Permettre de télécharger un fichier proprement avec Django et nginx


À un moment vous allez devoir proposer à vos utilisateurs de télécharger un fichier. Mais Django n’est pas du tout fait pour streamer des données, et du coup lui laisser cette tâche est un gros gouffre à performance qui va bloquer un de vos workers pendant tout le transfert.

Seulement parfois, il faut quand même générer le fichier via Django, ou au moins checker des permissions, bref, faire un traitement quelconque du côté du code Python. Comment faire alors ?

La solution est le header X-Accel-Redirect :

from django.http import HttpResponse
 
# ici ou pourrait mettre @login_required si on veut
def telecharger_fichier(request):
    # Faire un truc ici qui génère le fichier
    # ou qui récupère un fichier existant.
    # l'important est d'avoir le chemin ABSOLU du fichier
    chemin_vers_fichier = get_chemin_absolu()
 
    # On crée la réponse à la main
    response = HttpResponse() 
 
    # On laisse nginx s'occuper de détecter le mimetype
    del response['content-type'] 
    # On met un header que nginx va comprendre comme "sert le fichier à ma place"
    response['X-Accel-Redirect'] = chemin_vers_fichier
    return response

Et voilà, vous pouvez plugger telecharger_fichier comme vue n’importe où dans urls.py. Quand nginx va voir X-Accel-Redirect, il va servir le fichier automatiquement. Django lui, n’a a gérer que cette vue très légère et passe tout de suite la main au serveur en front.

Afin de rendre votre setup plus sécurisé, mettez la même url que vous avez dans urls.py dans votre fichier de conf nginx :

location /url/de/urls.py/pour/télécharger/les/fichiers {
    internal; # interdit l'accès au fichier depuis l'exterieur du serveur
    alias /chemin/vers/le/dossier/contenant/les/fichiers/;
}

Il existe d’autres headers selon les serveurs en front (WSGI, lighttpd, etc) et parfois en développement, on peut vouloir servir le fichier via Django quand même pour éviter d’installer nginx. L’application django-sendfile fournit des fonctions pour chacun de ces cas d’utilisations, car même si c’est facile à coder, il faut être feinéant.

5 thoughts on “Permettre de télécharger un fichier proprement avec Django et nginx

  • bendem

    “À un moment vous allez devoir proposer à vos utilisateurs de télécharger un fichier”

    Première ligne, deux fautes… Pas bien réveillé ce dimanche ? ;)

  • Sam Post author

    Mais nan, c’est OUne fichier, ma qué cé l’amour de la fichier tout entier.

  • grojean

    Mdr j’ai jamais fait attention mais les images qui illustrent tes articles (comme les mecs qui s’arrachent un œil); ont-elles un rapport avec le contenu dudit article?

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.