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

时间:2022-07-13 19:16:10

Here's my model. What I want to do is generate a new file and overwrite the existing one whenever a model instance is saved:

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

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)

I see lots of documentation about how to upload a file. But how do I generate a file, assign it to a model field and have Django store it in the right place?

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

3 个解决方案

#1


92  

You want to have a look at FileField and FieldFile in the Django docs, and especially FieldFile.save().

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

Basically, a field declared as a FileField, when accessed, gives you an instance of class FieldFile, which gives you several methods to interact with the underlying file. So, what you need to do is:

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

self.license_file.save(new_name, new_contents)

where new_name is the filename you wish assigned and new_contents is the content of the file. Note that new_contents must be an instance of either django.core.files.File or django.core.files.base.ContentFile (see given links to manual for the details). The two choices boil down to:

new_name是您希望分配的文件名,new_contents是文件的内容。注意,new_contents必须是django.core.files的一个实例。文件或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'))

#2


19  

Accepted answer is certainly a good solution, but here is the way I went about generating a CSV and serving it from a view.

公认的答案当然是一个很好的解决方案,但是下面是我生成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

Thought it was worth while putting this here as it took me a little bit of fiddling to get all the desirable behaviour (overwrite existing file, storing to the right spot, not creating duplicate files etc).

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

Django 1.4.1

Django 1.4.1

Python 2.7.3

Python 2.7.3

#3


0  

Thanks @tawmas. In addition to that,

谢谢@tawmas。除此之外,

I got an error if I don't specify the file mode while opening the file. So,

如果在打开文件时没有指定文件模式,则会出现错误。所以,

f = open('/path/to/file', 'r')

For ZIP kind of file,

对于ZIP类文件,

f = open('/path/to/file.zip', 'rb')

#1


92  

You want to have a look at FileField and FieldFile in the Django docs, and especially FieldFile.save().

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

Basically, a field declared as a FileField, when accessed, gives you an instance of class FieldFile, which gives you several methods to interact with the underlying file. So, what you need to do is:

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

self.license_file.save(new_name, new_contents)

where new_name is the filename you wish assigned and new_contents is the content of the file. Note that new_contents must be an instance of either django.core.files.File or django.core.files.base.ContentFile (see given links to manual for the details). The two choices boil down to:

new_name是您希望分配的文件名,new_contents是文件的内容。注意,new_contents必须是django.core.files的一个实例。文件或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'))

#2


19  

Accepted answer is certainly a good solution, but here is the way I went about generating a CSV and serving it from a view.

公认的答案当然是一个很好的解决方案,但是下面是我生成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

Thought it was worth while putting this here as it took me a little bit of fiddling to get all the desirable behaviour (overwrite existing file, storing to the right spot, not creating duplicate files etc).

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

Django 1.4.1

Django 1.4.1

Python 2.7.3

Python 2.7.3

#3


0  

Thanks @tawmas. In addition to that,

谢谢@tawmas。除此之外,

I got an error if I don't specify the file mode while opening the file. So,

如果在打开文件时没有指定文件模式,则会出现错误。所以,

f = open('/path/to/file', 'r')

For ZIP kind of file,

对于ZIP类文件,

f = open('/path/to/file.zip', 'rb')