¿Cómo subir un archivo en Django? [cerrado]

668

Como novato en Django, tengo dificultades para hacer una aplicación de carga en Django 1.3. No pude encontrar ningún ejemplo / fragmento actualizado. ¿Alguien puede publicar un código de ejemplo mínimo pero completo (Modelo, Vista, Plantilla) para hacerlo?

qliq
fuente

Respuestas:

1273

Uf, la documentación de Django realmente no tiene un buen ejemplo al respecto. Pasé más de 2 horas para desenterrar todas las piezas para entender cómo funciona esto. Con ese conocimiento, implementé un proyecto que hace posible cargar archivos y mostrarlos como una lista. Para descargar el código fuente del proyecto, visite https://github.com/axelpale/minimal-django-file-upload-example o clónelo:

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

Actualización 2013-01-30: La fuente en GitHub también tiene implementación para Django 1.4 además de 1.3. Aunque hay pocos cambios, el siguiente tutorial también es útil para 1.4.

Actualización 2013-05-10: Implementación para Django 1.5 en GitHub. Cambios menores en la redirección en urls.py y el uso de la etiqueta de plantilla de url en list.html. Gracias a Hubert3 por el esfuerzo.

Actualización 2013-12-07: Django 1.6 compatible en GitHub. Una importación cambió en myapp / urls.py. Gracias a Arthedian .

Actualización 2015-03-17: Django 1.7 compatible con GitHub, gracias a aronysidoro .

Actualización 2015-09-04: Django 1.8 compatible con GitHub, gracias a nerogit .

Actualización 2016-07-03: Django 1.9 compatible con GitHub, gracias a daavve y nerogit

Árbol del proyecto

Un proyecto básico de Django 1.3 con una sola aplicación y directorio media / para cargas.

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. Configuración: myproject / settings.py

Para cargar y servir archivos, debe especificar dónde almacena Django los archivos cargados y desde qué URL Django los sirve. MEDIA_ROOT y MEDIA_URL están en settings.py de forma predeterminada pero están vacías. Vea las primeras líneas en Django Managing Files para más detalles. Recuerde también configurar la base de datos y agregar 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. Modelo: myproject / myapp / models.py

A continuación, necesita un modelo con un FileField. Este campo particular almacena archivos, por ejemplo, en medios / documentos / 2011/12/24 / según la fecha actual y MEDIA_ROOT. Consulte la referencia de FileField .

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

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

3. Formulario: myproject / myapp / forms.py

Para manejar bien la carga, necesita un formulario. Este formulario tiene solo un campo, pero eso es suficiente. Consulte la referencia del formulario FileField para obtener más detalles.

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

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

4. Vista: myproject / myapp / views.py

Una vista donde sucede toda la magia. Presta atención como request.FILESse manejan. Para mí, fue realmente difícil detectar el hecho de que request.FILES['docfile']se puede guardar en modelos. FileField así como así. Save () del modelo maneja el almacenamiento del archivo en el sistema de archivos automáticamente.

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

Django no sirve MEDIA_ROOT de forma predeterminada. Eso sería peligroso en el entorno de producción. Pero en la etapa de desarrollo, podríamos acortarnos. Presta atención a la última línea. Esa línea permite que Django sirva archivos de MEDIA_URL. Esto funciona solo en la etapa de desarrollo.

Consulte la referencia de django.conf.urls.static.static para obtener más detalles. Consulte también esta discusión sobre la publicación de archivos multimedia .

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

Para que la vista sea accesible, debe especificar sus URL. Nada especial aquí.

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

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

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

La última parte: plantilla para la lista y el formulario de carga debajo de ella. El formulario debe tener el atributo enctype establecido en "multipart / form-data" y el método establecido en "post" para hacer posible la carga en Django. Consulte la documentación de Carga de archivos para más detalles.

FileField tiene muchos atributos que se pueden usar en plantillas. Por ejemplo, {{document.docfile.url}} y {{document.docfile.name}} como en la plantilla. Vea más sobre esto en el artículo Uso de archivos en modelos y en la documentación del objeto El archivo .

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

Simplemente ejecute syncdb y runserver.

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

Resultados

