Hacer que Django sirva archivos descargables [python]


Answers

Una "descarga" es simplemente un cambio de encabezado HTTP.

Consulte http://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment para saber cómo responder con una descarga .

Solo necesita una definición de URL para "/download" .

El diccionario GET o POST tendrá la información "f=somefile.txt" .

Su función de vista simplemente fusionará la ruta base con el valor " f ", abrirá el archivo, creará y devolverá un objeto de respuesta. Debe ser menos de 12 líneas de código.

Question

Quiero que los usuarios del sitio puedan descargar archivos cuyas rutas de acceso estén oscurecidas para que no se puedan descargar directamente.

Por ejemplo, me gustaría que la URL sea algo como esto, " http://example.com/download/?f=somefile.txt

Y en el servidor, sé que todos los archivos descargables residen en una carpeta "/ home / user / files /".

¿Hay alguna manera de hacer que Django sirva ese archivo para descargar en lugar de tratar de encontrar una URL y una vista para mostrarlo?




Para una solución muy simple pero no eficiente o escalable , puede usar la vista incorporada de django serve . Esto es excelente para prototipos rápidos o trabajos únicos, pero como se ha mencionado a lo largo de esta pregunta, debe usar algo como apache o nginx en producción.

from django.views.static import serve
filepath = '/some/path/to/local/file.txt'
return serve(request, os.path.basename(filepath), os.path.dirname(filepath))



Intentó la solución @Rocketmonkeys, pero los archivos descargados se estaban almacenando como * .bin y se les dieron nombres aleatorios. Eso no está bien, por supuesto. Agregar otra línea de @ elo80ka resolvió el problema.
Aquí está el código que estoy usando ahora:

filename = "/home/-addict/private-folder(not-porn)/image.jpg"
wrapper = FileWrapper(file(filename))
response = HttpResponse(wrapper, content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(filename)
response['Content-Length'] = os.path.getsize(filename)
return response

Ahora puede almacenar archivos en un directorio privado (no en el interior / media / / public_html) y exponerlos a través de django a ciertos usuarios o bajo ciertas circunstancias.
Espero eso ayude.

Gracias a @ elo80ka, @ S.Lott y @Rocketmonkeys por las respuestas, obtuve la solución perfecta combinando todas ellas =)







Django recomienda que use otro servidor para servir medios estáticos (otro servidor que se ejecuta en la misma máquina está bien). Recomiendan el uso de servidores como lighttp .

Esto es muy simple de configurar. Sin embargo. si se genera 'somefile.txt' a petición (el contenido es dinámico), entonces es posible que desee que django lo publique.

Django Docs - Archivos estáticos




Otro proyecto para echar un vistazo a: http://readthedocs.org/docs/django-private-files/en/latest/usage.html Parece prometedor, aún no lo he probado.

Básicamente, el proyecto abstrae la configuración de mod_xsendfile y le permite hacer cosas como:

from django.db import models
from django.contrib.auth.models import User
from private_files import PrivateFileField

def is_owner(request, instance):
    return (not request.user.is_anonymous()) and request.user.is_authenticated and
                   instance.owner.pk = request.user.pk

class FileSubmission(models.Model):
    description = models.CharField("description", max_length = 200)
        owner = models.ForeignKey(User)
    uploaded_file = PrivateFileField("file", upload_to = 'uploads', condition = is_owner)