Wie lade ich eine Datei in Django hoch? [geschlossen]

668

Als Neuling bei Django habe ich Schwierigkeiten, eine Upload-App in Django 1.3 zu erstellen. Ich konnte keine aktuellen Beispiele / Schnipsel finden. Darf jemand einen minimalen, aber vollständigen Beispielcode (Modell, Ansicht, Vorlage) veröffentlichen, um dies zu tun?

qliq
quelle

Antworten:

1273

Puh, die Django-Dokumentation hat wirklich kein gutes Beispiel dafür. Ich habe über 2 Stunden damit verbracht, alle Teile auszugraben, um zu verstehen, wie das funktioniert. Mit diesem Wissen habe ich ein Projekt implementiert, das es ermöglicht, Dateien hochzuladen und als Liste anzuzeigen. Um die Quelle für das Projekt herunterzuladen, besuchen Sie https://github.com/axelpale/minimal-django-file-upload-example oder klonen Sie sie:

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

Update 30.01.2013: Die Quelle bei GitHub hat neben 1.3 auch eine Implementierung für Django 1.4. Obwohl es nur wenige Änderungen gibt, ist das folgende Tutorial auch für 1.4 nützlich.

Update 10.05.2013: Implementierung für Django 1.5 bei GitHub. Kleinere Änderungen bei der Umleitung in urls.py und Verwendung des URL-Vorlagen-Tags in list.html. Danke an hubert3 für die Mühe.

Update 07.12.2013: Django 1.6 wird bei GitHub unterstützt. Ein Import wurde in myapp / urls.py geändert. Danke geht an Arthedian .

Update 17.03.2015: Django 1.7 wird dank aronysidoro bei GitHub unterstützt .

Update 04.09.2015: Django 1.8 wird dank nerogit bei GitHub unterstützt .

Update 03.07.2016: Django 1.9 wird bei GitHub dank Daavve und Nerogit unterstützt

Projektbaum

Ein einfaches Django 1.3-Projekt mit einer einzigen App und einem Medien- / Verzeichnis zum Hochladen.

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. Einstellungen: myproject / settings.py

Um Dateien hochzuladen und bereitzustellen, müssen Sie angeben, wo Django hochgeladene Dateien speichert und von welcher URL Django sie bereitstellt. MEDIA_ROOT und MEDIA_URL befinden sich standardmäßig in settings.py, sind jedoch leer. Weitere Informationen finden Sie in den ersten Zeilen in Django Managing Files . Denken Sie daran, auch die Datenbank festzulegen und myapp zu INSTALLED_APPS hinzuzufügen

...
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. Modell: myproject / myapp / models.py

Als nächstes benötigen Sie ein Modell mit einem FileField. In diesem speziellen Feld werden Dateien gespeichert, z. B. in Medien / Dokumenten / 2011/12/24 / basierend auf dem aktuellen Datum und MEDIA_ROOT. Siehe FileField-Referenz .

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

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

3. Formular: myproject / myapp / forms.py

Um den Upload gut zu handhaben, benötigen Sie ein Formular. Dieses Formular hat nur ein Feld, aber das reicht aus. Weitere Informationen finden Sie in der Referenz zu Form 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. Ansicht: myproject / myapp / views.py

Eine Ansicht, in der all die Magie passiert. Achten Sie darauf, wie request.FILESdamit umgegangen wird. Für mich war es wirklich schwer zu erkennen, dass request.FILES['docfile']es in Modellen gespeichert werden kann. FileField einfach so. Mit save () des Modells wird die Datei automatisch im Dateisystem gespeichert.

# -*- 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. Projekt-URLs: myproject / urls.py

Django bedient standardmäßig nicht MEDIA_ROOT. Das wäre in der Produktionsumgebung gefährlich. Aber in der Entwicklungsphase könnten wir abkürzen. Achten Sie auf die letzte Zeile. Diese Zeile ermöglicht es Django, Dateien von MEDIA_URL bereitzustellen. Dies funktioniert nur in der Entwicklungsphase.

Weitere Informationen finden Sie in der Referenz zu django.conf.urls.static.static . Siehe auch diese Diskussion zum Bereitstellen von Mediendateien .

# -*- 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. App-URLs: myproject / myapp / urls.py

Um die Ansicht zugänglich zu machen, müssen Sie URLs dafür angeben. Hier ist nichts Besonderes.

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

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

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

Der letzte Teil: Vorlage für die Liste und das Upload-Formular darunter. Das Formular muss ein enctype-Attribut auf "multipart / form-data" und eine Methode auf "post" setzen, um das Hochladen nach Django zu ermöglichen. Weitere Informationen finden Sie in der Dokumentation zum Hochladen von Dateien .

Das FileField verfügt über viele Attribute, die in Vorlagen verwendet werden können. ZB {{document.docfile.url}} und {{document.docfile.name}} wie in der Vorlage. Weitere Informationen hierzu finden Sie im Artikel Verwenden von Dateien in Modellen und in der Dokumentation zum Dateiobjekt .

<!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. Initialisieren