Finalmente, todo está listo. En el entorno de desarrollo predeterminado de Django, se puede ver la lista de documentos cargados en localhost:8000/list/. Hoy los archivos se cargan en / path / to / myproject / media / documents / 2011/12/17 / y se pueden abrir desde la lista.

Espero que esta respuesta ayude a alguien tanto como me hubiera ayudado.

Akseli Palén
fuente
99
Encontró la ubicación en django docs que muestra la carga de archivos. El ejemplo en esta respuesta es excelente, pero la información en los documentos de django se mantendrá actualizada con nuevos lanzamientos. docs.djangoproject.com/en/dev/topics/http/file-uploads
TaiwanGrapefruitTea
1
El ejemplo no funciona para Django "1.5". En el HTML se {% url list %}convierte {% url "list" %}.
Matthieu Riegler
44
Muchas gracias . Realmente funciona para mi. Sin embargo, para los próximos espectadores, debe verificar el código en gitHub para obtener la mejor compatibilidad con las nuevas versiones de Python y Django. Por ejemplo, el archivo views.py, render_to_response () debe reemplazarse con render (solicitud, ...,) para evitar el error CSRF. Salud.
Huy Than
1
¿Es posible hacer esto sin FORMULARIOS?
Roel
1
¿El archivo puede ser .zip u otros archivos comprimidos?
qg_java_17137
74

En términos generales, cuando está tratando de "obtener un ejemplo de trabajo", es mejor "comenzar a escribir código". No hay un código aquí para ayudarlo, por lo que hacer que responder la pregunta sea mucho más útil para nosotros.

Si desea obtener un archivo, necesita algo como esto en un archivo html en algún lugar:

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

Eso le dará el botón de exploración, un botón de carga para iniciar la acción (enviar el formulario) y anotar el enctype para que Django sepa darle request.FILES

En una vista en algún lugar, puede acceder al archivo con

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

Hay una gran cantidad de información en los documentos de carga de archivos

Le recomiendo que lea la página a fondo y simplemente comience a escribir código , luego regrese con ejemplos y seguimientos de pila cuando no funcione.

Enrique
fuente
10
Gracias Henry En realidad, he leído los documentos y he escrito algo de código, pero dado que los documentos tienen algunos vacíos (por ejemplo, "desde algún lugar import handle_uploaded_file") y mi código tenía fallas, pensé que sería mucho mejor si pudiera comenzar con un ejemplo de trabajo. .
qliq
26
De acuerdo con qliq. Un ejemplo de trabajo simple es la forma más eficiente de poner en marcha a los novatos, no a los documentos
Philip007
11
Lo enctype="multipart/form-data"que necesitaba para que esto funcionara, ¡gracias!
john-charles
55
Simplemente no se pierda el {% csrf_token%} dentro de las etiquetas del formulario.
jonincanada
es posible hacer esto SIN FORMULARIOS DE FORMULARIOS.PY?
Roel
71

Manifestación

Vea el repositorio de github , funciona con Django 3

Un ejemplo mínimo de carga de archivos Django

1. Crear un proyecto django

Ejecute startproject ::

$ django-admin.py startproject sample

ahora una carpeta ( se crea muestra ).

2. crear una aplicación

Crea una aplicación ::

$ cd sample
$ python manage.py startapp uploader

Ahora uploaderse crea una carpeta ( ) con estos archivos ::

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

3. Actualiza settings.py

En sample/settings.pyagregar 'uploader'a INSTALLED_APPSy agregar MEDIA_ROOTy MEDIA_URL, es decir:

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

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

4. Actualiza urls.py

en sample/urls.pyagregar ::

...<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. Actualizar modelos.py

actualización 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. Actualiza views.py

actualización 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. crear plantillas

Crear una carpeta de muestra / cargador / plantillas / cargador

Cree un archivo upload_form.html, es decir 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. Sincronizar base de datos

Sincronice la base de datos y el servidor de ejecución ::

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

visite http: // localhost: 8000 /

