Bagaimana cara mengunggah file dalam Django? [Tutup]

668

Sebagai pemula untuk Django, saya mengalami kesulitan membuat aplikasi unggah di Django 1.3. Saya tidak dapat menemukan contoh / cuplikan terbaru. Dapatkah seseorang memposting kode contoh minimal tapi lengkap (Model, Lihat, Templat) untuk melakukannya?

qliq
sumber

Jawaban:

1273

Fiuh, dokumentasi Django benar-benar tidak punya contoh bagus tentang ini. Saya menghabiskan lebih dari 2 jam untuk menggali semua bagian untuk memahami cara kerjanya. Dengan pengetahuan itu saya mengimplementasikan proyek yang memungkinkan untuk mengunggah file dan menunjukkannya sebagai daftar. Untuk mengunduh sumber untuk proyek ini, kunjungi https://github.com/axelpale/minimal-django-file-upload-example atau klonkan:

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

Pembaruan 2013-01-30: Sumber di GitHub juga menerapkan untuk Django 1.4 selain 1.3. Meskipun ada beberapa perubahan, tutorial berikut ini juga berguna untuk 1.4.

Pembaruan 2013-05-10: Implementasi untuk Django 1.5 di GitHub. Perubahan kecil dalam pengalihan di urls.py dan penggunaan tag templat url di list.html. Berkat hubert3 untuk usahanya.

Pembaruan 2013-12-07: Django 1.6 didukung di GitHub. Satu impor berubah di myapp / urls.py. Terima kasih kepada Arthedian .

Pembaruan 2015-03-17: Django 1.7 didukung di GitHub, terima kasih kepada aronysidoro .

Pembaruan 2015-09-04: Django 1.8 didukung di GitHub, terima kasih kepada nerogit .

Pembaruan 2016-07-03: Django 1.9 didukung di GitHub, terima kasih kepada daavve dan nerogit

Pohon proyek

Proyek Django 1.3 dasar dengan satu aplikasi dan media / direktori untuk diunggah.

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

Untuk mengunggah dan menyajikan file, Anda perlu menentukan di mana Django menyimpan file yang diunggah dan dari URL apa Django menyajikannya. MEDIA_ROOT dan MEDIA_URL secara default di setting.py tetapi kosong. Lihat baris pertama dalam Django Mengelola File untuk detailnya. Ingat juga atur database dan tambahkan myapp ke 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. Model: myproject / myapp / models.py

Selanjutnya Anda memerlukan model dengan FileField. Bidang khusus ini menyimpan file misalnya ke media / dokumen / 2011/12/24 / berdasarkan tanggal saat ini dan MEDIA_ROOT. Lihat referensi FileField .

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

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

3. Formulir: myproject / myapp / forms.py

Untuk menangani unggahan dengan baik, Anda memerlukan formulir. Formulir ini hanya memiliki satu bidang tetapi itu sudah cukup. Lihat referensi Formulir FileField untuk detailnya.

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

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

4. Lihat: myproject / myapp / views.py

Tampilan di mana semua keajaiban terjadi. Perhatikan bagaimana request.FILESpenanganannya. Bagi saya, itu sangat sulit untuk menemukan fakta yang request.FILES['docfile']dapat disimpan ke model. File hanya seperti itu. Save model () menangani penyimpanan file ke sistem file secara otomatis.

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

Django tidak menayangkan MEDIA_ROOT secara default. Itu akan berbahaya di lingkungan produksi. Tetapi dalam tahap pengembangan, kita bisa memotong pendek. Perhatikan baris terakhir. Baris itu memungkinkan Django untuk menyajikan file dari MEDIA_URL. Ini hanya berfungsi pada tahap pengembangan.

Lihat referensi django.conf.urls.static.static untuk detailnya. Lihat juga diskusi ini tentang menyajikan file media .

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

Agar tampilan dapat diakses, Anda harus menentukan url untuk itu. Tidak ada yang istimewa di sini.

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

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

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

Bagian terakhir: templat untuk daftar dan formulir unggahan di bawahnya. Formulir harus memiliki atribut enctype-set ke "multipart / form-data" dan metode set ke "posting" untuk memungkinkan unggahan ke Django. Lihat dokumentasi Upload File untuk detailnya.

FileField memiliki banyak atribut yang dapat digunakan dalam templat. Misalnya {{document.docfile.url}} dan {{document.docfile.name}} seperti pada templat. Lihat lebih lanjut tentang ini di Menggunakan file dalam artikel model dan dokumentasi objek 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. Inisialisasi

Jalankan saja syncdb dan runserver.

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

