Como fazer upload de um arquivo no Django? [fechadas]

668

Como iniciante no Django, estou tendo dificuldades para criar um aplicativo de upload no Django 1.3. Não foi possível encontrar nenhum exemplo / snippets atualizados. Alguém pode postar um código de exemplo mínimo, mas completo (modelo, exibição, modelo) para fazer isso?

qliq
fonte

Respostas:

1273

Ufa, a documentação do Django realmente não tem um bom exemplo disso. Passei mais de 2 horas para desenterrar todas as peças para entender como isso funciona. Com esse conhecimento, implementei um projeto que possibilita o upload de arquivos e os mostra como lista. Para baixar a fonte do projeto, visite https://github.com/axelpale/minimal-django-file-upload-example ou clone-o:

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

Atualização 2013-01-30: A fonte no GitHub também tem implementação para o Django 1.4, além da 1.3. Embora haja poucas alterações, o tutorial a seguir também é útil para o 1.4.

Atualização 2013-05-10: Implementação para o Django 1.5 no GitHub. Pequenas alterações no redirecionamento em urls.py e uso da tag de modelo de URL em list.html. Obrigado a hubert3 pelo esforço.

Atualização 07/12/2013: Django 1.6 suportado no GitHub. Uma importação foi alterada em myapp / urls.py. Agradecimentos vão para Arthedian .

Atualização 17-03-2015: Django 1.7 suportado no GitHub, graças a aronysidoro .

Atualização 2015-09-04: Django 1.8 suportado no GitHub, graças ao nerogit .

Atualização 2016-07-03: Django 1.9 suportado no GitHub, graças a daavve e nerogit

Árvore do projeto

Um projeto básico do Django 1.3 com aplicativo único e mídia / diretório para uploads.

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. Configurações: myproject / settings.py

Para fazer upload e servir arquivos, você precisa especificar onde o Django armazena os arquivos enviados e de qual URL o Django os serve. MEDIA_ROOT e MEDIA_URL estão em settings.py por padrão, mas estão vazios. Veja as primeiras linhas no Django Managing Files para detalhes. Lembre-se também de definir o banco de dados e adicionar myapp para 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. Modelo: myproject / myapp / models.py

Em seguida, você precisa de um modelo com um FileField. Este campo específico armazena arquivos, por exemplo, em mídia / documentos / 2011/12/24 / com base na data atual e MEDIA_ROOT. Consulte a referência FileField .

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

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

3. Formulário: myproject / myapp / forms.py

Para lidar bem com o upload, você precisa de um formulário. Este formulário possui apenas um campo, mas isso é suficiente. Consulte Referência do Form FileField para obter detalhes.

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

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

4. Visualização: myproject / myapp / views.py

Uma visão em que toda a mágica acontece. Preste atenção em como request.FILESsão tratados. Para mim, foi realmente difícil identificar o fato de que request.FILES['docfile']pode ser salvo nos modelos. O save () do modelo lida com o armazenamento do arquivo no sistema de arquivos automaticamente.

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

O Django não serve MEDIA_ROOT por padrão. Isso seria perigoso no ambiente de produção. Mas no estágio de desenvolvimento, poderíamos interromper. Preste atenção na última linha. Essa linha permite que o Django sirva arquivos de MEDIA_URL. Isso funciona apenas no estágio de desenvolvimento.

Consulte a referência django.conf.urls.static.static para obter detalhes. Consulte também esta discussão sobre a veiculação de arquivos de mídia .

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

Para tornar a visualização acessível, você deve especificar URLs para ela. Nada de especial aqui.

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

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

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

A última parte: modelo para a lista e o formulário de upload abaixo dela. O formulário deve ter o atributo enctype definido como "multipart / form-data" e o método definido como "post" para tornar possível o upload no Django. Consulte a documentação Upload de arquivos para obter detalhes.

O FileField possui muitos atributos que podem ser usados ​​em modelos. Por exemplo, {{document.docfile.url}} e {{document.docfile.name}} como no modelo. Veja mais sobre isso no artigo Usando arquivos nos modelos e na documentação do objeto Arquivo .

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

Basta executar syncdb e runserver.

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

