Come caricare un file in Django? [chiuso]


668

Come principiante di Django, ho difficoltà a creare un'app di caricamento in Django 1.3. Non sono riuscito a trovare esempi / frammenti aggiornati. Qualcuno può pubblicare un codice di esempio minimo ma completo (modello, vista, modello) per farlo?

Risposte:


1273

Accidenti, la documentazione di Django non ha davvero un buon esempio al riguardo. Ho trascorso più di 2 ore a scavare tutti i pezzi per capire come funziona. Con questa conoscenza ho implementato un progetto che rende possibile caricare file e mostrarli come elenco. Per scaricare la fonte per il progetto, visitare https://github.com/axelpale/minimal-django-file-upload-example o clonarlo:

> git clone https://github.com/axelpale/minimal-django-file-upload-example.git

Aggiornamento 30-01-2013: l'origine di GitHub ha anche un'implementazione per Django 1.4 oltre a 1.3. Anche se ci sono alcune modifiche, il seguente tutorial è utile anche per 1.4.

Aggiornamento 2013-05-10: Implementazione per Django 1.5 su GitHub. Piccole modifiche al reindirizzamento in urls.py e all'utilizzo del tag del modello url in list.html. Grazie a hubert3 per lo sforzo.

Aggiornamento 2013-12-07: Django 1.6 supportato su GitHub. Un'importazione è cambiata in myapp / urls.py. Grazie va ad Arthedian .

Aggiornamento 17-03-2015: Django 1.7 supportato su GitHub, grazie ad aronysidoro .

Aggiornamento 2015-09-04: Django 1.8 supportato su GitHub, grazie a nerogit .

Aggiornamento 03/07/2016: Django 1.9 supportato su GitHub, grazie a daavve e nerogit

Albero del progetto

Un progetto di base Django 1.3 con un'unica app e directory media / per i caricamenti.

minimal-django-file-upload-example/
    src/
        myproject/
            database/
                sqlite.db
            media/
            myapp/
                templates/
                    myapp/
                        list.html
                forms.py
                models.py
                urls.py
                views.py
            __init__.py
            manage.py
            settings.py
            urls.py

1. Impostazioni: myproject / settings.py

Per caricare e pubblicare file, devi specificare dove Django memorizza i file caricati e da quale URL Django li serve. MEDIA_ROOT e MEDIA_URL sono in settings.py per impostazione predefinita ma sono vuoti. Vedi le prime righe in Django Managing Files per i dettagli. Ricorda inoltre di impostare il database e aggiungere myapp a INSTALLED_APPS

...
import os

BASE_DIR = os.path.dirname(os.path.dirname(__file__))
...
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'database.sqlite3'),
        'USER': '',
        'PASSWORD': '',
        'HOST': '',
        'PORT': '',
    }
}
...
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'
...
INSTALLED_APPS = (
    ...
    'myapp',
)

2. Modello: myproject / myapp / models.py

Successivamente è necessario un modello con un FileField. Questo particolare campo memorizza i file, ad esempio su media / documenti / 2011/12/24 / in base alla data corrente e MEDIA_ROOT. Vedi riferimento FileField .

# -*- coding: utf-8 -*-
from django.db import models

class Document(models.Model):
    docfile = models.FileField(upload_to='documents/%Y/%m/%d')

3. Modulo: myproject / myapp / forms.py

Per gestire correttamente il caricamento, è necessario un modulo. Questo modulo ha solo un campo ma è abbastanza. Per ulteriori dettagli, consultare il riferimento al modulo FileField .

# -*- coding: utf-8 -*-
from django import forms

class DocumentForm(forms.Form):
    docfile = forms.FileField(
        label='Select a file',
        help_text='max. 42 megabytes'
    )

4. Visualizza: myproject / myapp / views.py

Una vista in cui accade tutta la magia. Prestare attenzione a come request.FILESvengono gestiti. Per me, è stato davvero difficile individuare il fatto che request.FILES['docfile']può essere salvato su modelli. FileField in questo modo. Save () del modello gestisce automaticamente la memorizzazione del file nel filesystem.

# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse

from myproject.myapp.models import Document
from myproject.myapp.forms import DocumentForm

