web-dev-qa-db-fra.com

Besoin d'un exemple minimal de téléchargement de fichier Django

En tant que débutant sur Django, j'ai de la difficulté à créer une application de téléchargement dans Django 1.3. Je n'ai trouvé aucun exemple/extrait mis à jour. Est-ce que quelqu'un peut poster un code d'exemple minimal mais complet (Modèle, Vue, Modèle) pour le faire?

629
qliq

Ouf, la documentation de Django n'a vraiment pas de bon exemple à ce sujet. J'ai passé plus de 2 heures à déterrer toutes les pièces pour comprendre comment cela fonctionne. Fort de cette connaissance, j'ai mis en place un projet permettant de télécharger des fichiers et de les afficher sous forme de liste. Pour télécharger la source du projet, visitez le site https://github.com/axelpale/minimal-Django-file-upload-example ou clonez-le:

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

Mise à jour 2013-01-30: La source de GitHub a également été mise en œuvre pour Django 1.4 en plus de la version 1.3. Même s'il y a peu de changements, le tutoriel suivant est également utile pour la version 1.4.

Mise à jour 2013-05-10: Implémentation de Django 1.5 sur GitHub. Modifications mineures de la redirection dans urls.py et de l'utilisation de la balise de modèle d'URL dans list.html. Merci à hubert pour l'effort.

Mise à jour 2013-12-07: Django 1.6 supporté par GitHub. Une importation a été modifiée dans myapp/urls.py. Merci à Arthedian .

Mise à jour 2015-03-17: Django 1.7 supporté par GitHub, grâce à aronysidoro .

Mise à jour 2015-09-04: Django 1.8 supporté par GitHub, grâce à nerogit .

Mise à jour 2016-07-03: Django 1.9 supporté par GitHub, grâce à daavve et nerogit

Arbre de projet

Un projet Django 1.3 de base avec une seule application et un seul répertoire media/pour les téléchargements.

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. Paramètres: myproject/settings.py

Pour télécharger et servir des fichiers, vous devez spécifier où Django stocke les fichiers téléchargés et à partir de l'URL que Django les sert. MEDIA_ROOT et MEDIA_URL sont dans settings.py par défaut mais ils sont vides. Voir les premières lignes dans Django Managing Files pour plus de détails. N'oubliez pas également de définir la base de données et d'ajouter myapp à 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. Modèle: myproject/myapp/models.py

Ensuite, vous avez besoin d'un modèle avec un FileField. Ce champ particulier stocke des fichiers, par exemple. à media/documents/2011/12/24/en fonction de la date du jour et de MEDIA_ROOT. Voir référence FileField .

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

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

3. Forme: myproject/myapp/forms.py

Pour gérer le téléchargement correctement, vous avez besoin d'un formulaire. Ce formulaire n'a qu'un seul champ mais cela suffit. Voir référence à FileField pour plus de détails.

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

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

4. Voir: myproject/myapp/views.py

Une vue où toute la magie se produit. Faites attention à la façon dont request.FILES est traité. Pour moi, il était vraiment difficile de remarquer le fait que request.FILES['docfile'] peut être enregistré dans models.FileField juste comme ça. Save () du modèle gère automatiquement le stockage du fichier dans le système de fichiers.

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

Django ne sert pas MEDIA_ROOT par défaut. Ce serait dangereux dans un environnement de production. Mais au stade du développement, nous pourrions couper court. Faites attention à la dernière ligne. Cette ligne permet à Django de servir des fichiers à partir de MEDIA_URL. Cela ne fonctionne qu'au stade de développement.

Voir référence Django.conf.urls.static.static pour plus de détails. Voir aussi cette discussion sur le service de fichiers multimédias .

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

Pour rendre la vue accessible, vous devez spécifier les URL correspondant. Rien de spécial ici.

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

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

7. Modèle: myproject/myapp/templates/myapp/list.html

La dernière partie: modèle pour la liste et le formulaire de téléchargement ci-dessous. Enctype-attribut doit être défini sur "multipart/form-data" et la méthode sur "post" pour que le téléchargement sur Django soit possible. Voir documentation sur les téléchargements de fichiers pour plus de détails.

Le champ de fichiers possède de nombreux attributs pouvant être utilisés dans les modèles. Par exemple. {{document.docfile.url}} et {{document.docfile.name}} comme dans le modèle. Plus d'informations à ce sujet dans tilisation de fichiers dans l'article modèles et Documentation d'objet 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. Initialiser

Il suffit de lancer syncdb et le serveur d'exécution.

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

Résultats

Enfin, tout est prêt. Dans l’environnement de développement Django par défaut, la liste des documents téléchargés est visible à localhost:8000/list/. Aujourd'hui, les fichiers sont chargés dans/path/to/myproject/media/documents/2011/12/17/et peuvent être ouverts à partir de la liste.

J'espère que cette réponse aidera quelqu'un autant qu'elle m'aurait aidé.

1241
Akseli Palén

En règle générale, lorsque vous essayez de "prendre exemple sur vous", il est préférable de "commencer à écrire du code". Il n'y a pas de code ici pour vous aider, il est donc plus compliqué de répondre à la question.

Si vous voulez récupérer un fichier, vous avez besoin de quelque chose comme ceci dans un fichier html quelque part:

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

Cela vous donnera le bouton de navigation, un bouton de téléchargement pour lancer l'action (soumettez le formulaire) et notez le type d'enctype afin que Django sache vous donner request.FILES

