| 1 | from django.db.models import ImageField, FileField, signals |
| 2 | from django.conf import settings |
| 3 | import shutil, os, glob, re |
| 4 | |
| 5 | class CustomImageField(ImageField): |
| 6 | """Allows model instance to specify upload_to dynamically. |
| 7 | |
| 8 | Model class should have a method like: |
| 9 | |
| 10 | def get_upload_to(self, attname): |
| 11 | return 'path/to/%d' % self.id |
| 12 | |
| 13 | Based closely on: http://scottbarnham.com/blog/2007/07/31/uploading-images-to-a-dynamic-path-with-django/ |
| 14 | Later updated for newforms-admin by jamstooks: http://pandemoniumillusion.wordpress.com/2008/08/06/django-imagefield-and-filefield-dynamic-upload-path-in-newforms-admin/ |
| 15 | """ |
| 16 | def __init__(self, *args, **kwargs): |
| 17 | if not 'upload_to' in kwargs: |
| 18 | kwargs['upload_to'] = 'tmp' |
| 19 | self.use_key = kwargs.get('use_key', False) |
| 20 | if 'use_key' in kwargs: |
| 21 | del(kwargs['use_key']) |
| 22 | super(CustomImageField, self).__init__(*args, **kwargs) |
| 23 | |
| 24 | def contribute_to_class(self, cls, name): |
| 25 | """Hook up events so we can access the instance.""" |
| 26 | super(CustomImageField, self).contribute_to_class(cls, name) |
| 27 | signals.post_save.connect(self._move_image, sender=cls) |
| 28 | |
| 29 | def _move_image(self, instance=None, **kwargs): |
| 30 | """ |
| 31 | Function to move the temporarily uploaded image to a more suitable directory |
| 32 | using the model's get_upload_to() method. |
| 33 | """ |
| 34 | if hasattr(instance, 'get_upload_to'): |
| 35 | src = getattr(instance, self.attname) |
| 36 | if src: |
| 37 | m = re.match(r"%s/(.*)" % self.upload_to, src) |
| 38 | if m: |
| 39 | if self.use_key: |
| 40 | dst = os.path.join( |
| 41 | instance.get_upload_to(self.attname), |
| 42 | instance.id, m.groups()[0] |
| 43 | ) |
| 44 | else: |
| 45 | dst = os.path.join( |
| 46 | instance.get_upload_to(self.attname), |
| 47 | m.groups()[0] |
| 48 | ) |
| 49 | basedir = os.path.join( |
| 50 | settings.MEDIA_ROOT, |
| 51 | os.path.dirname(dst) |
| 52 | ) |
| 53 | fromdir = os.path.join( |
| 54 | settings.MEDIA_ROOT, |
| 55 | src |
| 56 | ) |
| 57 | shutil.move(fromdir, basedir) |
| 58 | setattr(instance, self.attname, dst) |
| 59 | instance.save() |
| 60 | |
| 61 | def db_type(self): |
| 62 | """Required by Django for ORM.""" |
| 63 | return 'varchar(200)' |