如何使用upload_to动态路径
我想创建一个文件夹的每个用户把他们的项目将文件保存到一个模型。因此,他们的文件将具有路径..\project\id\filename
,id
是用户id
和filename
是文件的名称。现在使用Filefield
中的upload_to
(instance
和filename
)所允许的参数,我意识到instance.id
将是None
,文件的路径将是..\project\None\filename
而不是..\project\id\filename
。如何使用upload_to动态路径
现在读Django documentation upload_to我看到了这一点:
在大多数情况下,这个对象将不会被保存到数据库 还,所以如果使用默认的下拉列表AutoField,它可能还没有一个 它的主键字段的值。
我的解释是,创建一个新的记录,并user_directory_path
不是在同一时间实例,那就是,当我打电话create
上Project
模型,instance.id
将None
。我的问题是,现在有没有办法解决这个问题?虽然我看到upload_to
很方便,但对于动态路径(如我正在做的那样)来说,这并不一定很方便。我正在考虑创建记录,然后在更新中添加文件路径,但我正在寻找一种可以一步保存所有内容的方法。
models.py
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'project/{0}/{1}'.format(instance.user.id, filename)
class Project(models.Model):
email = models.ForeignKey(User,
to_field="email",
max_length=50
)
title = models.CharField(max_length=100)
date_created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
file = models.FileField(upload_to=user_directory_path, validators=[validate_file_type], null=True)
当表格通过验证时,这是views.py
。在create
之前调用user_directory_path
。
email = request.user.email
title = request.POST.get('title', '')
file = request.FILES['file']
filename = file.name
instance = Usermie.objects.get(email=request.user.email)
# Save to model
user_directory_path(instance=instance, filename=filename)
Project.objects.create(
title=title, file=file,
)
如果像你说的,要在文件路径使用的ID是的id用户,而不是项目的ID ..那么没有问题,因为用户在保存项目时已经存在。由于email
是一个外键User
,你只是做:
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
return 'project/{0}/{1}'.format(instance.email.id, filename)
但我要指出的是,在做的事情,做一个场称为email
这是Django的方式外键User
实际上是很混乱。数据库中的字段将被称为email_id
..并且模型字段的值将返回User
..的实例,而不是实际的电子邮件地址,即使电子邮件地址是存储在列中的。要获得电子邮件地址,您需要执行以下操作之一:
myproject.email.email
myproject.email_id
两者都不是很清楚。所以,除非你有这样的理由,否则你应该打电话给user
,并取消to_field='email'
。允许Django通过id
加入表格,这是默认行为。
然后,如果你需要的用户电子邮件地址,你可以通过
myproject.user.email
得到它的任何时间和好处是,如果用户更改他们的电子邮件地址,它会无处不在改变,你不必依赖在级联更新来修复所有外键。
信任我,使用Django,当你想通过id
(默认),除非有一个理由这样做ForeignKey的...
一个简单的解决方案,可以节省不使用文件对象,然后保存文件中像这样
email = request.user.email
title = request.POST.get('title', '')
file = request.FILES['file']
filename = file.name
instance = Usermie.objects.get(email=request.user.email)
# Save to model
user_directory_path(instance=instance, filename=filename)
project = Project.objects.create(title=title)
project.file = file
project.save()
'而且奖金是,如果用户更改他们的电子邮件地址,它将在任何地方都会发生变化,您不必依赖级联更新来修复所有外键。“在ForeignKey中使用id的非常好的理由。 –
谢谢!这实际上给了我更好的视力。我将返回并将所有其他模型中的电子邮件字段更改为用户标识。直到现在,我还没有意识到用户更改电子邮件的问题。谢谢@Massan。我一直知道这一点,但没有意识到我在做这件事。 – Jam1
不客气,我很高兴我可以提供帮助。我应该提到的另一件事是,一旦创建了项目,就不能允许用户更改,因为这会改变目录路径,并且django不会再找到这些文件。 –