Hasil

Akhirnya semuanya siap. Pada lingkungan pengembangan Django default, daftar dokumen yang diunggah dapat dilihat di localhost:8000/list/. Hari ini file diunggah ke / path / ke / myproject / media / dokumen / 2011/12/17 / dan dapat dibuka dari daftar.

Saya harap jawaban ini akan membantu seseorang sebanyak itu akan membantu saya.

Akseli Palén
sumber
9
Menemukan lokasi di django docs yang menunjukkan unggahan file. Contoh dalam jawaban ini sangat bagus, tetapi info dalam django docs akan terus diperbarui dengan rilis baru. docs.djangoproject.com/en/dev/topics/http/file-uploads
TaiwanGrapefruitTea
1
Contoh tidak bekerja untuk Django "1.5". Di HTML {% url list %}menjadi {% url "list" %}.
Matthieu Riegler
4
Terima kasih banyak . Ini benar-benar bekerja untuk saya. Namun, untuk pemirsa yang akan datang, Anda harus memeriksa kode di gitHub untuk kompatibilitas terbaik dengan versi baru Python dan Django. Misalnya, views.py, render_to_response () harus diganti dengan render (request, ...,) untuk menghindari kesalahan CSRF. Bersulang.
Huy Than
1
mungkin melakukan ini tanpa BENTUK?
Roel
1
Bisakah file tersebut menjadi .zip, atau file terkompresi lainnya?
qg_java_17137
75

Secara umum ketika Anda mencoba untuk 'hanya mendapatkan contoh kerja' yang terbaik adalah 'mulai menulis kode'. Tidak ada kode di sini untuk membantu Anda, sehingga membuat menjawab pertanyaan lebih bermanfaat bagi kami.

Jika Anda ingin mengambil file, Anda perlu sesuatu seperti ini di file html di suatu tempat:

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

Itu akan memberi Anda tombol telusuri, tombol unggah untuk memulai tindakan (kirimkan formulir) dan catat enctype sehingga Django tahu untuk memberi Anda request.FILES

Dalam tampilan di suatu tempat Anda dapat mengakses file

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

Ada sejumlah besar informasi dalam dokumen unggahan file

Saya sarankan Anda membaca halaman secara menyeluruh dan mulai menulis kode - kemudian kembali dengan contoh dan susun jejak ketika itu tidak berfungsi.

Henry
sumber
10
Terima kasih Henry. Sebenarnya saya sudah membaca dokumen dan telah menulis beberapa kode tetapi karena dokumen memiliki beberapa celah (misalnya "dari suatu tempat import handle_uploaded_file") dan kode saya cacat, berpikir bahwa akan jauh lebih baik jika saya dapat mulai dari contoh yang berfungsi .
qliq
26
Setuju dengan qliq. Contoh kerja sederhana adalah cara yang paling efisien untuk membuat para pemula bekerja, bukan dokumen
Philip007
11
The enctype="multipart/form-data"apa yang saya butuhkan untuk membuat pekerjaan ini, terima kasih!
john-charles
5
Hanya saja jangan lewatkan {% csrf_token%} dalam tag formulir.
jonincanada
mungkin melakukan ini TANPA BENTUK DARI BENTUK. PY?
Roel
71

Demo

Lihat repo github , bekerja dengan Django 3

Contoh unggah file Django minimal

1. Buat proyek Django

Jalankan startproject ::

$ django-admin.py startproject sample

sekarang folder ( contoh ) dibuat.

2. buat aplikasi

Buat aplikasi ::

$ cd sample
$ python manage.py startapp uploader

Sekarang folder ( uploader) dengan file-file ini dibuat ::

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

3. Perbarui pengaturan.py

Pada sample/settings.pytambahkan 'uploader'ke INSTALLED_APPSdan tambahkan MEDIA_ROOTdan MEDIA_URL, yaitu ::

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

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

4. Perbarui urls.py

di sample/urls.pytambahkan ::

...<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. Perbarui models.py

perbarui 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. Perbarui views.py

perbarui 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. buat template

Buat contoh folder / pengunggah / templat / pengunggah

Buat file upload_form.html yaitu 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. Sinkronkan basis data

Sinkronkan basis data dan runserver ::

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

kunjungi http: // localhost: 8000 /

