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 문서, 특히 FieldFile.save () 에서 FileField 및 FieldFile 을 살펴보고 싶습니다. .

기본적으로로 선언 된 필드는 FileField액세스 할 때 FieldFile기본 파일과 상호 작용할 수있는 여러 메서드를 제공하는 class의 인스턴스 를 제공합니다. 따라서해야 할 일은 다음과 같습니다.

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
좋아, 작동한다고 생각하지만 save 메소드에서 호출하는 일종의 재귀 루프에 들어갑니다. 영원히 파일을 계속 생성합니다.
그렉

11
재귀 문제의 경우 arg save = False로 self.license_file.save를 호출해야합니다.
그렉

1
이 (ContentFile)은 django-wkhtmltopdf의 convert_to_pdf명령에서 반환 된 파일 문자열과 완벽하게 작동합니다 . 감사합니다!!
Nostalg.io

또한 파일을 여는 동안 파일 모드를 지정하지 않으면 오류가 발생합니다. 그래서, f = open('/path/to/file', 'r')파일의 ZIP 종류,f = open('/path/to/file.zip', 'rb')
rajagopalx

1
제 경우에는 위의 파일이 폴더에 저장되지 않았습니다. 문제는 내가 docker-compose 를 사용하여 셀러리 작업자와 함께 django 앱을 실행하고 있다는 것 입니다. 에 대한 django 앱 볼륨 MEDIA_ROOT이 셀러리 워커의 동일한 볼륨과 공유되지 않았습니다. 명명 된 볼륨을 공유하여 수정했습니다 ( ref ).
shadi

28

허용되는 답변은 확실히 좋은 솔루션이지만 여기에 CSV를 생성하고보기에서 제공하는 방법이 있습니다.

원하는 모든 동작 (기존 파일 덮어 쓰기, 올바른 위치에 저장, 중복 파일 생성 안 함 등)을 얻기 위해 약간의 조작이 필요했기 때문에 이것을 여기에 넣는 것이 가치가 있다고 생각했습니다.

장고 1.4.1

파이썬 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있습니다. 사용하는 경우 사용자 정의 mixin을FileSystemStorage 작성할 수 있습니다. .

마지막으로 업데이트 된 타임 스탬프와 같은 사용자 지정 부작용이 발생하도록하려면 FileField의 save 메서드 대신 모델의 save 메서드를 호출 할 수도 있습니다. 이 경우 파일의 이름 속성을 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.