Django-ファイルを作成してモデルのFileFieldに保存する方法は?


110

これが私のモデルです。私がしたいことは、新しいファイルを生成し、モデルインスタンスが保存されるたびに既存のファイルを上書きすることです。

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に適切な場所に保存させるにはどうすればよいですか?

回答:


152

DjangoドキュメントのFileFieldとFieldFile、特にFieldFile.save()を確認したいとします。

基本的に、として宣言されたフィールドFileFieldにアクセスすると、クラスのインスタンスがFieldFile提供されます。これにより、基礎となるファイルを操作するいくつかのメソッドが提供されます。だから、あなたがする必要があるのは:

self.license_file.save(new_name, new_contents)

ここで、new_nameは割り当てたいファイル名new_contentsで、ファイルの内容です。またはのnew_contentsインスタンスでなければならないことに注意してください(詳細については、マニュアルへのリンクを参照してください)。2つの選択肢は次のように要約されます。django.core.files.Filedjango.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
OK、うまくいくと思いますが、saveメソッドでそれを呼び出すある種の再帰ループに入ります。永久にファイルを作成し続けるだけです。
グレッグ

11
再帰的な問題については、引数save = Falseを指定してself.license_file.saveを呼び出す必要があります。
グレッグ

1
これ(ContentFile)は、django-wkhtmltopdfのconvert_to_pdfコマンドによって返されるファイル文字列と完全に連携します。ありがとうございました!!
Nostalg.io 2016

これに加えて、ファイルを開くときにファイルモードを指定しないと、エラーが発生しました。したがって、f = open('/path/to/file', 'r')ZIPの種類のファイルの場合f = open('/path/to/file.zip', 'rb')
rajagopalx 2017

1
私の場合、上記はファイルをフォルダに保存していませんでした。問題は、私がdocker-composeを使用してセロリワーカーと一緒にdjangoアプリを実行していることです。のdjangoアプリのボリュームMEDIA_ROOTは、セロリワーカーの同じボリュームと共有されませんでした。名前付きボリュームを共有することで修正されました(参照)。
shadi

28

受け入れられた答えは確かに良い解決策ですが、CSVを生成してビューから提供する方法を以下に示します。

これをここに置くことは価値があると思いましたが、すべての望ましい動作(既存のファイルを上書きし、正しい場所に保存し、重複したファイルを作成しないなど)を得るには少し手間がかかりました。

Django 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

1

コンテキストマネージャーを使用するか、 close()ファイル保存プロセス中に例外が発生した場合はを行うことをお勧めします。ストレージバックエンドがダウンしている場合などに発生する可能性があります。

上書き動作はストレージバックエンドで設定する必要があります。たとえば、S3Boto3Storageには設定がありますAWS_S3_FILE_OVERWRITE。使用しているFileSystemStorage場合は、カスタムミックスインを

最後に更新されたタイムスタンプなどのカスタムの副作用を発生させたい場合は、FileFieldのsaveメソッドの代わりにモデルのsaveメソッドを呼び出すこともできます。その場合は、ファイルのname属性をファイルの名前に設定することもできますMEDIA_ROOT。これはに関連しています。デフォルトではファイルのフルパスに設定されているので、設定しないと問題が発生する可能性があります-File .__ init __() File.nameを

FileField / ImageFile selfのモデルインスタンスがである例を次に示しますmy_file。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()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.