Django - bir dosya nasıl oluşturulur ve bir modelin Dosya Alanına nasıl kaydedilir?


110

İşte modelim. Yapmak istediğim şey, yeni bir dosya oluşturmak ve bir model örneği kaydedildiğinde mevcut dosyanın üzerine yazmak:

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)

Bir dosyanın nasıl yükleneceğiyle ilgili çok sayıda belge görüyorum. Ama nasıl bir dosya oluşturabilirim, onu bir model alanına atayabilirim ve Django'nun bunu doğru yerde saklamasını sağlayabilirim?

Yanıtlar:


152

Django belgelerinde FileField ve FieldFile'a ve özellikle FieldFile.save () 'ye bir göz atmak istiyorsunuz .

Temel olarak, FileFielderişildiğinde, olarak bildirilen bir alan FieldFile, size temeldeki dosyayla etkileşim kurmanız için çeşitli yöntemler sağlayan bir sınıf örneği verir. Yani yapmanız gereken şey:

self.license_file.save(new_name, new_contents)

Nerede new_nameatadığınız dilek dosya adı ve new_contentsdosyanın içeriğidir. Bunun new_contentsbir django.core.files.Fileveya örneği olması gerektiğini unutmayın django.core.files.base.ContentFile(ayrıntılar için kılavuza verilen bağlantılara bakın). İki seçenek şu şekilde özetlenebilir:

# 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
Tamam, bunun işe yarayacağını düşünüyorum ama bunu kaydetme yönteminde çağıran bir tür özyinelemeli döngüye giriyorum. Sadece sonsuza kadar dosya oluşturmaya devam ediyor.
Greg

11
Özyinelemeli sorun için self.license_file.save'yi arg save = False ile çağırmalıyım.
Greg

1
Bu (ContentFile), django-wkhtmltopdf convert_to_pdfkomutunun döndürdüğü dosya dizesiyle mükemmel çalışır . Teşekkür ederim!!
Nostalg.io

Buna ek olarak, dosyayı açarken dosya modunu belirtmezsem bir hata alıyorum. Öyleyse, f = open('/path/to/file', 'r')ZIP türü dosya içinf = open('/path/to/file.zip', 'rb')
rajagopalx

1
Benim durumumda, yukarıdakiler dosyayı klasöre kaydetmiyordu. Sorun şu ki, django uygulamamı bir kereviz işçisiyle birlikte çalıştırmak için docker-compose kullanıyorum . Django uygulaması hacmi MEDIA_ROOT, kereviz işçisinde aynı ciltle paylaşılmadı. Adlandırılmış hacmi paylaşmak onu düzeltti ( ref ).
shadi

28

Kabul edilen yanıt kesinlikle iyi bir çözüm, ancak bir CSV oluşturmaya ve onu bir bakış açısıyla sunmaya başladığım yol burada.

Bunu buraya koymanın değeceğini düşündüm, çünkü istenen tüm davranışları elde etmek için biraz uğraştım (mevcut dosyanın üzerine yazın, doğru yere depolayın, çift dosyalar oluşturmayın vb.).

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()Dosya kaydetme işlemi sırasında istisnalar olması durumunda bir bağlam yöneticisi kullanmak veya çağrı yapmak iyi bir uygulamadır . Depolama arka ucunuz çalışmadığında vb. Olabilir.

Herhangi bir üzerine yazma davranışı, depolama arka ucunuzda yapılandırılmalıdır. Örneğin S3Boto3Storage'ın bir ayarı vardır AWS_S3_FILE_OVERWRITE. Eğer kullanıyorsanız özel bir mixinFileSystemStorage yazabilirsiniz .

Son güncellenen zaman damgaları gibi herhangi bir özel yan etkinin olmasını istiyorsanız, FileField'ın kaydetme yöntemi yerine modelin kaydetme yöntemini de çağırmak isteyebilirsiniz. Durum buysa, dosyanın name özniteliğini de göreceli olan dosyanın adına ayarlayabilirsiniz MEDIA_ROOT. Varsayılan olarak dosyanın tam yoludur ve ayarlamazsanız sorunlara neden olabilir - bkz. Dosya .__ init __ () ve Dosya.adı .

Aşağıda , FileField / ImageFile olduğu, yalnızca FileField yerine tüm model örneğini çağıran selfmodel örneğinin olduğu bir örnek verilmiştir :my_filesave()

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()
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.