How to change upload_to parameter of ImageField based on field name in Django?
Asked Answered
B

2

5

I would like to upload images to the media root based on the field values given by the Django admin user. Here is the code that I've written and I know that the upload_to parameter is causing the problem. But I don't know how to make it work.

models.py

class Info(models.Model):
    file_no = models.CharField(max_length=100)
    date = models.DateField()
    area = models.IntegerField(default=0.00)
    mouja = models.CharField(max_length=100)
    doc_type_choices = (
            ('deed', 'Deed'),
            ('khotian', 'Khotian'),
        )
    doc_type = models.CharField(max_length=50,
                                choices=doc_type_choices,
                                default='deed')
    doc_no = models.CharField(max_length=50)

    def __unicode__(self):
        return self.file_no

class Image(models.Model):
    info = models.ForeignKey('Info')
    content = models.ImageField(upload_to=self.info.mouja/self.info.doc_type)

    def __unicode__(self):
        return self.info.file_no

Whenever I run python manage.py makemigrations it shows NameError: name 'self' is not defined Thanks in advance for any help!

Blackness answered 20/5, 2015 at 12:23 Comment(0)
E
9

In the upload_to keyword you would need to provide a function that you will define, for instance:

def path_file_name(instance, filename):
    return '/'.join(filter(None, (instance.info.mouja, instance.info.doc_type, filename)))

class Image(models.Model):
    content = models.ImageField(upload_to=path_file_name)

From Django documentation: Model field reference:

This may also be a callable, such as a function, which will be called to obtain the upload path, including the filename. This callable must be able to accept two arguments, and return a Unix-style path (with forward slashes) to be passed along to the storage system.

Within this callable, which in the particular case is path_file_name function, we build a path from the instance field which is the particular record of Image model.

The filter function removes any None items out of the list and the join function constructs the path by joining all list items with /.

Engulf answered 20/5, 2015 at 12:27 Comment(8)
os.path.join would be a lot better here.Resurge
Actually the first code worked but this new code is not working. Gives this error --> AttributeError at /admin/index/info/add/ 'tuple' object has no attribute 'rfind'Blackness
I can't see any rfind in the code provided, is this relevant? What is the exact error and where?Engulf
The error occurs when I press 'Save' in the Django Admin after I input all the data. Here is a bigger version of the error --> AttributeError at /admin/index/info/add/ 'tuple' object has no attribute 'rfind' Request Method: POST Request URL: localhost:8000/admin/index/info/add Django Version: 1.8.1 Exception Type: AttributeError Exception Value: 'tuple' object has no attribute 'rfind' Exception Location: /usr/lib/python2.7/posixpath.py in split, line 92 Python Executable: /usr/bin/python Python Version: 2.7.6Blackness
Is there any reference to your code in the traceback and django's, and what exactly it says? This particular method that I recommended is the one that I extensively use so I find it hard to be wrong.Engulf
I rolled back to the initial answer. Maybe os.path.join is better here, but this one I have tested as well it seems.Engulf
No reference anywhere.Blackness
Thanks for the help. However, I don't understand how this code works. Can you direct me to an article from where I can learn about the syntax you used?Blackness
B
2

Here is the original code that worked. Just in case anyone needs it.

def path_file_name(instance, filename):
    return '/'.join(filter(None, (instance.info.mouja, instance.info.doc_type, filename)))
Blackness answered 20/5, 2015 at 12:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.