Django'da dosya nasıl yüklenir? [kapalı]


668

Django için bir acemi olarak, Django 1.3 bir yükleme uygulaması yapmakta zorluk yaşıyorum. Güncel bir örnek / snippet bulamadım. Birisi bunu yapmak için minimal ancak eksiksiz (Model, Görünüm, Şablon) örnek kod yayınlayabilir mi?

Yanıtlar:


1273

Vay be, Django belgelerinde bu konuda gerçekten iyi bir örnek yok. Bunun nasıl çalıştığını anlamak için tüm parçaları kazmak için 2 saatten fazla harcadım. Bu bilgi ile dosyaları yüklemeyi ve liste halinde göstermeyi mümkün kılan bir proje uyguladım. Proje kaynağını indirmek için https://github.com/axelpale/minimal-django-file-upload-example adresini ziyaret edin veya kopyalayın:

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

2013-01-30 Güncellemesi: GitHub'daki kaynak 1.3'e ek olarak Django 1.4 için de uygulandı. Birkaç değişiklik olmasına rağmen, aşağıdaki öğretici 1.4 için de yararlıdır.

2013-05-10 Güncellemesi: GitHub'da Django 1.5 uygulaması. Urls.py dosyasında yeniden yönlendirmede küçük değişiklikler ve list.html dosyasında url şablon etiketinin kullanımı. Bu çaba için hubert3'e teşekkürler .

Güncelleme 2013-12-07: GitHub'da Django 1.6 destekleniyor. Bir içe aktarma işlemi myapp / urls.py olarak değiştirildi. Arthedian'a teşekkürler .

2015-03-17 Güncellemesi: Drongo 1.7, aronysidoro sayesinde GitHub'da desteklendi .

2015-09-04 Güncellemesi: Nerogit sayesinde Django 1.8 GitHub'da desteklendi .

Güncelleme 2016-07-03: Daavve ve Nerogit sayesinde GitHub'da Django 1.9 destekleniyor

Proje ağacı

Yüklemeler için tek bir uygulama ve medya / dizin ile temel bir Django 1.3 projesi.

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. Ayarlar: projem / settings.py

Dosyaları yüklemek ve sunmak için, Django'nun yüklenen dosyaları nerede depoladığını ve Django'nun hangi URL'den sunduğunu belirtmeniz gerekir. MEDIA_ROOT ve MEDIA_URL varsayılan olarak settings.py'de bulunur, ancak boştur. Ayrıntılar için Django Dosyaları Yönetme'deki ilk satırlara bakın. Veritabanını ayarlamayı ve INSTALLED_APPS'e myapp eklemeyi de unutmayın

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

Sonra FileField ile bir modele ihtiyacınız var. Bu özel alan, dosyaları geçerli tarihe ve MEDIA_ROOT'a göre medya / belgeler / 2011/12/24 / şeklinde depolar. Bkz. FileField başvurusu .

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

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

3. Form: projem / myapp / forms.py

Yüklemeyi iyi işlemek için bir forma ihtiyacınız var. Bu formun sadece bir alanı vardır, ancak bu yeterlidir. Ayrıntılar için Form FileField başvurusuna bakın.

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

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

4. Görünüm: projem / myapp / views.py

Tüm büyünün gerçekleştiği bir görünüm. Nasıl request.FILESele alındığına dikkat edin . Benim için, request.FILES['docfile']modellere kaydedilebilecek gerçeği tespit etmek gerçekten zordu . FileField aynen böyle. Modelin save () yöntemi, dosyanın dosya sistemine otomatik olarak depolanmasını sağlar.

# -*- 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. Proje URL'leri: projem / urls.py

Django varsayılan olarak MEDIA_ROOT hizmetini sunmaz. Bu üretim ortamında tehlikeli olabilir. Ancak geliştirme aşamasında, kısa kesebiliriz. Son satıra dikkat edin. Bu satır, Django'nun MEDIA_URL dosyalarından dosya sunmasını sağlar. Bu sadece geliştirme aşamasında çalışır.

Ayrıntılar için django.conf.urls.static.static referansına bakın. Medya dosyalarının sunulmasıyla ilgili bu tartışmaya da bakın .

# -*- 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. Uygulama URL'leri: projem / myapp / urls.py

Görünümü erişilebilir hale getirmek için görünümün URL'lerini belirtmeniz gerekir. Burada özel bir şey yok.

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

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

7. Şablon: projem / myapp / şablonlar / myapp / list.html

Son bölüm: liste şablonu ve altındaki yükleme formu. Django'ya yüklenmeyi mümkün kılmak için, formun "multipart / form-data" olarak ayarlanmış enctype-özniteliği ve "post" olarak ayarlanmış yöntemi olmalıdır. Ayrıntılar için Dosya Yüklemeleri dokümanına bakın.