Führen Sie einfach syncdb und runserver aus.

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

Ergebnisse

Endlich ist alles fertig. In der Standard-Django-Entwicklungsumgebung kann die Liste der hochgeladenen Dokumente unter angezeigt werden localhost:8000/list/. Heute werden die Dateien nach / path / to / myproject / media / documents / 2011/12/17 / hochgeladen und können aus der Liste geöffnet werden.

Ich hoffe, diese Antwort hilft jemandem so sehr, wie es mir geholfen hätte.

Akseli Palén
quelle
9
In Django-Dokumenten wurde der Speicherort gefunden, an dem das Hochladen von Dateien angezeigt wird. Das Beispiel in dieser Antwort ist ausgezeichnet, aber die Informationen in den Django-Dokumenten werden mit neuen Versionen auf dem neuesten Stand gehalten. docs.djangoproject.com/de/dev/topics/http/file-uploads
TaiwanGrapefruitTea
1
Das Beispiel funktioniert nicht für Django "1.5". Im HTML {% url list %}wird {% url "list" %}.
Matthieu Riegler
4
Vielen Dank . Es funktioniert wirklich für mich. Für die kommenden Betrachter sollten Sie jedoch den Code in gitHub auf die beste Kompatibilität mit neuen Versionen von Python und Django überprüfen. Beispielsweise sollte die Datei views.py, render_to_response () durch render (request, ...,) ersetzt werden, um den CSRF-Fehler zu vermeiden. Prost.
Huy als
1
ist es möglich dies ohne FORMEN zu tun?
Roel
1
Kann die Datei .zip oder andere komprimierte Dateien sein?
qg_java_17137
75

Wenn Sie versuchen, nur ein funktionierendes Beispiel zu erhalten, ist es im Allgemeinen am besten, einfach mit dem Schreiben von Code zu beginnen. Es gibt hier keinen Code, der Ihnen dabei hilft, sodass die Beantwortung der Frage für uns viel einfacher ist.

Wenn Sie eine Datei abrufen möchten, benötigen Sie irgendwo in einer HTML-Datei Folgendes:

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

Dadurch erhalten Sie die Schaltfläche zum Durchsuchen, eine Schaltfläche zum Hochladen, um die Aktion zu starten (senden Sie das Formular) und den Enctype zu notieren, damit Django Sie kennen kann request.FILES

In einer Ansicht irgendwo können Sie mit auf die Datei zugreifen

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

Die Datei-Upload-Dokumente enthalten eine Vielzahl von Informationen

Ich empfehle Ihnen, die Seite gründlich zu lesen und einfach mit dem Schreiben von Code zu beginnen. Geben Sie dann Beispiele und Stapelspuren zurück, wenn dies nicht funktioniert.

Henry
quelle
10
Danke Henry. Eigentlich habe ich die Dokumente gelesen und Code geschrieben, aber da die Dokumente einige Lücken aufweisen (zum Beispiel "von irgendwo import handle_uploaded_file") und mein Code fehlerhaft war, dachte ich, dass es viel besser wäre, wenn ich von einem funktionierenden Beispiel ausgehen könnte .
Qliq
26
Stimmen Sie mit qliq überein. Ein einfaches Arbeitsbeispiel ist der effizienteste Weg, um Neulinge zum Laufen zu bringen, nicht Dokumente
Philip007
11
Das, enctype="multipart/form-data"was ich brauchte, um diese Arbeit zu machen, danke!
John-Charles
5
Verpassen Sie nur nicht die {% csrf_token%} in den Formular-Tags.
Jonincanada
ist es möglich, dies OHNE FORMEN VON FORMS.PY zu tun?
Roel
71

Demo

Siehe das Github-Repo , funktioniert mit Django 3

Ein minimales Beispiel für das Hochladen von Django-Dateien

1. Erstellen Sie ein Django-Projekt

Führen Sie startproject :: aus.

$ django-admin.py startproject sample

Jetzt wird ein Ordner ( Beispiel ) erstellt.

2. Erstellen Sie eine App

Erstellen Sie eine App ::

$ cd sample
$ python manage.py startapp uploader

Nun wird ein Ordner ( uploader) mit diesen Dateien erstellt ::

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

3. Aktualisieren Sie settings.py

Auf sample/settings.pyAdd 'uploader'zu INSTALLED_APPSund fügen MEDIA_ROOTund MEDIA_URL, dh ::

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

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

4. Aktualisieren Sie urls.py

in sample/urls.pyadd ::

...<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. Aktualisieren Sie models.py

update 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. Aktualisieren Sie views.py

update 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. Vorlagen erstellen

Erstellen Sie einen Ordner sample / uploader / templates / uploader

Erstellen Sie eine Datei upload_form.html dh 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. Datenbank synchronisieren

Synchronisieren Sie Datenbank und Runserver ::

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

Besuchen Sie http: // localhost: 8000 /