suhailvs
sumber
2
sempurna kecuali untuk baris terakhir - harus localhost.com:8000/upload > Ini berfungsi untuk Django 1.6 dan Python 3.3.
Steve
5
+1 untuk pola desain aplikasi Django yang dapat digunakan kembali
Marcel
1
Akseli menggunakan FileFieldsementara suhail menggunakan ImageField, bisakah seseorang tolong menjelaskan pilihannya?
dvtan
@ dtgq Saya memperbarui jawaban untuk digunakan FileField. ImageFieldharus untuk hanya mengunggah gambar. pembaruan akan bekerja dengan Django 1.11.
suhailvs
diuji pada Django 2.0 dan bekerja dengan sempurna
diek
29

Saya harus mengatakan saya menemukan dokumentasi di Django membingungkan. Juga untuk contoh paling sederhana mengapa formulir disebutkan? Contoh saya bekerja di views.py adalah: -

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

File html terlihat seperti kode di bawah ini, meskipun contoh ini hanya mengunggah satu file dan kode untuk menyimpan banyak file: -

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

Contoh-contoh ini bukan kode saya, mereka telah memilih dari dua contoh lain yang saya temukan. Saya seorang pemula relatif untuk Django sehingga sangat mungkin saya kehilangan beberapa poin kunci.

jimscafe
sumber
3
+1 karena tidak menggunakan a FileFielddan a model.Form. Untuk pemula (dan untuk tugas-tugas sepele), pemrosesan manual dari file yang diunggah seperti yang ditunjukkan di atas kurang membingungkan.
AneesAhmed777
dest = buka (path, 'wb') saat file menulis dengan byte
Bipul Roy
20

Saya juga punya persyaratan serupa. Sebagian besar contoh di internet meminta untuk membuat model dan membuat formulir yang tidak ingin saya gunakan. Ini kode terakhir saya.

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

Dan dalam HTML untuk mengunggah saya menulis:

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

Berikut ini adalah HTML yang menampilkan konten file:

{% block content %}
    <h3>File uploaded successfully</h3>
    {{file.name}}
    </br>content = {{contentOfFile}}
{% endblock %}
chetan pawar
sumber
bagus karena kadang-kadang seseorang hanya ingin menggunakan isi file tidak menyimpan unggahan ...
nemesisfixx
17

Memperluas pada contoh 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

Anda dapat memanggil handle_uploaded_filefungsi ini dari tampilan Anda dengan objek file yang diunggah. Ini akan menyimpan file dengan nama unik (diawali dengan nama file dari file yang diunggah asli) dalam sistem file dan mengembalikan path lengkap file yang disimpan. Anda dapat menyimpan path dalam database, dan melakukan sesuatu dengan file nanti.

Imran
sumber
Imran, saya mencoba kode Anda pada pandangan saya tetapi mendapat kesalahan ini: objek 'WSGIRequest' tidak memiliki atribut 'nama'.
qliq
2
Lewati objek file yang diunggah ( request.FILES['myfile']) ke handle_uploaded_file, bukan objeknya requestsendiri.
Imran
Bisakah saya menyimpannya langsung ke database? stackoverflow.com/questions/24705246/…
AlexandruC
Dengan menggunakannya prefix=source.namemenambahkan karakter tambahan di akhir file, mengacaukan ekstensi file. Misalnya upload.csvdiubah menjadi upload.csv5334. Mengubahnya untuk suffix=source.namememperbaikinya untuk saya.
Tahreem Iqbal
13

Di sini dapat membantu Anda: membuat bidang file di models.py Anda

Untuk mengunggah file (di admin.py Anda):

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)

dan gunakan bidang itu di templat Anda juga.

Vijesh Venugopal
sumber
1
Ini berguna, ketika Anda harus secara manual marah dengan file yang ingin Anda simpan. Jika demikian, Anda mungkin juga memerlukan bagian ini: docs.djangoproject.com/en/dev/topics/files/#the-file-object
kecske
11

Anda dapat merujuk ke contoh server di Pengunggah Baik, yang memiliki versi Django. https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader

Ini sangat elegan dan yang paling penting dari semuanya, ia menyediakan fitur js lib. Template tidak termasuk dalam contoh server, tetapi Anda dapat menemukan demo di situs webnya. Pengunggah Baik: http://fineuploader.com/demos.html

django-fine-uploader

views.py

UploadView mengirimkan kiriman dan menghapus permintaan ke masing-masing penangan.

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

Tidak yakin apakah ada kelemahan pada pendekatan ini tetapi bahkan lebih minimal, di views.py:

entry = form.save()

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

Saya menghadapi masalah yang sama, dan diselesaikan oleh situs admin 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)
hlpmee
sumber
[masukkan uraian tautan di sini] [1] [masukkan uraian tautan di sini] [2] [1]: youtu.be/0tNZB3dyopY [2]: youtu.be/klhMYMc3PlY
uda123