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.
精彩评论