这是我的模特。我想要做的是生成一个新文件,并在保存模型实例时覆盖现有文件:
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将其存储在正确的位置?
答案 0 :(得分:127)
您想要查看Django文档中的FileField and FieldFile,尤其是FieldFile.save()。
基本上,声明为FileField
的字段在访问时会为您提供类FieldFile
的实例,它为您提供了几种与底层文件交互的方法。所以,你需要做的是:
self.license_file.save(new_name, new_contents)
其中new_name
是您希望分配的文件名,new_contents
是文件的内容。请注意,new_contents
必须是django.core.files.File
或django.core.files.base.ContentFile
的实例(有关详细信息,请参阅手册的指定链接)。这两个选择归结为:
# Using File
f = open('/path/to/file')
self.license_file.save(new_name, File(f))
# Using ContentFile
self.license_file.save(new_name, ContentFile('A string with the file content'))
答案 1 :(得分:21)
接受的答案肯定是一个很好的解决方案,但这是我开始生成CSV并从视图中提供服务的方式。
#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
认为把它放在这里是值得的,因为我花了一些时间来摆弄所有理想的行为(覆盖现有文件,存储到正确的位置,不创建重复文件等)。
Django 1.4.1
Python 2.7.3
答案 2 :(得分:0)
谢谢@tawmas。除此之外,
如果在打开文件时未指定文件模式,则会出错。所以,
f = open('/path/to/file', 'r')
对于ZIP类型的文件,
f = open('/path/to/file.zip', 'rb')
答案 3 :(得分:0)
在文件保存过程中出现异常的情况下,最好使用上下文管理器或调用close()
。如果您的存储后端关闭等情况,可能会发生。
任何覆盖行为都应在存储后端中配置。例如,S3Boto3Storage的设置为AWS_S3_FILE_OVERWRITE
。如果您使用的是FileSystemStorage
,则可以编写custom mixin。
如果您希望发生任何自定义的副作用(例如最近更新的时间戳记),则可能还需要调用模型的save方法而不是FileField的save方法。在这种情况下,您还可以将文件的name属性设置为文件名-相对于MEDIA_ROOT
。它默认为文件的完整路径,如果不设置它,可能会引起问题-请参见File.__init__()和File.name。
下面是一个示例,其中self
是模型实例,其中my_file
是FileField / ImageFile,在整个模型实例而不是FileField上调用save()
:
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()