Django: Access primary key in models.filefield(upload_to) location

前端 未结 4 1449
一生所求
一生所求 2020-12-16 16:51

I\'d like to save my files using the primary key of the entry.

Here is my code:

def get_nzb_filename(instance, filename):
    if not instance.pk:
            


        
相关标签:
4条回答
  • 2020-12-16 17:07

    Context

    Had the same issue. Solved it attributing an id to the current object by saving the object first.

    Method

    1. create a custom upload_to function
    2. detect if object has pk
    3. if not, save instance first, retrieve the pk and assign it to the object
    4. generate your path with that

    Sample working code :

    class Image(models.Model):
        def upload_path(self, filename):
            if not self.pk:
                i = Image.objects.create()
                self.id = self.pk = i.id
            return "my/path/%s" % str(self.id)
        file = models.ImageField(upload_to=upload_path)
    
    0 讨论(0)
  • 2020-12-16 17:20

    It seems you'll need to pre-generate your File models with empty file fields first. Then pick up one and save it with the given file object.

    You can have a custom manager method like this;

    def create_with_pk(self):
        instance = self.create()
        instance.save()     # probably this line is unneeded
        return instance
    

    But this will be troublesome if either of your fields is required. Because you are initially creating a null object, you can't enforce required fields on the model level.

    EDIT

    create_with_pk is supposed to be a custom manager method, in your code it is just a regular method. Hence self is meaningless. It is all properly documented with examples.

    0 讨论(0)
  • 2020-12-16 17:27

    Ty, is there a reason you rolled your own slugify filter?

    Django ships with a built-in slugify filter, you can use it like so:

    from django.template.defaultfilters import slugify
    
    slug = slugify(some_string)
    

    Not sure if you were aware it was available to use...

    0 讨论(0)
  • 2020-12-16 17:28

    You can do this by setting upload_to to a temporary location and by creating a custom save method.

    The save method should call super first, to generate the primary key (this will save the file to the temporary location). Then you can rename the file using the primary key and move it to it's proper location. Call super one more time to save the changes and you are good to go! This worked well for me when I came across this exact issue.

    For example:

    class File( models.Model ):
        nzb = models.FileField( upload_to='temp' )
    
        def save( self, *args, **kwargs ):
            # Call save first, to create a primary key
            super( File, self ).save( *args, **kwargs )
    
            nzb = self.nzb
            if nzb:
                # Create new filename, using primary key and file extension
                oldfile = self.nzb.name
                dot = oldfile.rfind( '.' )
                newfile = str( self.pk ) + oldfile[dot:]
    
                # Create new file and remove old one
                if newfile != oldfile:
                    self.nzb.storage.delete( newfile )
                    self.nzb.storage.save( newfile, nzb )
                    self.nzb.name = newfile 
                    self.nzb.close()
                    self.nzb.storage.delete( oldfile )
    
            # Save again to keep changes
            super( File, self ).save( *args, **kwargs )
    
    0 讨论(0)
提交回复
热议问题