web-dev-qa-db-fra.com

Django - comment créer un fichier et l'enregistrer dans le FileField d'un modèle?

Voici mon modèle. Ce que je veux faire, c'est générer un nouveau fichier et écraser le fichier existant chaque fois qu'une instance de modèle est enregistrée:

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)

Je vois beaucoup de documentation sur la façon de télécharger un fichier. Mais comment puis-je générer un fichier, l’assigner à un champ de modèle et le faire stocker par Django au bon endroit? 

77
Greg

Vous voulez regarder FileField et FieldFile dans les documents Django, et en particulier FieldFile.save () .

En gros, un champ déclaré en tant que FileField, lors de l'accès, vous donne une instance de la classe FieldFile, qui vous donne plusieurs méthodes pour interagir avec le fichier sous-jacent. Alors, ce que vous devez faire c'est:

self.license_file.save(new_name, new_contents)

new_name est le nom du fichier que vous souhaitez attribuer et new_contents au contenu du fichier. Notez que new_contents doit être une instance de Django.core.files.File ou Django.core.files.base.ContentFile (voir les liens donnés au manuel pour plus de détails). Les deux choix se résument à:

# 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'))
116
tawmas

La réponse acceptée est certainement une bonne solution, mais voici comment je me suis mis à générer un fichier CSV et à le servir d’un point de vue.

#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

Je pensais que cela valait la peine de mettre ceci ici, car il m'a fallu un peu de bidouillage pour obtenir tous les comportements souhaitables (écraser le fichier existant, stocker au bon endroit, ne pas créer de fichiers dupliqués, etc.).

Django 1.4.1

Python 2.7.3

20
markdsievers

Merci @tawmas. En plus de ça,

J'ai une erreur si je ne spécifie pas le mode de fichier lors de l'ouverture du fichier. Alors,

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

Pour le type de fichier Zip,

f = open('/path/to/file.Zip', 'rb')
0
rajagopalx