9

I would like to include the username in my upload_to directory path for when a user uploads an image. Here is what I currently have --

#model
class Avatar(models.Model):
    avatar = models.ImageField(upload_to='images/%s' %(USERNAME) )
     user = models.ForeignKey(UserProfile)

#form
class ProfilePictureForm(ModelForm):
    class Meta:
        model = Avatar
        fields = ('avatar',)

How would I get the USERNAME in the model to be able to set the upload_to path?

David542
  • 104,438
  • 178
  • 489
  • 842

2 Answers2

25

upload_to can be a callable instead of a string, in which case it will be passed the current instance and the filename -- see the documentation. Something like this should work (instance.user.user because instance.user is the UserProfile, so instance.user.user is the User).

def upload_to(instance, filename):
    return 'images/%s/%s' % (instance.user.user.username, filename)
class Avatar(models.Model):
    avatar = models.ImageField(upload_to=upload_to)
    user = models.ForeignKey(UserProfile)
Ismail Badawi
  • 36,054
  • 7
  • 85
  • 97
  • 7
    This is the correct answer to the question. However, I would suggest the user the user id instead of a username. You never know when you would need to modify a username, which could bring some headaches of its own. – JeromeParadis Aug 14 '12 at 21:04
  • 2
    @JeromeParadis There is a problem using the id, as the docs say: "In most cases, this object will not have been saved to the database yet, so if it uses the default AutoField, it might not yet have a value for its primary key field." https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.FileField.upload_to – Caumons Sep 19 '13 at 10:18
  • @Caumons Good point. In this case I assumed the UserProfile instance has already been saved and that the Avatar is created in another step. In any case, I think my initial point is a bit moot since wherever the image is saved, the path is stored in the ImageField object. The only problem is that you are losing some kind of integrity between the image path and the username if username changes are allowed. – JeromeParadis Nov 15 '13 at 15:52
  • 2
    I would suggest using os.path.join to create path – Pax0r Mar 06 '14 at 11:45
  • @IsmailBadawi - In my case there is not `UserProfile` form. I have some model as `class Document(models.Model): category = models.ManyToManyField(DocumentCategory, verbose_name=_("Document Category"), blank=True) file = models.FileField(_("Softcopy"), upload_to=upload_to, max_length=10000, null=True)` – trex Sep 01 '20 at 04:00
0

Ismail Badawi answer is completely correct. Also you can use new string formatting and lambda function.

New string formatting:

def upload_to(instance, filename):
    return 'images/{username}/{filename}'.format(
        username=instance.user.user.username, filename=filename)


class Avatar(models.Model):
    avatar = models.ImageField(upload_to=upload_to)
    user = models.ForeignKey(UserProfile)

New String formatting and lambda function:

 path = lambda instance, filename: 'images/{username}/{filename}'.format(
        username=instance.user.user.username, filename=filename)


class Avatar(models.Model):
    avatar = models.ImageField(upload_to=path)
    user = models.ForeignKey(UserProfile)
Mohammad Reza
  • 693
  • 9
  • 16