Resultados

Finalmente, está tudo pronto. No ambiente de desenvolvimento padrão do Django, a lista de documentos enviados pode ser vista emlocalhost:8000/list/ . Hoje, os arquivos são enviados para / path / to / myproject / media / documents / 2011/12/17 / e podem ser abertos a partir da lista.

Espero que esta resposta ajude alguém tanto quanto teria me ajudado.

Akseli Palén
fonte
9
Encontrou o local nos documentos do django que mostra os uploads de arquivos. O exemplo nesta resposta é excelente, mas as informações nos documentos do django serão atualizadas com os novos lançamentos. docs.djangoproject.com/en/dev/topics/http/file-uploads
TaiwanGrapefruitTea
1
O exemplo não funciona para o Django "1.5". No HTML {% url list %}se torna {% url "list" %}.
Matthieu Riegler
4
Muito obrigado . Isso realmente funciona para mim. No entanto, para os próximos visualizadores, você deve verificar o código no gitHub para obter a melhor compatibilidade com as novas versões do Python e Django. Por exemplo, o views.py, render_to_response () deve ser substituído por render (request, ...,) para evitar o erro do CSRF. Felicidades.
Huy Than
1
é possível fazer isso sem o FORMS?
Roel
1
O arquivo pode ser .zip ou outros arquivos compactados?
qg_java_17137
75

De um modo geral, quando você está tentando "apenas obter um exemplo prático", é melhor "apenas começar a escrever o código". Não existe um código aqui para ajudá-lo, portanto, responder à pergunta é muito mais útil para nós.

Se você deseja pegar um arquivo, precisa de algo assim em um arquivo html em algum lugar:

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

Isso fornecerá o botão de navegação, um botão de upload para iniciar a ação (envie o formulário) e observe o enctype para que o Django saiba dar a você request.FILES

Em uma exibição em algum lugar, você pode acessar o arquivo com

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

Há uma enorme quantidade de informações nos documentos de upload de arquivos

Eu recomendo que você leia a página completamente e apenas comece a escrever o código - depois volte com exemplos e empilhe rastreamentos quando não funcionar.

Henry
fonte
10
Obrigado Henry. Na verdade, eu li os documentos e escrevi algum código, mas como os documentos têm algumas lacunas (por exemplo, "de algum lugar import handle_uploaded_file") e meu código foi defeituoso, pensei que seria muito melhor se eu pudesse começar com um exemplo de trabalho .
Qlq
26
Concorde com qliq. Um exemplo simples de trabalho é a forma mais eficiente de se iniciantes indo, não docs
Philip007
11
O enctype="multipart/form-data"que eu precisava para fazer isso funcionar, obrigado!
john-charles
5
Apenas não perca o {% csrf_token%} nas tags do formulário.
Jonincanada
é possível fazer isso SEM FORMS FROM FORMS.PY?
Roel
71

Demo

Veja o repositório do github , trabalha com o Django 3

Um exemplo mínimo de upload de arquivo Django

1. Crie um projeto django

Execute o startproject ::

$ django-admin.py startproject sample

agora uma pasta ( amostra ) é criada.

2. crie um aplicativo

Crie um aplicativo ::

$ cd sample
$ python manage.py startapp uploader

Agora uma pasta ( uploader) com esses arquivos é criada:

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

3. Atualize settings.py

Em sample/settings.pyadicionar 'uploader'a INSTALLED_APPSe adicionar MEDIA_ROOTe MEDIA_URL, ou seja:

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

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

4. Atualize urls.py

em 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. Atualize 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. Atualize 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. criar modelos

Crie uma pasta sample / uploader / templates / uploader

Crie um arquivo upload_form.html 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. Sincronize o banco de dados

Sincronizar banco de dados e servidor de execução ::

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

visite http: // localhost: 8000 /

suhailvs
fonte
2
perfeito, exceto pela última linha - deve ser localhost.com:8000/upload > Isso funcionou no django 1.6 e no Python 3.3.
10134 Steve Steve
5
+1 para o padrão de design reutilizável de aplicativos django
Marcel
1
Akseli usou um FileFieldtempo suhail usou um ImageField, alguém poderia por favor explicar as escolhas?
dvtan
@dtgq Atualizei a resposta para usar FileField. ImageFielddeve apenas para upload de imagem. a atualização funcionará com o Django 1.11.
suhailvs
testado em Django 2.0 e funcionou perfeitamente
Diek
29

