Django:访问models.filefield(upload_to)位置的主键

时间:2009-03-16 20:02:39

标签: python django file-io

我想使用条目的主键保存我的文件。

这是我的代码:

def get_nzb_filename(instance, filename):
    if not instance.pk:
        instance.save() # Does not work.
    name_slug = re.sub('[^a-zA-Z0-9]', '-', instance.name).strip('-').lower()
    name_slug = re.sub('[-]+', '-', name_slug)
    return u'files/%s_%s.nzb' % (instance.pk, name_slug)

class File(models.Model):
    nzb = models.FileField(upload_to=get_nzb_filename)
    name = models.CharField(max_length=256)

我知道第一次保存对象时主键不可用,所以我愿意采取额外的命中来保存对象以获取主键,然后继续。

上述代码不起作用。它会引发以下错误:

maximum recursion depth exceeded while calling a Python object

我假设这是一个无限循环。调用save方法会调用get_nzb_filename方法,该方法将再次调用save方法,依此类推。

我正在使用最新版本的Django主干。

如何获取主键以便我可以使用它来保存上传的文件?


更新@muhuk:

我喜欢你的解决方案。你能帮我实现吗?我已将代码更新为以下内容,错误为'File' object has no attribute 'create'。也许我正在使用你在上下文之外写的东西?

def create_with_pk(self):
    instance = self.create()
    instance.save()
    return instance

def get_nzb_filename(instance, filename):
    if not instance.pk:
        create_with_pk(instance)
    name_slug = re.sub('[^a-zA-Z0-9]', '-', instance.name).strip('-').lower()
    name_slug = re.sub('[-]+', '-', name_slug)
    return u'files/%s_%s.nzb' % (instance.pk, name_slug)

class File(models.Model):
    nzb = models.FileField(upload_to=get_nzb_filename, blank=True, null=True)
    name = models.CharField(max_length=256)

不是在我的模型中强制执行必需的字段,而是在Form类中执行。没问题。

4 个答案:

答案 0 :(得分:3)

您可以通过将upload_to设置为临时位置并创建自定义保存方法来执行此操作。

save方法应首先调用super,以生成主键(这会将文件保存到临时位置)。然后,您可以使用主键重命名文件并将其移动到正确的位置。再打电话超级保存更改,你很高兴!当我遇到这个问题时,这对我很有用。

例如:

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 )

答案 1 :(得分:2)

您似乎需要先使用空文件字段预生成File模型。然后选择一个并使用给定的文件对象保存它。

您可以使用这样的自定义管理器方法;

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

但如果您需要任何一个字段,这将很麻烦。由于您最初是在创建空对象,因此无法在模型级别强制执行必需的字段。

修改

create_with_pk应该是custom manager method,在您的代码中它只是一个常规方法。因此self毫无意义。这些都是documented的例子。

答案 2 :(得分:2)

上下文

有同样的问题。 解决了它通过首先保存对象将id归因于当前对象。

方法

  1. 创建自定义upload_to功能
  2. 检测对象是否有pk
  3. 如果没有,首先保存实例,检索pk并将其分配给对象
  4. 使用
  5. 生成您的路径

    示例工作代码:

    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)
    

答案 3 :(得分:-1)

Ty,你有没有理由推出自己的slugify过滤器?

Django附带内置slugify过滤器,您可以这样使用它:

from django.template.defaultfilters import slugify

slug = slugify(some_string)

不确定您是否知道可以使用...