Dans une vue quelque part, vous pouvez accéder au fichier avec

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

Il y a une énorme quantité d'informations dans le documents de téléchargement de fichier

Je vous recommande de lire attentivement la page et commencez tout juste à écrire du code - puis revenez avec des exemples et des traces de pile lorsque cela ne fonctionne pas.

65
Henry

démo

Mise à jour de réponse d'Akseli Palén . voir le github repo , fonctionne avec Django 2

Un exemple minimal de téléchargement de fichier Django

1. Créer un projet Django

Lancer startproject ::

$ Django-admin.py startproject sample

maintenant un dossier ( exemple ) est créé ::

sample/
  manage.py
  sample/
    __init__.py
    settings.py
    urls.py
    wsgi.py 

2. créer une application

Créer une application ::

$ cd sample
$ python manage.py startapp uploader

Maintenant, un dossier (uploader) avec ces fichiers est créé:

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

3. Mettez à jour settings.py

Sur sample/settings.py, ajoutez 'uploader.apps.UploaderConfig' à INSTALLED_APPS et ajoutez MEDIA_ROOT et MEDIA_URL, c'est-à-dire ::

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

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

4. Mettre à jour urls.py

dans sample/urls.py add ::

...<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.home, name='imageupload'),
]+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

5. Mettre à jour models.py

mettre à jour uploader/models.py ::

from Django.db import models
from Django.forms import ModelForm

class Upload(models.Model):
    pic = models.FileField(upload_to="images/")    
    upload_date=models.DateTimeField(auto_now_add =True)

# FileUpload form class.
class UploadForm(ModelForm):
    class Meta:
        model = Upload
        fields = ('pic',)

6. Mettre à jour views.py

mettre à jour uploader/views.py ::

from Django.shortcuts import render
from uploader.models import UploadForm,Upload
from Django.http import HttpResponseRedirect
from Django.urls import reverse
# Create your views here.
def home(request):
    if request.method=="POST":
        img = UploadForm(request.POST, request.FILES)       
        if img.is_valid():
            img.save()  
            return HttpResponseRedirect(reverse('imageupload'))
    else:
        img=UploadForm()
    images=Upload.objects.all().order_by('-upload_date')
    return render(request,'home.html',{'form':img,'images':images})

7. créer des modèles

Créez un dossier des modèles dans le dossier de l'uploader , puis créez un fichier home.html , c'est-à-dire sample/uploader/templates/home.html ::

<div style="padding:40px;margin:40px;border:1px solid #ccc">
    <h1>picture</h1>
    <form action="#" method="post" enctype="multipart/form-data">
        {% csrf_token %} {{form}} 
        <input type="submit" value="Upload" />
    </form>
    {% for img in images %}
        {{forloop.counter}}.<a href="{{ img.pic.url }}">{{ img.pic.name }}</a>
        ({{img.upload_date}})<hr />
    {% endfor %}
</div>

8. Syncronize base de données

Syncronize base de données et runserver ::

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

visitez http://localhost.com:80

62
suhailvs

Je dois dire que je trouve la documentation de Django confuse. Aussi, pour l'exemple le plus simple, pourquoi les formulaires sont-ils mentionnés? L'exemple que j'ai eu à travailler dans le views.py est: -

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

Le fichier html ressemble au code ci-dessous, bien que cet exemple ne télécharge qu'un fichier et que le code pour enregistrer les fichiers en traite plusieurs: -

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

Ces exemples ne sont pas mon code, ils ont été choisis parmi deux autres exemples que j'ai trouvés. Je suis un débutant relatif à Django, alors il est très probable que je manque un point clé.

27
jimscafe

Étendre sur exemple 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

Vous pouvez appeler cette fonction handle_uploaded_file à partir de votre vue avec l’objet fichier téléchargé. Cela enregistrera le fichier avec un nom unique (préfixé avec le nom du fichier du fichier téléchargé d'origine) dans le système de fichiers et renverra le chemin complet du fichier enregistré. Vous pouvez enregistrer le chemin dans la base de données et faire quelque chose avec le fichier ultérieurement.

16
Imran

J'ai également eu la même exigence. La plupart des exemples sur le net demandent à créer des modèles et des formulaires que je ne voulais pas utiliser. Voici mon code final.

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

Et en HTML à télécharger, j'ai écrit:

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

Voici le code HTML qui affiche le contenu du fichier:

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

Ici, cela peut vous aider: créez un champ de fichier dans vos modèles.py

Pour télécharger le fichier (dans votre 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)

et utilisez également ce champ dans votre modèle.

11
Vijesh Venugopal

Vous pouvez vous référer aux exemples de serveur dans Fine Uploader, qui contient la version de Django. https://github.com/FineUploader/server-examples/tree/master/python/Django-fine-uploader

C'est très élégant et le plus important de tous, il fournit js lib en vedette. Le modèle n'est pas inclus dans les exemples de serveurs, mais vous pouvez trouver une démonstration sur son site Web. Fine Uploader: http://fineuploader.com/demos.html

Django-fine-uploader

views.py

UploadView envoie le message et supprime la demande aux gestionnaires respectifs.

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

Vous ne savez pas si cette approche présente des inconvénients, mais encore plus minime dans views.py:

entry = form.save()

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

J'ai fait face au même problème et résolu par le site d'administration 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)
0
hlpmee