Skip to content
Snippets Groups Projects
Select Git revision
  • 2ffddc90fc94f1d6e3aaf155402476c869a47d68
  • master default
2 results

exemple-upload-django

user avatar
florimondmanca authored
2ffddc90
History

exemple-upload-django

Ceci est un exemple, sous Django, de gestion de fichiers uploadés par un utilisateur dans le cadre d'un formulaire.

Il s'agit d'une petite application CRD (Create, Read, Delete) autour d'un modèle très simple de dossier d'inscription pour lycéen, comprenant 3 champs :

  • Prénom
  • Nom
  • Autorisation de droit à l'image

Ce dernier champ est un champ de fichier où l'utilisateur doit fournir un fichier PDF. Pour tester l'application, on pourra utiliser sample-data/doej.pdf.

Installation

Après avoir clôné le repo :

# Recommandé : créez un environnement virtuel
$ virtualenv env
$ . env/bin/activate

# Installez les dépendances
$ pip install -r requirements.txt

# Initialisez la DB
$ cd uploadexample
$ python manage.py makemigrations
$ python manage.py migrate

# Lancez le serveur de dev
$ python manage.py runserver

Le site sera accessible à l'adresse http://localhost:8000.

Notes d'implémentation

Stockage de fichiers uploadés dans Django : les médias

Pour activer le stockage des fichiers de médias par Django, on définit les paramètres suivants dans settings.py :

# uploadexample/settings.py

# URL pour accéder à une ressource de type média
MEDIA_URL = '/media/'

# Dossier où seront stockés les médias
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Lorsqu'un fichier est uploadé via un formulaire, Django le placera dans le dossier indiqué par MEDIA_ROOT en ayant au préalable éventuellement ajouté un hash à son nom (pour éviter les doublons). Il sera accessible à l'adresse <MEDIA_URL>/<nom_du_fichier> sur le serveur Django.

Service des médias en développement

Dans un contexte de développement, on peut se permettre de servir les fichiers de médias et les fichiers statiques par Django. Cette approche n'est pas efficace en production : la solution à employer et alors de passer par un serveur web dédié aux fichiers statiques et aux médias, tel que nginx.

# uploadexample/urls.py

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)
    urlpatterns += static(settings.STATIC_URL,
                          document_root=settings.STATIC_ROOT)

Écriture du modèle

Sur le modèle, on utilise un champ FileField :

# upload/models.py

class StudentRegistration(models.Model):
	...
	image_agreement = models.FileField("autorisation de droit à l'image")
	...

Le serializer est tout-à-fait classique et est défini dans upload/serializers.py.

Côté front

La gestion du formulaire côté frontend est ici assurée par le Django REST Framework (rendu d'un serializer comme un formulaire). Ce n'est pas une nécessité et le front pourrait tout aussi bien se faire en JS (même si cet exemple ne dispose pas d'une API REST et serait donc à adapter).

Les templates utilisés sont dans le dossier upload/templates. La chose la plus importante à noter concerne le <form> de création d'un nouveau dossier d'inscription : il doit définir enctype="multipart/form-data pour permettre la transmission de fichiers via la requête HTTP POST.

<!-- upload/templates/upload/registration_create.html -->
<form action="{% url 'registration-create' %}" method="post" enctype="multipart/form-data">

Accès aux fichiers de médias par leur URL

Django stocke les fichiers sur le serveur et expose l'URL du fichier via l'attribut url d'un FileField. Dans la page de liste des inscriptions, on utilise cet attribut pour créer un lien vers le fichier correspondant :

<!-- upload/templates/upload/registration_list.html -->
<a href="{{ registration.image_agreement.url }}">Droit à l'image</a>

Dans le cas d'un frontend Javascript, il est tout-à-fait envisageable de fournir l'URL directement dans le JSON d'une requête de type GET /api/registrations/. Libre au front d'utiliser cette URL comme bon lui semble : lien vers le fichier ou affichage direct dans la page... La réponse JSON ressemblera typiquement à:

[
	{
		"first_name": "John",
		"last_name": Doe",
		"url": "http://localhost:8000/media/doej.pdf"
	},
	...
]

Gestion des fichiers inutilisés

Lorsqu'un modèle ayant un ou plusieurs champs FileField est supprimé, les fichiers correspondants ne sont pas supprimés du serveur, et deviennent inutilisés (c'est un choix délibéré du framework).

On doit alors supprimer manuellement ou par une tâche périodique (job Cron) les fichiers inutilisés. Une commande de gestion a été définie dans cet exemple (définie dans upload/management/commands/clean_media.py) et s'utilise comme suit :

$ python manage.py clean_media
# Si des médias inutilisés sont détectés :
Detected unused media files:
	doej.pdf
Deleted 1 unused media file(s).
# Sinon :
No unusued media files detected.

Cette commande n'est pas spécifique à cette application et se contente de supprimer tous les fichiers qui ne sont référencés par aucun modèle de la DB.