suhailvs
fuente
2
perfecto, excepto por la última línea, debe ser localhost.com:8000/upload > Esto funcionó para django 1.6 y Python 3.3.
Steve
55
+1 para el patrón de diseño de la aplicación django reutilizable
Marcel
1
Akseli usó un FileFieldtiempo, suhail usó un ImageField, ¿alguien podría explicar las opciones?
dvtan
@dtgq Actualicé la respuesta para usar con FileField. ImageFielddebe para cargar solo la imagen. la actualización funcionará con Django 1.11.
suhailvs
probado en Django 2.0 y funcionó perfectamente
diek 01 de
29

Debo decir que encuentro la documentación en django confusa. También para el ejemplo más simple, ¿por qué se mencionan los formularios? El ejemplo que puse a trabajar en views.py es: -

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

El archivo html se parece al siguiente código, aunque este ejemplo solo carga un archivo y el código para guardar los archivos maneja muchos:

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

Estos ejemplos no son mi código, se obtuvieron de otros dos ejemplos que encontré. Soy un principiante relativo a django, por lo que es muy probable que me falte algún punto clave.

jimscafe
fuente
3
+1 por no usar ay FileFielda model.Form. Para principiantes (y para tareas triviales), el procesamiento manual de los archivos cargados como se muestra arriba es menos confuso.
AneesAhmed777
dest = open (ruta, 'wb') cuando el archivo se escribe con bytes
Bipul Roy
20

También tuve el requisito similar. La mayoría de los ejemplos en la red piden crear modelos y crear formularios que no quería usar. Aquí está mi 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})

Y en HTML para subir escribí:

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

El siguiente es el HTML que muestra el contenido del archivo:

{% block content %}
    <h3>File uploaded successfully</h3>
    {{file.name}}
    </br>content = {{contentOfFile}}
{% endblock %}
chetan pawar
fuente
bueno porque a veces uno solo quiere usar el contenido del archivo y no guardar la carga ...
nemesisfixx
17

Ampliando el ejemplo 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

Puede llamar a esta handle_uploaded_filefunción desde su vista con el objeto de archivo cargado. Esto guardará el archivo con un nombre único (prefijado con el nombre del archivo original cargado) en el sistema de archivos y devolverá la ruta completa del archivo guardado. Puede guardar la ruta en la base de datos y hacer algo con el archivo más adelante.

Imran
fuente
Imran, probé su código desde mi punto de vista, pero recibí este error: el objeto 'WSGIRequest' no tiene el atributo 'nombre'.
qliq
2
Pase el objeto del archivo cargado ( request.FILES['myfile']) a handle_uploaded_file, no el requestpropio.
Imran
¿Puedo guardarlo directamente en la base de datos? stackoverflow.com/questions/24705246/…
AlexandruC
Al usarlo, prefix=source.namese agregaron caracteres adicionales al final del archivo y se confundió con la extensión del archivo. Por ejemplo, upload.csvse cambió a upload.csv5334. Cambiándolo a suffix=source.namearreglado para mí.
Tahreem Iqbal
13

Aquí puede ayudarte: crea un campo de archivo en tu models.py

Para cargar el archivo (en su 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)

y usa ese campo en tu plantilla también.

Vijesh Venugopal
fuente
1
Esto es útil cuando tiene que moderar manualmente los archivos que desea guardar. Si es así, también puede necesitar esta sección: docs.djangoproject.com/en/dev/topics/files/#the-file-object
kecske
11

Puede consultar ejemplos de servidores en Fine Uploader, que tiene la versión django. https://github.com/FineUploader/server-examples/tree/master/python/django-fine-uploader

Es muy elegante y lo más importante de todo, proporciona js lib destacada. La plantilla no está incluida en los ejemplos de servidores, pero puede encontrar la demostración en su sitio web. Cargador fino: http://fineuploader.com/demos.html

django-fine-uploader

views.py

UploadView despacha la solicitud de publicación y eliminación a los respectivos controladores

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'
            }))

formas.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
fuente
7

No estoy seguro de si hay alguna desventaja en este enfoque, pero aún más mínimo, en views.py:

entry = form.save()

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

Me enfrenté al problema similar y lo resolví con el sitio de administración de 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
fuente
[ingrese la descripción del enlace aquí] [1] [ingrese la descripción del enlace aquí] [2] [1]: youtu.be/0tNZB3dyopY [2]: youtu.be/klhMYMc3PlY
uda123