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!

Community
  • 1
  • 1
MiniGunnR
  • 5,590
  • 8
  • 42
  • 66

2 Answers2

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 /.

Wtower
  • 18,848
  • 11
  • 103
  • 80
  • `os.path.join` would be a lot better here. – Burhan Khalid May 20 '15 at 12:28
  • 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' – MiniGunnR May 20 '15 at 12:39
  • I can't see any `rfind` in the code provided, is this relevant? What is the exact error and where? – Wtower May 20 '15 at 12:42
  • 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: http://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.6 – MiniGunnR May 20 '15 at 12:44
  • 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. – Wtower May 20 '15 at 12:46
  • 2
    I rolled back to the initial answer. Maybe `os.path.join` is better here, but this one I have tested as well it seems. – Wtower May 20 '15 at 12:50
  • No reference anywhere. – MiniGunnR May 20 '15 at 12:51
  • 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? – MiniGunnR May 20 '15 at 12:53
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)))
MiniGunnR
  • 5,590
  • 8
  • 42
  • 66