def list(request):
    # Handle file upload
    if request.method == 'POST':
        form = DocumentForm(request.POST, request.FILES)
        if form.is_valid():
            newdoc = Document(docfile = request.FILES['docfile'])
            newdoc.save()

            # Redirect to the document list after POST
            return HttpResponseRedirect(reverse('myapp.views.list'))
    else:
        form = DocumentForm() # A empty, unbound form

    # Load documents for the list page
    documents = Document.objects.all()

    # Render list page with the documents and the form
    return render_to_response(
        'myapp/list.html',
        {'documents': documents, 'form': form},
        context_instance=RequestContext(request)
    )

5. URL del progetto: myproject / urls.py

Django non serve MEDIA_ROOT per impostazione predefinita. Sarebbe pericoloso nell'ambiente di produzione. Ma in fase di sviluppo, potremmo tagliare. Presta attenzione all'ultima riga. Questa linea consente a Django di pubblicare file da MEDIA_URL. Funziona solo in fase di sviluppo.

Vedi riferimento django.conf.urls.static.static per i dettagli. Vedi anche questa discussione sulla pubblicazione di file multimediali .

# -*- coding: utf-8 -*-
from django.conf.urls import patterns, include, url
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = patterns('',
    (r'^', include('myapp.urls')),
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

6. URL delle app: myproject / myapp / urls.py

Per rendere accessibile la vista, è necessario specificare gli URL per essa. Niente di speciale qui.

# -*- coding: utf-8 -*-
from django.conf.urls import patterns, url

urlpatterns = patterns('myapp.views',
    url(r'^list/$', 'list', name='list'),
)

7. Template: myproject / myapp / templates / myapp / list.html

L'ultima parte: modello per l'elenco e il modulo di caricamento sottostante. Il modulo deve avere l'attributo enctype impostato su "multipart / form-data" e il metodo impostato su "post" per rendere possibile il caricamento su Django. Consulta la documentazione relativa ai caricamenti di file per i dettagli.

FileField ha molti attributi che possono essere utilizzati nei modelli. Ad esempio {{document.docfile.url}} e {{document.docfile.name}} come nel modello. Per ulteriori informazioni, consultare l' articolo sull'utilizzo dei file nei modelli e la documentazione dell'oggetto File .

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Minimal Django File Upload Example</title>   
    </head>
    <body>
    <!-- List of uploaded documents -->
    {% if documents %}
        <ul>
        {% for document in documents %}
            <li><a href="{{ document.docfile.url }}">{{ document.docfile.name }}</a></li>
        {% endfor %}
        </ul>
    {% else %}
        <p>No documents.</p>
    {% endif %}

        <!-- Upload form. Note enctype attribute! -->
        <form action="{% url 'list' %}" method="post" enctype="multipart/form-data">
            {% csrf_token %}
            <p>{{ form.non_field_errors }}</p>
            <p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
            <p>
                {{ form.docfile.errors }}
                {{ form.docfile }}
            </p>
            <p><input type="submit" value="Upload" /></p>
        </form>
    </body>
</html> 

8. Inizializza

Basta eseguire syncdb e RunServer.

> cd myproject
> python manage.py syncdb
> python manage.py runserver

risultati

Finalmente è tutto pronto. Nell'ambiente di sviluppo di Django predefinito è possibile visualizzare l'elenco dei documenti caricati su localhost:8000/list/. Oggi i file vengono caricati in / percorso / in / myproject / media / documenti / 2011/12/17 / e possono essere aperti dall'elenco.

Spero che questa risposta possa aiutare qualcuno tanto quanto mi avrebbe aiutato.


9
Trovata la posizione nei documenti di django che mostra i caricamenti di file. L'esempio in questa risposta è eccellente, ma le informazioni nei documenti di django verranno aggiornate con le nuove versioni. docs.djangoproject.com/en/dev/topics/http/file-uploads
TaiwanGrapefruitTea

1
L'esempio non funziona per Django "1.5". Nel codice HTML {% url list %}diventa {% url "list" %}.
Matthieu Riegler,

4
Grazie mille . Funziona davvero per me. Tuttavia, per i prossimi spettatori, dovresti controllare il codice in gitHub per la migliore compatibilità con le nuove versioni di Python e Django. Ad esempio, il views.py, render_to_response () dovrebbe essere sostituito con render (richiesta, ...,) per evitare l'errore CSRF. Saluti.
Huy Than

1
è possibile farlo senza FORMS?
Roel,

1
Il file può essere .zip o altri file compressi?
qg_java_17137,

74

In generale, quando si sta tentando di "solo ottenere un esempio funzionante", è meglio "iniziare a scrivere codice". Non esiste un codice qui per aiutarti, quindi rispondere alla domanda molto più funziona per noi.

Se vuoi prendere un file, hai bisogno di qualcosa del genere in un file html da qualche parte:

<form method="post" enctype="multipart/form-data">
    <input type="file" name="myfile" />
    <input type="submit" name="submit" value="Upload" />
</form>

Questo ti darà il pulsante Sfoglia, un pulsante di caricamento per avviare l'azione (inviare il modulo) e annotare il tipo in modo che Django sappia darti request.FILES

In una vista da qualche parte è possibile accedere al file con

def myview(request):
    request.FILES['myfile'] # this is my file

C'è un'enorme quantità di informazioni nei documenti di caricamento dei file

Ti consiglio di leggere attentamente la pagina e iniziare a scrivere il codice , quindi tornare con esempi e impilare le tracce quando non funziona.


10
Grazie Henry. In realtà ho letto i documenti e ho scritto un po 'di codice ma dato che i documenti hanno delle lacune (ad esempio "da qualche parte import handle_uploaded_file") e il mio codice era difettoso, ho pensato che sarebbe stato molto meglio se potessi partire da un esempio funzionante .
qliq,

26
Sono d'accordo con qliq. Un semplice esempio di lavoro è il modo più efficace per far andare i neofiti, non i documenti
Philip007,

11
Quello di enctype="multipart/form-data"cui avevo bisogno per farlo funzionare, grazie!
john-charles,

5
Non perdere il {% csrf_token%} nei tag del modulo.
jonincanada,

è possibile farlo SENZA FORME DA FORMS.PY?
Roel,

71

dimostrazione

Guarda il repository github , funziona con Django 3

Un esempio minimo di upload di file Django

1. Crea un progetto django

Esegui startproject ::

$ django-admin.py startproject sample

ora viene creata una cartella ( esempio ).

2. creare un'app

Crea un'app ::

$ cd sample
$ python manage.py startapp uploader

Ora uploaderviene creata una cartella ( ) con questi file:

uploader/
  __init__.py
  admin.py
  app.py
  models.py
  tests.py
  views.py
  migrations/
    __init__.py

3. Aggiorna settings.py

Su sample/settings.pyadd 'uploader'a INSTALLED_APPSe aggiungere MEDIA_ROOTe MEDIA_URL, cioè ::

INSTALLED_APPS = [
    'uploader',
    ...<other apps>...      
]

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

4. Aggiorna urls.py

in sample/urls.pyaggiunta ::

...<other imports>...
from django.conf import settings
from django.conf.urls.static import static
from uploader import views as uploader_views

urlpatterns = [
    ...<other url patterns>...
    path('', uploader_views.UploadView.as_view(), name='fileupload'),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

5. Aggiorna models.py

aggiornamento uploader/models.py::

from django.db import models
class Upload(models.Model):
    upload_file = models.FileField()    
    upload_date = models.DateTimeField(auto_now_add =True)

6. Aggiorna views.py

aggiornamento uploader/views.py::

from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .models import Upload
class UploadView(CreateView):
    model = Upload
    fields = ['upload_file', ]
    success_url = reverse_lazy('fileupload')
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['documents'] = Upload.objects.all()
        return context

7. creare modelli

Crea una cartella campione / uploader / template / uploader

Crea un file upload_form.html cioè sample/uploader/templates/uploader/upload_form.html::

<div style="padding:40px;margin:40px;border:1px solid #ccc">
    <h1>Django File Upload</h1>
    <form method="post" enctype="multipart/form-data">
      {% csrf_token %}
      {{ form.as_p }}
      <button type="submit">Submit</button>
    </form><hr>
    <ul>
    {% for document in documents %}
        <li>
            <a href="{{ document.upload_file.url }}">{{ document.upload_file.name }}</a>
            <small>({{ document.upload_file.size|filesizeformat }}) - {{document.upload_date}}</small>
        </li>
    {% endfor %}
    </ul>
</div>

8. Sincronizzare il database

Sincronizza database e ran server ::

$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py runserver

visita http: // localhost: 8000 /


2
perfetto tranne per l'ultima riga - dovrebbe essere localhost.com:8000/upload > Questo ha funzionato per django 1.6 e Python 3.3.
Steve,

5
+1 per il modello riutilizzabile di design dell'app django
Marcel,

1
Akseli ha usato un FileFieldpo 'suhail ha usato ImageFieldqualcuno, qualcuno potrebbe spiegare per favore le scelte?
dvtan,

@dtgq Ho aggiornato la risposta da utilizzare con FileField. ImageFieldè necessario solo per il caricamento di immagini. l'aggiornamento funzionerà con Django 1.11.
suhailvs,

testato su Django 2.0 e funzionato perfettamente
diek

29

Devo dire che trovo confusa la documentazione su Django. Anche per l'esempio più semplice, perché vengono menzionati i moduli? L'esempio che ho avuto per lavorare in views.py è: -

for key, file in request.FILES.items():
    path = file.name
    dest = open(path, 'w')
    if file.multiple_chunks:
        for c in file.chunks():
            dest.write(c)
    else:
        dest.write(file.read())
    dest.close()

Il file html assomiglia al codice seguente, anche se questo esempio carica solo un file e il codice per salvare i file gestisce molti: -

<form action="/upload_file/" method="post" enctype="multipart/form-data">{% csrf_token %}
<label for="file">Filename:</label>
<input type="file" name="file" id="file" />
<br />
<input type="submit" name="submit" value="Submit" />
</form>

Questi esempi non sono il mio codice, sono stati ottenuti da altri due esempi che ho trovato. Sono un principiante relativamente di Django, quindi è molto probabile che mi manchi qualche punto chiave.


3
+1 per non usare a FileFielde a model.Form. Per i principianti (e per compiti banali), l'elaborazione manuale dei file caricati come mostrato sopra è meno confusa.
AneesAhmed777,

dest = open (path, 'wb') quando il file scrive con byte
Bipul Roy

20

Avevo anche il requisito simile. La maggior parte degli esempi in rete chiedono di creare modelli e creare moduli che non volevo usare. Ecco il mio codice finale.

if request.method == 'POST':
    file1 = request.FILES['file']
    contentOfFile = file1.read()
    if file1:
        return render(request, 'blogapp/Statistics.html', {'file': file1, 'contentOfFile': contentOfFile})

E in HTML per caricare ho scritto:

{% block content %}
    <h1>File content</h1>
    <form action="{% url 'blogapp:uploadComplete'%}" method="post" enctype="multipart/form-data">
         {% csrf_token %}
        <input id="uploadbutton" type="file" value="Browse" name="file" accept="text/csv" />
        <input type="submit" value="Upload" />
    </form>
    {% endblock %}

Di seguito è riportato l'HTML che visualizza il contenuto del file:

{% block content %}
    <h3>File uploaded successfully</h3>
    {{file.name}}
    </br>content = {{contentOfFile}}
{% endblock %}

bene perché a volte si vuole solo usare il contenuto del file per non salvare il caricamento ...
nemesisfixx,

17

Estendendo l'esempio di Henry :

import tempfile
import shutil

FILE_UPLOAD_DIR = '/home/imran/uploads'

def handle_uploaded_file(source):
    fd, filepath = tempfile.mkstemp(prefix=source.name, dir=FILE_UPLOAD_DIR)
    with open(filepath, 'wb') as dest:
        shutil.copyfileobj(source, dest)
    return filepath

Puoi chiamare questa handle_uploaded_filefunzione dalla tua vista con l'oggetto file caricato. Ciò salverà il file con un nome univoco (con prefisso con il nome del file caricato originale) nel filesystem e restituirà il percorso completo del file salvato. È possibile salvare il percorso nel database e fare qualcosa con il file in un secondo momento.


Imran, ho provato il tuo codice a mio avviso, ma ho riscontrato questo errore: l'oggetto 'WSGIRequest' non ha attributo 'nome'.
qliq,

2
Passa l'oggetto file caricato ( request.FILES['myfile']) a handle_uploaded_file, non lo requeststesso.
Imran,

Posso salvarlo direttamente nel database? stackoverflow.com/questions/24705246/…
AlexandruC

Usandolo prefix=source.nameha aggiunto caratteri extra alla fine del file, rovinando l'estensione del file. Ad esempio, è upload.csvstato modificato in upload.csv5334. Modificandolo per suffix=source.namerisolverlo per me.
Tahreem Iqbal,

13

Qui può esserti utile: crea un campo file nel tuo model.py

Per caricare il file (nel tuo admin.py):

def save_model(self, request, obj, form, change):
    url = "http://img.youtube.com/vi/%s/hqdefault.jpg" %(obj.video)
    url = str(url)

    if url:
        temp_img = NamedTemporaryFile(delete=True)
        temp_img.write(urllib2.urlopen(url).read())
        temp_img.flush()
        filename_img = urlparse(url).path.split('/')[-1]
        obj.image.save(filename_img,File(temp_img)

e usa quel campo anche nel tuo modello.


1
Questo è utile quando devi temperare manualmente con i file che vuoi salvare. In tal caso, potresti anche aver bisogno di questa sezione: docs.djangoproject.com/en/dev/topics/files/#the-file-object
kecske

11

Puoi fare riferimento agli esempi di server in Fine Uploader, che ha la versione di django. https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader

È molto elegante e, soprattutto, offre funzionalità js lib. Il modello non è incluso negli esempi di server, ma puoi trovare la demo sul suo sito web. Uploader eccellente: http://fineuploader.com/demos.html

django-fine-Uploader

views.py

UploadView invia posta ed elimina la richiesta ai rispettivi gestori.

class UploadView(View):

    @csrf_exempt
    def dispatch(self, *args, **kwargs):
        return super(UploadView, self).dispatch(*args, **kwargs)

    def post(self, request, *args, **kwargs):
        """A POST request. Validate the form and then handle the upload
        based ont the POSTed data. Does not handle extra parameters yet.
        """
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            handle_upload(request.FILES['qqfile'], form.cleaned_data)
            return make_response(content=json.dumps({ 'success': True }))
        else:
            return make_response(status=400,
                content=json.dumps({
                    'success': False,
                    'error': '%s' % repr(form.errors)
                }))

    def delete(self, request, *args, **kwargs):
        """A DELETE request. If found, deletes a file with the corresponding
        UUID from the server's filesystem.
        """
        qquuid = kwargs.get('qquuid', '')
        if qquuid:
            try:
                handle_deleted_file(qquuid)
                return make_response(content=json.dumps({ 'success': True }))
            except Exception, e:
                return make_response(status=400,
                    content=json.dumps({
                        'success': False,
                        'error': '%s' % repr(e)
                    }))
        return make_response(status=404,
            content=json.dumps({
                'success': False,
                'error': 'File not present'
            }))

forms.py

class UploadFileForm(forms.Form):

    """ This form represents a basic request from Fine Uploader.
    The required fields will **always** be sent, the other fields are optional
    based on your setup.
    Edit this if you want to add custom parameters in the body of the POST
    request.
    """
    qqfile = forms.FileField()
    qquuid = forms.CharField()
    qqfilename = forms.CharField()
    qqpartindex = forms.IntegerField(required=False)
    qqchunksize = forms.IntegerField(required=False)
    qqpartbyteoffset = forms.IntegerField(required=False)
    qqtotalfilesize = forms.IntegerField(required=False)
    qqtotalparts = forms.IntegerField(required=False)

7

Non sono sicuro se ci siano degli svantaggi in questo approccio, ma ancora più minimale, in views.py:

entry = form.save()

# save uploaded file
if request.FILES['myfile']:
    entry.myfile.save(request.FILES['myfile']._name, request.FILES['myfile'], True)

0

Ho affrontato il problema simile e risolto dal sito di amministrazione di Django.

# models
class Document(models.Model):
    docfile = models.FileField(upload_to='documents/Temp/%Y/%m/%d')

    def doc_name(self):
        return self.docfile.name.split('/')[-1] # only the name, not full path

# admin
from myapp.models import Document
class DocumentAdmin(admin.ModelAdmin):
    list_display = ('doc_name',)
admin.site.register(Document, DocumentAdmin)

[inserisci la descrizione del link qui] [1] [inserisci la descrizione del link qui] [2] [1]: youtu.be/0tNZB3dyopY [2]: youtu.be/klhMYMc3PlY
uda123
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.