我在python中生成一个文件,并希望"上传"该文件到django数据库。这样它就会自动放入媒体文件夹中,并与我的应用程序的所有其他文件整齐地组织在一起。
现在我在尝试这里:(使用类型提示,因为它的python 3.6)
# forms.py
class UploadForm(forms.ModelForm):
class Meta:
model = UploadedFile
fields = ('document',)
# models.py
class UploadedFile(models.Model):
document = models.FileField(upload_to=get_upload_path)
# mimetype is generated by filename on save
mimetype = models.CharField(max_length=255)
# ... additional fields like temporary
def get_upload_path(instance: UploadedFile, filename):
if instance.temporary:
return "uploaded_files/temp/" + filename
return "uploaded_files/" + filename
# views.py, file_out has been generated
with open(file_out, 'rb') as local_file:
from django.core.files import File
form = UploadForm(dict(), {'document': File(local_file)})
print(form.errors)
if form.is_valid():
file = form.save(commit=False)
# ... set additional fields
file.save()
form.save_m2m()
return file
现在这不是我尝试过的唯一一件事。首先我直接设置了FileField
,但导致save()
失败,同时设置了mimetype字段。因为原始文件位于媒体文件夹之外,因此会触发可疑文件操作。
此外,该表单通过form.errors
提供了有关"上传"的一些反馈。
根据我的方法,save()
如上所述失败 - 意味着"上传"实际上并不复制媒体文件夹中的文件 - 或者表单返回没有文件传输的错误,并告诉检查表单协议。
现在我的理论是,我必须去初始化我自己的InMemoryUploadedFile
实例,但我自己无法弄清楚如何做到这一点,并且互联网上没有可用的文档。
感觉我从一开始就采取了错误的方法。如何正确地做到这一点?
答案 0 :(得分:1)
您是否定义了get_upload_path
?如果没有,这可以解释你得到的错误。
从我所看到的你走在正确的轨道上。如果您不需要上传的动态路径,如果您只想在media/uploads
中使用它们,则可以传递upload_to
的字符串值(来自Django docs):
# file will be uploaded to MEDIA_ROOT/uploads
document = models.FileField(upload_to='uploads/')
答案 1 :(得分:0)
首先,感谢Franey指示我storage documentation引导我contentfile documentation。
ContentFile
实际上解决了这个问题,因为它基本上是我正在寻找的InMemoryUploadedFile
的自我实例化版本。它是未存储在磁盘上的django File
。
以下是完整的解决方案:
# views.py, file_out has been generated
with open(file_out, 'rb') as local_file:
from django.core.files.base import ContentFile
# we need to provide a name. Otherwise the Storage.save
# method reveives a None-parameter and breaks.
form = UploadForm(dict(), {'document': ContentFile(local_file.read(), name=name)})
if form.is_valid():
file = form.save(commit=False)
# ... set additional fields
file.save()
form.save_m2m()
return file