Django-如何创建一个文件并将其保存到模型的 FileField?

这是我的模型。我想做的是生成一个新文件,并在保存模型实例时覆盖现有文件:

class Kitten(models.Model):
claw_size = ...
license_file = models.FileField(blank=True, upload_to='license')


def save(self, *args, **kwargs):
#Generate a new license file overwriting any previous version
#and update file path
self.license_file = ???
super(Request,self).save(*args, **kwargs)

我看到了很多关于如何上传文件的文档。但是我如何生成一个文件,将其分配给一个模型字段,并让 Django 将其存储在正确的位置?

135889 次浏览

您需要查看 Django 文档中的 FileField 和 FieldFile,特别是 Save ()

基本上,声明为 FileField的字段在被访问时会提供类 FieldFile的一个实例,它提供了几个与底层文件交互的方法。所以,你需要做的是:

self.license_file.save(new_name, new_contents)

其中 new_name是您希望分配的文件名,而 new_contents是文件的内容。请注意,new_contents必须是 django.core.files.Filedjango.core.files.base.ContentFile的实例(详细信息请参阅给定的手册链接)。

这两个选择归结为:

from django.core.files.base import ContentFile, File


# Using File
with open('/path/to/file') as f:
self.license_file.save(new_name, File(f))


# Using ContentFile
self.license_file.save(new_name, ContentFile('A string with the file content'))

接受的答案当然是一个很好的解决方案,但这里是我生成 CSV 并从视图提供服务的方法。

我认为把它放在这里是值得的,因为它花了我一点小小的改动来获得所有想要的行为(覆盖现有的文件,存储到正确的位置,不创建重复的文件等)。

姜戈1.4.1

Python 2.7.3

#Model
class MonthEnd(models.Model):
report = models.FileField(db_index=True, upload_to='not_used')


import csv
from os.path import join


#build and store the file
def write_csv():
path = join(settings.MEDIA_ROOT, 'files', 'month_end', 'report.csv')
f = open(path, "w+b")


#wipe the existing content
f.truncate()


csv_writer = csv.writer(f)
csv_writer.writerow(('col1'))


for num in range(3):
csv_writer.writerow((num, ))


month_end_file = MonthEnd()
month_end_file.report.name = path
month_end_file.save()


from my_app.models import MonthEnd


#serve it up as a download
def get_report(request):
month_end = MonthEnd.objects.get(file_criteria=criteria)


response = HttpResponse(month_end.report, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename=report.csv'


return response

最好使用上下文管理器,或者在文件保存过程中出现异常时调用 close()。如果您的存储后端关闭等,可能会发生这种情况。

应该在存储后端配置任何覆盖行为。例如,S3Boto3Storage 具有 AWS_S3_FILE_OVERWRITE设置。如果你使用 FileSystemStorage,你可以写一个 定制搅拌器

如果希望发生任何自定义副作用(如上次更新的时间戳) ,还可以调用模型的 save 方法,而不是 FileField 的 save 方法。如果是这种情况,您还可以将文件的 name 属性设置为文件的名称-相对于 MEDIA_ROOT。它默认为文件的完整路径,如果你不设置它可能会导致问题-见 文件。 _ _ init _ _ ()文件名

这里有一个例子,其中 self是模型实例,其中 my_file是 FileField/ImageFile,在整个模型实例上调用 save(),而不仅仅是 FileField:

import os
from django.core.files import File


with open(filepath, 'rb') as fi:
self.my_file = File(fi, name=os.path.basename(fi.name))
self.save()