开发者

What would be a consistent method to preserve FileField behaviour in Django 1.2.5

As with Django 1.2.5 a model containing a filefield will not automatically delete the associated files any more when the model is deleted. Check the release notes here: http://docs.djangoproject.com/en/1.2/releases/1开发者_开发问答.2.5/

I am quite new to Django, so i wonder what would be a good way to preserve the old behaviour, as i have a need for it. Is it enough to just override the model.save method?


if you take a look at changeset 15321 in django's code repository, you'll see that this functionality has been removed by deleting a signal handler that the FileField had which intercepted the its parent model's delete event and subsequently tried to delete its file.

The functionality is quite easy to restore, you just need to "undo" these changes. One warning though: The problem with deleting files within transactions is real and if you delete files "the old fashioned way" you could end up deleting stuff even when a rollback occurs. Now, if that doesn't pose a problem for you, read on!

We can easy subclass the FileField and restore that functionality without touching the original class. This could should do that (note that I'm just restoring the old functionality deleted from the code):

from django.db.models.fields.files import FileField

class RetroFileField(FileField):
    # restore the old delete file when model is deleted functionality

    def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs):
        # init FileField normally
        super(RetroFileField, self).__init__(verbose_name, name, upload_to, storage, **kwargs)

    def contribute_to_class(self, cls, name):
        # restore the SIGNAL that is handled when a model is deleted
        super(RetroFileField, self).contribute_to_class(cls, name)
        signals.post_delete.connect(self.delete_file, sender=cls)

    def delete_file(self, instance, sender, **kwargs):
        file = getattr(instance, self.attname)
        # If no other object of this type references the file,
        # and it's not the default value for future objects,
        # delete it from the backend.
        if file and file.name != self.default and \
            not sender._default_manager.filter(**{self.name: file.name}):
                file.delete(save=False)
        elif file:
            # Otherwise, just close the file, so it doesn't tie up resources.
            file.close()

(I haven't tested the code... but it should be more or less ok)

You should put this code in a fields.py module in your project, or wherever it makes sense to you. Just remember, that from now on, instead of using django.db.models.FileField you'll be using yourproject.fields.RetroFileField for your file fields. And if you're using image fields and you depend on this functionality too... well... I think you'll need to subclass the image fields too and make them use your RetroFileField instead of the original FileField.

Oh, and if you don't like the name of the field, just rename it to something more appropriate, just remember to update the super() calls inside.

Hope this helps!

Another note: You should see if you can just use a cron job to delete orphaned files like the changelog suggests.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