如何使用 upload_to 动态路径将文件保存到模型
How to save a file to a model using upload_to for dynamic paths
我正在尝试为每个用户创建一个文件夹来放入他们的项目。因此他们的文件将具有路径 ..\project\id\filename
,id
是用户 id
和 filename
是文件名。现在在 Filefield
中使用 upload_to
(instance
和 filename
)允许的参数,我意识到 instance.id
将是 None
和路径到文件将是 ..\project\None\filename
而不是 ..\project\id\filename
.
正在阅读 Django documentation upload_to 我看到了这个:
In most cases, this object will not have been saved to the database
yet, so if it uses the default AutoField, it might not yet have a
value for its primary key field.
我的解释是creating a new record和user_directory_path
不是同时实例化的,也就是说,当我在Project
模型上调用create
时,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
。注意 user_directory_path
在 create
.
之前调用
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,
)
一个简单的解决方案可以是在没有文件的情况下保存对象,然后像这样保存文件
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()
如果像你说的那样,你想在文件路径中使用的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)
但我要指出的是,在 Django 的做事方式中,创建一个名为 email
的字段作为 User
的外键实际上非常令人困惑。数据库中的字段将被称为 email_id
.. 并且模型字段的值将 return User
.. 的实例而不是实际的电子邮件地址,即使电子邮件地址是列中存储了什么。要获取电子邮件地址,您需要执行以下操作之一:
myproject.email.email
myproject.email_id
谁都不是很清楚。因此,除非您有充分的理由这样做,否则您应该调用字段 user
并删除 to_field='email'
。允许 Django 通过 id
连接表,这是默认行为。
然后如果您需要用户电子邮件地址,您可以随时通过
获取
myproject.user.email
好处是,如果用户更改了他们的电子邮件地址,它将随处更改,您不必依赖级联更新来修复所有外键。
相信我,在使用 Django 时,你希望按 id
(默认)执行 ForeignKey,除非有原因...
我正在尝试为每个用户创建一个文件夹来放入他们的项目。因此他们的文件将具有路径 ..\project\id\filename
,id
是用户 id
和 filename
是文件名。现在在 Filefield
中使用 upload_to
(instance
和 filename
)允许的参数,我意识到 instance.id
将是 None
和路径到文件将是 ..\project\None\filename
而不是 ..\project\id\filename
.
正在阅读 Django documentation upload_to 我看到了这个:
In most cases, this object will not have been saved to the database yet, so if it uses the default AutoField, it might not yet have a value for its primary key field.
我的解释是creating a new record和user_directory_path
不是同时实例化的,也就是说,当我在Project
模型上调用create
时,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
。注意 user_directory_path
在 create
.
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,
)
一个简单的解决方案可以是在没有文件的情况下保存对象,然后像这样保存文件
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()
如果像你说的那样,你想在文件路径中使用的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)
但我要指出的是,在 Django 的做事方式中,创建一个名为 email
的字段作为 User
的外键实际上非常令人困惑。数据库中的字段将被称为 email_id
.. 并且模型字段的值将 return User
.. 的实例而不是实际的电子邮件地址,即使电子邮件地址是列中存储了什么。要获取电子邮件地址,您需要执行以下操作之一:
myproject.email.email
myproject.email_id
谁都不是很清楚。因此,除非您有充分的理由这样做,否则您应该调用字段 user
并删除 to_field='email'
。允许 Django 通过 id
连接表,这是默认行为。
然后如果您需要用户电子邮件地址,您可以随时通过
获取 myproject.user.email
好处是,如果用户更改了他们的电子邮件地址,它将随处更改,您不必依赖级联更新来修复所有外键。
相信我,在使用 Django 时,你希望按 id
(默认)执行 ForeignKey,除非有原因...