2011-09-22 24 views
62

Oto mój model. Co chcę zrobić, to wygenerować nowy plik i zastąpić istniejący gdy instancja modelu jest zapisany:Django - jak utworzyć plik i zapisać go w FileField modelu?

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) 

widzę mnóstwo dokumentacji o tym, jak przesłać plik. Ale w jaki sposób mogę wygenerować plik, przypisać go do pola modelu i czy Django będzie przechowywać go we właściwym miejscu?

Odpowiedz

91

Chcesz się przyjrzeć FileField and FieldFile w dokumentach Django, a zwłaszcza FieldFile.save().

Zasadniczo pole zadeklarowane jako FileField, po uzyskaniu dostępu, udostępnia instancję klasy FieldFile, która udostępnia kilka metod interakcji z plikiem bazowym. Więc co trzeba zrobić, to:

self.license_file.save(new_name, new_contents) 

gdzie new_name jest nazwa pliku, który szkoda przypisane i new_contents jest zawartość pliku. Zauważ, że new_contents musi być instancją django.core.files.File lub django.core.files.base.ContentFile (zobacz podane linki do instrukcji dla szczegółów). Oba wybory sprowadzają się do:

# 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, myślę, że będzie działać, ale ja dostaję w jakiejś pętli rekurencyjnej dzwoniącej, że w sposobie oszczędzania. Po prostu tworzy pliki na zawsze. – Greg

+8

Dla problemu rekursywnego muszę wywołać self.license_file.save z arg save = False. – Greg

+0

@Greg dziękuję, problem rekurencyjny jest naprawdę denerwujący. – laike9m

18

Przyjęte rozwiązanie jest z pewnością dobrym rozwiązaniem, ale tutaj jest sposób poszedłem o generowanie CSV i obsługujących go z widzenia.

#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 

że było warto natomiast umieszczenie tego tutaj zajęło mi trochę błahy, aby wszystkie pożądane zachowania (nadpisać istniejący plik, przechowywania na właściwym miejscu, a nie tworzenie duplikatów plików itd.)

Django 1.4.1

Python 2.7.3

0

Dzięki @tawmas. Oprócz tego,

Wystąpił błąd, jeśli nie określiłem trybu pliku podczas otwierania pliku. Więc

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

Dla rodzaju pliku ZIP,

f = open('/path/to/file.zip', 'rb') 
Powiązane problemy