See:
http://scottbarnham.com/blog/2008/08/25/dynamic-upload-paths-in-django/
from django.db.models import ImageField, signals class CustomImageField(ImageField): """Allows model instance to specify upload_to dynamically. Model class should have a method like: def get_upload_to(self, attname): return 'path/to/%d' % self.id Based on: http://code.djangoproject.com/wiki/CustomUploadAndFilters """ def __init__(self, *args, **kwargs): if not 'upload_to' in kwargs: kwargs['upload_to'] = 'dummy' self.prime_upload = kwargs.get('prime_upload', False) if 'prime_upload' in kwargs: del(kwargs['prime_upload']) super(CustomImageField, self).__init__(*args, **kwargs) def contribute_to_class(self, cls, name, **kwargs): """Hook up events so we can access the instance.""" super(CustomImageField, self).contribute_to_class(cls, name) if self.prime_upload: signals.post_init.connect(self._get_upload_to, sender=cls) signals.pre_save.connect(self._get_upload_to, sender=cls) def _get_upload_to(self, instance=None, **kwargs): """Get dynamic upload_to value from the model instance.""" if hasattr(instance, 'get_upload_to'): self.upload_to = instance.get_upload_to(self.attname) def db_type(self): """Required by Django for ORM.""" return 'varchar(100)']]>
I have a new short post with an example of how to get dynamic upload paths since the FileStorageRefactor merge. It uses a callable in the upload_to parameter and is much simpler than the method in this post.
]]> def contribute_to_class(self, cls, name):
“””
Hook up events so we can access the instance.
“””
super(CustomImageField, self).contribute_to_class(cls, name)
if self.prime_upload:
signals.post_init.connect(self._get_upload_to, sender=cls)
signals.pre_save.connect(self._get_upload_to, sender=cls)
def _get_upload_to(self, **kwargs):
“””
Get dynamic upload_to value from the model instance.
“””
instance = kwargs[‘instance’]
if hasattr(instance, ‘get_upload_to’):
self.upload_to = instance.get_upload_to(self.attname)
post_save
signal. I’ve posted it on my blog:I’ve just posted an updated version (see above) which should work in this situation.
]]> if form.is_valid():
l = ListingImage()
uploadedImage = form.cleaned_data[‘image’] # an UploadedFile object
l.save_image_file(uploadedImage.filename, uploadedImage.content)
l.caption = form.cleaned_data[‘caption’]
l.sort = form.cleaned_data[‘sort’]
l.save()
ListingImage.image is a CustomImageField()
Anyone know why calling save_image_file() doesn’t invoke the get_upload_to() to save the image to the dynamic path?
]]>Yes, you can. The model that contains the CustomImageField
gets to build up the path. Assuming you have a Photo
model which has a CustomImageField
and is related to a user, you could do something like:
class Photo(models.Model): user = models.ForeignKey(User, related_name='photos') image = CustomImageField(upload_to='photos') creation_date = models.DateTimeField() ... def get_upload_to(self, field_attname): return self.user.username
The upload path will be made up of the media path, username and filename. Assuming the username is “ted”, you will get something like: /path/to/media/ted/head.jpg