11
votes

Django: Servir un téléchargement en vue générique

Je veux servir quelques fichiers MP3 à partir d'un dossier dans / home / nom d'utilisateur / musique code>. Je ne pensais pas que ce serait une grosse affaire, mais je suis un peu confus sur la façon de le faire en utilisant les vues génériques et mon propre URL.

urls.py p>

def song_download(request, song_id):
    song = Song.objects.get(id=song_id)

    response = object_detail(
        request,
        object_id = song_id,
        mimetype = "audio/mpeg",
    )
    response['Content-Disposition'= "attachment; filename=%s - %s.mp3" % (song.artist, song.title)

    return response


0 commentaires

3 Réponses :


18
votes

Pourquoi voulez-vous faire cela avec une vue générique? Il est très facile de le faire sans vues génériques:

from django.http import HttpResponse


def song_download(request, song_id):
    song = Song.objects.get(id=song_id)
    fsock = open('/path/to/file.mp3', 'rb')
    response = HttpResponse(fsock, content_type='audio/mpeg')
    response['Content-Disposition'] = "attachment; filename=%s - %s.mp3" % \
                                     (song.artist, song.title)
    return response


3 commentaires

Bien foutu, suppose que je suis tellement fixé pour que cela fonctionne avec une vue générique, je ne pensais pas pourquoi j'en ai même eu besoin. Exactement ce dont j'avais besoin, merci!


MP3 est des fichiers binaires, donc en utilisant le mode de lecture de fichier 'rb' au lieu de 'r'


J'ai regardé partout ça! Merci pour cela!



1
votes

Servir des fichiers statiques avec Django est une mauvaise idée, utilisez Apache, Nginx, etc.

https://docs.djangoproject.com/fr/ Dev / HOWTO / STATIC-Fichiers / Déploiement /


5 commentaires

J'entends toi, je suis tout pour utiliser Apache, mais comment puis-je accomplir la réponse acceptée à l'aide d'Apache comme serveur Web? Je veux utiliser mes propres URL et ne pas révéler mon URL de téléchargement.


Je ne suis pas un expert en servant de fichiers statique, mais je parie que vous pouvez réécrire ainsi l'URL des médias statiques.


Ma conflit avec le lien ci-dessus sont des lignes telles que "Nous vous recommandons d'utiliser un serveur Web distinct - c'est-à-dire, c'est-à-dire qui ne fonctionne pas aussi django - pour servir des médias. Voici quelques bons choix:" Je les entends fort et clair mais disons que je Ayez un chemin complet et / ou une URL dans le fichier, comment puis-je cracher cela en utilisant mon style URL mentionné ci-dessus? J'essaie de trouver des projets de Django open source pour voir comment ils le font.


Vous devriez plutôt regarder Apache ou Ngixs Configuration et / ou Modules - cela n'a rien à voir avec Django qui fonctionne derrière le serveur HTTP.


Ce serait moi. Si vous avez eu le même problème et est venu sur cette page pour trouver la réponse. Votre réponse, cependant, ne résout aucun problème du tout. C'est juste un lien vers le site qui ne résout pas non pas ce problème. Quelque chose comme ça peut avoir aidé: Utilisez Apache, mod_xsendfile, ajoutez "xsendfile sur" "xsendfileAllowabove on" à votre Apache Conf, utilisez-le comme ceci: defong_download (Demande, Song_ID): réponse = httpresponse () réponse ['x -Sendfile '] = smart_str (nom de fichier) réponse ["Type de contenu'] =" Audio / MPEG 'réponse ["Contenu-Longueur'] = OS.Stat (nom de fichier) .st_size Retour Response



9
votes

Pour envelopper mon commentaire à Tomasz Zielinski dans une vraie réponse:

Pour plusieurs raisons, il est en effet préférable de laisser Apache / nginx / etc. faire le travail d'envoi de fichiers. La plupart des serveurs ont des mécanismes pour aider à cette upeSease: Apache et Lightpd ont Xsendfile, Nginx a X-Accel-redirect. P>

L'idée est que vous pouvez utiliser toutes les fonctionnalités de Django comme de belles URL, méthodes d'authentification, etc., mais que le serveur effectue le travail de servir des fichiers. Ce que votre point de vue Django doit faire, c'est renvoyer une réponse avec un en-tête spécial. Le serveur remplacera ensuite la réponse avec le fichier réel. P>

Exemple pour Apache: P>

def song_download(request):
    path = '/path/to/file.mp3'
    response = HttpResponse()
    response['X-Sendfile'] = smart_str(path)
    response['Content-Type'] = "audio/mpeg"
    response['Content-Length'] = os.stat(path).st_size
    return response
  • Installez mode_xsendfile li>
  • ajout xsendfileon sur code> et (selon la version) xsendfileallowabove sur code> ou xsendfilepath the / chemin / servez / à partir de CODE> à votre Apache configuration. li> ul>

    De cette façon, vous ne vous refroidissez pas l'emplacement du fichier et conservez toute la gestion de l'URL à Django. P> P>


3 commentaires

Vous pouvez utiliser OS.Path.GetSize (Pathtofile) au lieu de OS.Stat (chemin) .st_size


C'est la vraie affaire, merci à @xubuntix! J'adore que avec votre solution, Django ne se bougeait pas en train de lire le fichier s'il s'agit d'un fichier volumineux.


Quel est le rôle de smart_str ici? - Mise à jour: je vois maintenant que la réponse provient de l'ancien python 2 jours. Je pense que avec Python3, nous n'avons plus besoin de smart_str. Est-ce exact?