python - para - instalar django en windows 10
Que Django sirva archivos descargables (14)
Quiero que los usuarios del sitio puedan descargar archivos cuyas rutas estén ocultas para que no puedan descargarse directamente.
Por ejemplo, me gustaría que la URL fuera 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 descargarlo en lugar de intentar encontrar una URL y Ver para mostrarlo?
Debe usar las apis de sendfile dadas por servidores populares como apache
o nginx
en producción. Durante muchos años, estuve usando la aplicación sendfile de estos servidores para proteger archivos. Luego creó una aplicación django sencilla basada en middleware para este propósito, adecuada tanto para desarrollo como para producción. here puede acceder al código fuente.
ACTUALIZACIÓN: en la nueva versión, el proveedor de python
usa django FileResponse
si está disponible y también agrega soporte para muchas implementaciones de servidores desde lighthttp, caddy a hiawatha
Uso
pip install django-fileprovider
- agrega la aplicación
fileprovider
a la configuración deINSTALLED_APPS
, - agregar
fileprovider.middleware.FileProviderMiddleware
a la configuración deMIDDLEWARE_CLASSES
- establezca la configuración de
FILEPROVIDER_NAME
ennginx
oapache
en producción, de forma predeterminada espython
para fines de desarrollo.
en sus vistas basadas en clases o funciones, establezca el valor del X-File
encabezado de respuesta en la ruta absoluta al archivo. Por ejemplo,
def hello(request):
// code to check or protect the file from unauthorized access
response = HttpResponse()
response[''X-File''] = ''/absolute/path/to/file''
return response
django-fileprovider
mejorado de manera que su código solo necesitará una modificación mínima.
Configuracion nginx
Para proteger el archivo del acceso directo, puede configurar la configuración como
location /files/ {
internal;
root /home/sideffect0/secret_files/;
}
Aquí nginx
establece una ubicación url /files/
solo acceso interno, si está utilizando la configuración anterior, puede configurar X-File como,
response[''X-File''] = ''/files/filename.extension''
Al hacer esto con la configuración de nginx, el archivo estará protegido y también puede controlar el archivo desde las views
django
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 pedido (el contenido es dinámico), es posible que desee que django lo sirva.
He enfrentado el mismo problema más de una vez y, por lo tanto, lo he implementado utilizando el módulo xsendfile y los decoradores de vistas de autenticación en la django-filelibrary . Siéntase libre de usarlo como inspiración para su propia solución.
Otro proyecto para echar un vistazo a: http://readthedocs.org/docs/django-private-files/en/latest/usage.html Parece promisorio, pero no lo he probado.
Básicamente, el proyecto abstrae la configuración 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)
Para "lo mejor de los dos mundos", puede combinar la solución de S.Lott con el módulo xsendfile : django genera la ruta al archivo (o el archivo en sí), pero Apache / Lighttpd maneja el archivo real. Una vez que haya configurado mod_xsendfile, la integración con su vista toma algunas líneas de código:
from django.utils.encoding import smart_str
response = HttpResponse(mimetype=''application/force-download'') # mimetype is replaced by content_type for django 1.7
response[''Content-Disposition''] = ''attachment; filename=%s'' % smart_str(file_name)
response[''X-Sendfile''] = smart_str(path_to_file)
# It''s usually a good idea to set the ''Content-Length'' header too.
# You can also set any other required headers: Cache-Control, etc.
return response
Por supuesto, esto solo funcionará si usted tiene control sobre su servidor, o si su compañía de alojamiento ya ha configurado mod_xsendfile.
EDITAR:
mimetype es reemplazado por content_type para django 1.7
response = HttpResponse(content_type=''application/force-download''
EDITAR: Para nginx
verifique this , usa X-Accel-Redirect
lugar del encabezado de apache
X-Sendfile.
Para una solución muy simple pero no eficiente o escalable , solo puede usar la vista integrada de django serve
. Esto es excelente para prototipos rápidos o trabajos únicos, pero como se mencionó 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))
Probé la solución @Rocketmonkeys pero los archivos descargados se almacenaron como * .bin y se les dieron nombres aleatorios. Eso no está bien, por supuesto. Añadir otra línea de @ elo80ka solucionó el problema.
Aquí está el código que estoy usando ahora:
from wsgiref.util import FileWrapper
from django.http import HttpResponse
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 dentro de / media ni / 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 combinándolas todas =)
Proporcionar acceso protegido a la carpeta html estática usando https://github.com/johnsensible/django-sendfile : https://gist.github.com/iutinvg/9907731
Pruebe: https://pypi.python.org/pypi/django-sendfile/
"La abstracción para descargar archivos subidos al servidor web (por ejemplo, Apache con mod_xsendfile) una vez que Django haya verificado los permisos, etc."
S.Lott tiene la solución "buena" / simple, y elo80ka tiene la solución "mejor" / eficiente. Aquí hay una solución "mejor" / intermedia: no hay configuración del servidor, pero es más eficiente para archivos grandes que la solución ingenua:
http://djangosnippets.org/snippets/365/
Básicamente, Django aún maneja el archivo, pero no carga todo en la memoria de una vez. Esto permite que su servidor sirva (lentamente) un archivo grande sin aumentar el uso de la memoria.
Nuevamente, el archivo X-SendFile de S.Lott sigue siendo mejor para archivos más grandes. Pero si no puedes o no quieres molestarte con eso, entonces esta solución intermedia te dará una mayor eficiencia sin la molestia.
Se mencionó anteriormente que el método mod_xsendfile no permite caracteres no ASCII en los nombres de archivo.
Por esta razón, tengo un parche disponible para mod_xsendfile que permitirá que se envíe cualquier archivo, siempre que el nombre esté codificado como URL y el encabezado adicional:
X-SendFile-Encoding: url
Se envía también.
Solo mencionando el objeto FileResponse disponible en Django 1.10
Edición: Me topé con mi propia respuesta mientras buscaba una forma fácil de transmitir archivos a través de Django, así que aquí hay un ejemplo más completo (para mí en el futuro). Se supone que el nombre de FileField es imported_file
vistas.py
from django.views.generic.detail import DetailView
from django.http import FileResponse
class BaseFileDownloadView(DetailView):
def get(self, request, *args, **kwargs):
filename=self.kwargs.get(''filename'', None)
if filename is None:
raise ValueError("Found empty filename")
some_file = self.model.objects.get(imported_file=filename)
response = FileResponse(some_file.imported_file, content_type="text/csv")
# https://docs.djangoproject.com/en/1.11/howto/outputting-csv/#streaming-large-csv-files
response[''Content-Disposition''] = ''attachment; filename="%s"''%filename
return response
class SomeFileDownloadView(BaseFileDownloadView):
model = SomeModel
urls.py
...
url(r''^somefile/(?P<filename>[-/w_//-//.]+)$'', views.SomeFileDownloadView.as_view(), name=''somefile-download''),
...
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 http://docs.djangoproject.com/en/dev/ref/request-response/#telling-the-browser-to-treat-the-response-as-a-file-attachment 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.
def qrcodesave(request):
import urllib2;
url ="http://chart.apis.google.com/chart?cht=qr&chs=300x300&chl=s&chld=H|0";
opener = urllib2.urlopen(url);
content_type = "application/octet-stream"
response = HttpResponse(opener.read(), content_type=content_type)
response["Content-Disposition"]= "attachment; filename=aktel.png"
return response