| | 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)' |