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

Gre*_*reg 93 python django django-models

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

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)
Run Code Online (Sandbox Code Playgroud)

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

taw*_*mas 135

您想要查看Django文档中的FileField和FieldFile,尤其是FieldFile.save().

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

self.license_file.save(new_name, new_contents)
Run Code Online (Sandbox Code Playgroud)

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'))
Run Code Online (Sandbox Code Playgroud)

  • 对于递归问题,我必须使用arg save = False调用self.license_file.save. (11认同)
  • 好的,我认为这会起作用,但我正在进入某种递归循环,在保存方法中调用它。它只是永远不断地创建文件。 (4认同)
  • 这个 (ContentFile) 与 django-wkhtmltopdf 的 `convert_to_pdf` 命令返回的文件字符串完美配合。谢谢!! (2认同)
  • 就我而言,上述内容并未将文件保存到文件夹中。事实证明,问题是我正在使用 [docker-compose](https://docs.docker.com/compose/) 与 celery Worker 一起运行我的 django 应用程序。“MEDIA_ROOT”的 django 应用程序卷未与 celery Worker 中的同一卷共享。共享命名卷修复了它([参考](/sf/answers/3099949541/))。 (2认同)

mar*_*ers 26

接受的答案肯定是一个很好的解决方案,但这是我开始生成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
Run Code Online (Sandbox Code Playgroud)

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

Django 1.4.1

Python 2.7.3


whp*_*whp 11

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

任何覆盖行为都应在您的存储后端进行配置。例如S3Boto3Storage有一个设置AWS_S3_FILE_OVERWRITE。如果您正在使用,FileSystemStorage您可以编写自定义 mixin

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

下面是一个示例,其中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()
Run Code Online (Sandbox Code Playgroud)