suhailvs
quelle
2
perfekt bis auf die letzte Zeile - sollte localhost.com:8000/upload sein > Dies funktionierte für Django 1.6 und Python 3.3.
Steve
5
+1 für wiederverwendbare Django App Design-Muster
Marcel
1
Akseli benutzte eine FileFieldWeile suhail benutzte eine ImageField, könnte jemand bitte die Entscheidungen erklären?
dvtan
@dtgq Ich habe die Antwort aktualisiert, um sie zu verwenden FileField. ImageFieldmuss nur für bild hochladen. Das Update funktioniert mit Django 1.11.
Suhailvs
getestet auf Django 2.0 und funktionierte perfekt
diek
29

Ich muss sagen, ich finde die Dokumentation bei Django verwirrend. Auch für das einfachste Beispiel, warum werden Formulare erwähnt? Das Beispiel, das ich in views.py arbeiten musste, ist: -

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()

Die HTML-Datei sieht wie folgt aus: In diesem Beispiel wird jedoch nur eine Datei hochgeladen, und der Code zum Speichern der Dateien verarbeitet viele: -

<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>

Diese Beispiele sind nicht mein Code, sie wurden aus zwei anderen Beispielen ausgewählt, die ich gefunden habe. Ich bin ein relativer Anfänger von Django, daher ist es sehr wahrscheinlich, dass mir ein wichtiger Punkt fehlt.

jimscafe
quelle
3
+1 für die Nichtverwendung von a FileFieldund a model.Form. Für Anfänger (und für triviale Aufgaben) ist die manuelle Verarbeitung hochgeladener Dateien wie oben gezeigt weniger verwirrend.
AneesAhmed777
dest = open (Pfad, 'wb') beim Schreiben von Dateien mit Bytes
Bipul Roy
20

Ich hatte auch die ähnliche Anforderung. Die meisten Beispiele im Internet fordern das Erstellen von Modellen und Formularen, die ich nicht verwenden wollte. Hier ist mein endgültiger Code.

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

Und in HTML zum Hochladen schrieb ich:

{% 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 %}

Das Folgende ist der HTML-Code, der den Inhalt der Datei anzeigt:

{% block content %}
    <h3>File uploaded successfully</h3>
    {{file.name}}
    </br>content = {{contentOfFile}}
{% endblock %}
Chetan Pawar
quelle
gut, weil man manchmal nur den Inhalt der Datei verwenden möchte, um den Upload nicht zu speichern ...
nemesisfixx
17

Erweiterung auf Henrys Beispiel :

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

Sie können diese handle_uploaded_fileFunktion aus Ihrer Sicht mit dem hochgeladenen Dateiobjekt aufrufen . Dadurch wird die Datei unter einem eindeutigen Namen (vorangestellt mit dem Dateinamen der ursprünglich hochgeladenen Datei) im Dateisystem gespeichert und der vollständige Pfad der gespeicherten Datei zurückgegeben. Sie können den Pfad in der Datenbank speichern und später etwas mit der Datei tun.

Imran
quelle
Imran, ich habe Ihren Code in meiner Ansicht ausprobiert, aber den folgenden Fehler erhalten: Das Objekt 'WSGIRequest' hat kein Attribut 'Name'.
Qliq
2
Übergeben Sie das hochgeladene Dateiobjekt ( request.FILES['myfile']) an handle_uploaded_file, nicht an das requestselbst.
Imran
Könnte ich es direkt in der Datenbank speichern? stackoverflow.com/questions/24705246/…
AlexandruC
Durch die Verwendung prefix=source.namewurden zusätzliche Zeichen am Ende der Datei hinzugefügt, wodurch die Dateierweiterung durcheinander gebracht wurde. ZB upload.csvwurde geändert zu upload.csv5334. Ändern Sie es, um suffix=source.namees für mich zu beheben.
Tahreem Iqbal
13

Hier kann es Ihnen helfen: Erstellen Sie ein Dateifeld in Ihrer models.py

Zum Hochladen der Datei (in Ihrer 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)

und verwenden Sie dieses Feld auch in Ihrer Vorlage.

Vijesh Venugopal
quelle
1
Dies ist nützlich, wenn Sie manuell mit Dateien arbeiten müssen, die Sie speichern möchten. In diesem Fall
kecske
11

Sie können auf Serverbeispiele in Fine Uploader verweisen, das die Django-Version hat. https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader

Es ist sehr elegant und vor allem bietet es eine vorgestellte js lib. Vorlage ist nicht in Server-Beispielen enthalten, aber Sie können Demo auf seiner Website finden. Feiner Uploader: http://fineuploader.com/demos.html

Django-Fein-Uploader

views.py

UploadView sendet Post- und Löschanforderungen an die jeweiligen Handler.

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)
Jiawei Dai
quelle
7

Ich bin mir nicht sicher, ob dieser Ansatz Nachteile hat, aber in views.py noch minimaler:

entry = form.save()

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

Ich stand vor einem ähnlichen Problem und wurde von der Django-Admin-Site gelöst.

# 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)
hlpmee
quelle
[ Linkbeschreibung hier eingeben] [1] [ Linkbeschreibung hier eingeben] [2] [1]: youtu.be/0tNZB3dyopY [2]: youtu.be/klhMYMc3PlY
uda123