Devo dizer que acho a documentação no django confusa. Também para o exemplo mais simples, por que os formulários estão sendo mencionados? O exemplo que eu trabalhei no 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()

O arquivo html se parece com o código abaixo, embora este exemplo faça upload apenas de um arquivo e o código para salvar os arquivos lide com muitos: -

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

Esses exemplos não são meu código, eles foram obtidos de outros dois exemplos que encontrei. Eu sou um iniciante em relação ao django, por isso é muito provável que esteja perdendo algum ponto-chave.

jimscafe
fonte
3
+1 por não usar ae FileFielda model.Form. Para iniciantes (e para tarefas triviais), o processamento manual dos arquivos enviados, como mostrado acima, é menos confuso.
precisa saber é o seguinte
dest = aberto (caminho, 'wb') quando o arquivo é
gravado
20

Eu também tive o requisito semelhante. A maioria dos exemplos na net está pedindo para criar modelos e criar formulários que eu não queria usar. Aqui está o meu código final.

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

E em HTML para enviar escrevi:

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

A seguir está o HTML que exibe o conteúdo do arquivo:

{% block content %}
    <h3>File uploaded successfully</h3>
    {{file.name}}
    </br>content = {{contentOfFile}}
{% endblock %}
chetan pawar
fonte
bom porque às vezes alguém só quer usar o conteúdo do arquivo para não salvar o upload ...
nemesisfixx
17

Estendendo o exemplo de 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

Você pode chamar essa handle_uploaded_filefunção da sua visualização com o objeto de arquivo carregado. Isso salvará o arquivo com um nome exclusivo (prefixado com o nome do arquivo do arquivo original carregado) no sistema de arquivos e retornará o caminho completo do arquivo salvo. Você pode salvar o caminho no banco de dados e fazer algo com o arquivo posteriormente.

Imran
fonte
Imran, tentei o seu código na minha opinião, mas recebi o seguinte erro: O objeto 'WSGIRequest' não tem atributo 'nome'.
Qlq
2
Passe o objeto de arquivo carregado ( request.FILES['myfile']) para handle_uploaded_file, não o requestpróprio.
Imran
Posso salvá-lo diretamente no banco de dados? stackoverflow.com/questions/24705246/...
AlexandruC
Ao usá- prefix=source.namelo, adicionou caracteres extras no final do arquivo, atrapalhando a extensão do arquivo. Por exemplo, upload.csvfoi alterado para upload.csv5334. Alterá-lo para suffix=source.namecorrigi-lo para mim.
Tahreem Iqbal 15/08/16
13

Aqui pode ajudar você a: criar um campo de arquivo em seus models.py

Para fazer upload do arquivo (em seu 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 use esse campo no seu modelo também.

Vijesh Venugopal
fonte
1
Isso é útil quando você precisa modificar manualmente os arquivos que deseja salvar. Se assim for, você também pode precisar desta seção: docs.djangoproject.com/en/dev/topics/files/#the-file-object
kecske
11

Você pode consultar exemplos de servidor no Fine Uploader, que possui a versão do django. https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader

É muito elegante e o mais importante de tudo, fornece o js lib em destaque. O modelo não está incluído nos exemplos de servidor, mas você pode encontrar uma demonstração em seu site. Fine Uploader: http://fineuploader.com/demos.html

django-fine-uploader

views.py

O UploadView envia a solicitação de postagem e exclusão para os respectivos manipuladores.

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

Não tenho certeza se há alguma desvantagem nessa abordagem, mas ainda mais mínima, no views.py:

entry = form.save()

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

Eu enfrentei o problema semelhante e resolvi pelo site de administração do 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
fonte
[inserir descrição do link aqui] [1] [inserir descrição do link aqui] [2] [1]: youtu.be/0tNZB3dyopY [2]: youtu.be/klhMYMc3PlY
uda123