FileField, şablonlarda kullanılabilecek birçok özelliğe sahiptir. Şablondaki gibi {{document.docfile.url}} ve {{document.docfile.name}}. Bunlarla ilgili daha fazla bilgiyi Modellerde dosya kullanma makalesi ve Dosya nesnesi belgeleri bölümüne bakın .

<!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. Başlat

Sadece syncdb ve runserver'ı çalıştırın.

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

Sonuçlar

Sonunda her şey hazır. Varsayılan olarak Django geliştirme ortamında yüklenen belgelerin listesi adresinde görülebilir localhost:8000/list/. Bugün dosyalar / path / dizinine / projem / medya / belgeler / 2011/12/17 / dizinine yüklenir ve listeden açılabilir.

Umarım bu cevap birisinin bana yardım ettiği kadar yardımcı olacaktır.


9
Dosya yüklemelerini gösteren django dokümanlarında yer bulundu. Bu cevaptaki örnek mükemmel, ancak django belgelerindeki bilgiler yeni sürümlerle güncel tutulacak. docs.djangoproject.com/tr/dev/topics/http/file-uploads
TayvanGrapefruitTea 29:12

1
Örnek Django "1.5" için geçerli değildir. HTML'de {% url list %}olur {% url "list" %}.
Matthieu Riegler

4
Çok teşekkür ederim . Gerçekten benim için çalışıyor. Ancak, yaklaşan izleyiciler için Python ve Django'nun yeni sürümleriyle en iyi uyumluluk için gitHub'daki kodu kontrol etmelisiniz. Örneğin, CSRF hatasını önlemek için views.py, render_to_response () ile render (istek, ...,) kullanılmalıdır. Şerefe.
Huy Than

1
FORMS olmadan bunu yapmak mümkün mü?
Roel

1
Dosya .zip veya diğer sıkıştırılmış dosyalar olabilir mi?
qg_java_17137

75

Genel olarak, 'sadece çalışan bir örnek almaya' çalışırken, 'sadece kod yazmaya başlamak' en iyisidir. Burada size yardımcı olacak bir kod yok, bu yüzden soruyu cevaplamak bizim için çok daha işe yarar.

Bir dosyayı almak istiyorsanız, bir yerde bir html dosyasında böyle bir şeye ihtiyacınız vardır:

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

Bu size göz at düğmesi, eylemi başlatmak için bir yükleme düğmesi (formu gönderin) ve Django'nun size vermeyi bilmesi için şifreyi not eder. request.FILES

Bir yerde bir görünümde dosyaya

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

Dosya yükleme belgelerinde çok miktarda bilgi var

Sayfayı iyice okumanızı ve sadece kod yazmaya başlamanızı öneririm - sonra çalışmazken örnekler ve yığın izleri ile geri dönün.


10
Teşekkürler Henry. Aslında belgeleri okudum ve bazı kodlar yazdım, ancak dokümanlar bazı boşluklar (örneğin "bir yerden import handle_uploaded_file") olduğundan ve kodum hatalıydı, çalışan bir örnekten başlayabilirsem çok daha iyi olacağını düşündüm .
qliq

26
Qliq ile aynı fikirde. Basit bir çalışma örneği, yeni başlayanlara dokümanlar değil, gitmenin en etkili yoludur
Philip007

11
enctype="multipart/form-data"Ben, bu işi yapmak için teşekkür gerekeni!
john-charles

5
Form etiketlerindeki {% csrf_token%} ifadesini kaçırmayın.
jonincanada

bunu FORMS.PY'DEN FORMLAR OLMADAN mümkün mü?
Roel

71

gösteri

Github deposunu görün, Django 3 ile çalışır

Minimal bir Django dosyası yükleme örneği

1. Bir django projesi oluşturun

Startproject'i çalıştırın ::

$ django-admin.py startproject sample

şimdi bir klasör ( örnek ) oluşturulur.

2. bir uygulama oluşturun

Bir uygulama oluşturun ::

$ cd sample
$ python manage.py startapp uploader

Şimdi uploaderbu dosyaları içeren bir klasör ( ) oluşturulur ::

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

3. settings.py dosyasını güncelleyin

On sample/settings.pyeklenti 'uploader'için INSTALLED_APPSve eklemek MEDIA_ROOTve MEDIA_URL, yani ::

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

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

4. urls.py dosyasını güncelleyin

içinde sample/urls.pyeklenti ::

...<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. Modelleri güncelleyin .py

güncelleme 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. views.py dosyasını güncelleyin

güncelleme 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. şablon oluşturma

Bir klasör örneği / yükleyici / şablonlar / yükleyici oluşturma

Upload_form.html dosyası oluşturun ie 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. Veritabanını senkronize etme

Veritabanını ve runserver'ı senkronize et ::

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

ziyaret http: // localhost: 8000 /


2
son satır hariç mükemmel - localhost.com olmalıdır: 8000/upload > Bu django 1.6 ve Python 3.3 için çalıştı.
Steve

5
Yeniden kullanılabilir django uygulama tasarım deseni için +1
Marcel

1
Akseli bir FileFieldsüre suhail kullandı ImageField, birisi seçenekleri açıklayabilir mi?
dvtan

@dtgq Kullanılacak yanıtı güncelledim FileField. ImageFieldyalnızca resim yüklemek için gerekir. güncelleme Django 1.11 ile çalışacaktır.
suhailvs

Django 2.0 üzerinde test edildi ve mükemmel çalıştı
diek

29

Django'da kafa karıştırıcı belgeleri bulduğumu söylemeliyim. Ayrıca en basit örnek için formlardan neden bahsediliyor? Ben views.py çalışmak zorunda örnek: -

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

Html dosyası aşağıdaki koda benziyor, ancak bu örnek yalnızca bir dosya yükler ve dosyaları kaydetmek için kod çok işlenir: -

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

Bu örnekler benim kodum değil, bulduğum diğer iki örnekten elde edildi. Ben django göreceli bir acemiyim, bu yüzden bazı önemli noktaları kaçırıyorum.


3
A FileFieldve a kullanmadığınız için +1 model.Form. Yeni başlayanlar (ve önemsiz görevler için), yukarıda gösterildiği gibi yüklenen dosyaların manuel olarak işlenmesi daha az kafa karıştırıcıdır.
AneesAhmed777

dest = open (yol, 'wb') bayt ile dosya yazarken
Bipul Roy

20

Ben de benzer bir gereksinimim vardı. Net'teki örneklerin çoğu, kullanmak istemediğim modeller ve formlar oluşturmayı istiyor. İşte son kodum.

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

Ve yüklemek için HTML'de yazdım:

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

Dosyanın içeriğini gösteren HTML aşağıdadır:

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

iyi çünkü bazen sadece yükleme içeriğini kaydetmez dosyanın içeriğini kullanmak istiyor ...
nemesisfixx

17

Henry örneğini genişletmek :

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

handle_uploaded_fileYüklenen dosya nesnesiyle görünümünüzden bu işlevi çağırabilirsiniz . Bu, dosyayı benzersiz bir adla (yüklenen orijinal dosyanın dosya adıyla ön ekli) dosya sistemine kaydeder ve kaydedilen dosyanın tam yolunu döndürür. Yolu veritabanına kaydedebilir ve daha sonra dosyayla bir şeyler yapabilirsiniz.


Imran, kodumu benim görünümümde denedim ama şu hatayı aldım: 'WSGIRequest' nesnesinin 'name' özelliği yok.
qliq

2
Yüklenen dosya nesnesini ( request.FILES['myfile']) kendisine handle_uploaded_filedeğil, requestiletin.
İmran

Doğrudan veritabanına kaydedebilir miyim? stackoverflow.com/questions/24705246/…
AlexandruC

Bunu kullanarak prefix=source.namedosya sonuna ekstra karakterler ekleyerek dosya uzantısıyla uğraşmak. Örneğin upload.csvdeğiştirildi var upload.csv5334. Bunu benim için suffix=source.namedüzeltmek için değiştirmek .
Tahreem Iqbal

13

Burada size yardımcı olabilir: models.py'nizde bir dosya alanı oluşturun

Dosyayı yüklemek için (admin.py dosyasında):

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)

ve bu alanı şablonunuzda da kullanabilirsiniz.


1
Bu, kaydetmek istediğiniz dosyalarla manuel olarak temperleme yapmanız gerektiğinde kullanışlıdır. Öyleyse, bu bölüme de ihtiyacınız olabilir: docs.djangoproject.com/en/dev/topics/files/#the-file-object
kecske

11

Django sürümü olan Fine Uploader'daki sunucu örneklerine başvurabilirsiniz. https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader

Çok zarif ve en önemlisi, özellikli js lib sağlar. Şablon sunucu örneklerine dahil edilmemiştir, ancak web sitesinde demo bulabilirsiniz. İnce Yükleyici: http://fineuploader.com/demos.html

django-ince yükleyici

views.py

UploadView ilgili işleyicilere gönderi ve silme isteği gönderir.

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

Bu yaklaşımın herhangi bir dezavantajı olup olmadığından emin değilim, ancak daha az, views.py'de:

entry = form.save()

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

0

Benzer bir sorunla karşılaştım ve django yönetici sitesi tarafından çözüldüm.

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

[bağlantı açıklamasını buraya girin] [1] [bağlantı açıklamasını buraya girin] [2] [1]: youtu.be/0tNZB3dyopY [2]: youtu.be/klhMYMc3PlY
uda123 12:19
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.