Package: django-reverse-proxy-send-file
django-reverse-proxy-send-fileSumaryThis package help writing views which use theX-Accel-Redirectheader to havenginxserving files but still allow a permission check at django's sideIntroThestorage.ReverseProxySendFileFileSystemStorageclass is a drop-in replacement of django'sFileSystemStoragewhich make FileField (or ImageField) url to use theREVERSE_PROXY_SENDFILE_MEDIA_URLsettings base url instead of MEDIA_URLThestorage.ReverseProxySendFileStorageMixinallow you to apply the overridenbase_urlon any storage classTheReverseProxySendFileViewclass handle GET request and return an empty response with nginx'sX-Accel-Redirectheader to order nginx to return the file at given path. TheREVERSE_PROXY_SENDFILE_MEDIA_ROOTsetting must be defined in the nginx context si it can find the fileTheReverseProxySendFileViewcan be overrided to implement a customcheck_permissionmethod which verify is the current user is allowed to download the resource.InstallationInstall thedjango-reverse-proxy-send-filepypi package.
ex:poetry add django-reverse-proxy-send-filepip install django-reverse-proxy-send-fileUsageSee example section bellowSettingsNameDefaultDescriptionREVERSE_PROXY_SENDFILE_MEDIA_ROOTMEDIA_ROOTBase path in django's context where to store media files when uploaded (used by Storage class)REVERSE_PROXY_SENDFILE_MEDIA_URL"smedia/"URL that handle the resources that should be served by the reverse proxy.REVERSE_PROXY_SENDFILE_REVERSE_PROXY_ROOT"smedia/"Base path in reverse-proxy's context which is sent back to reverse-proxy in header so it can find the fileREVERSE_PROXY_SENDFILE_MODE"nginx"Possible values:"nginx"or"apache".nginxmode will useX-Accel-Redirectheader.apachemode will useX-SendfileREVERSE_PROXY_SENDFILE_HEADER_NAMENoneA custom header name. If set this header will be used regardlessREVERSE_PROXY_SENDFILE_MODEsetting.REVERSE_PROXY_SENDFILE_DEBUG_SERVE_RESOURCETrueIn django'sDEBUGmode, the resource is directly served by the dev server.Exemplesettings.py...REVERSE_PROXY_SENDFILE_MEDIA_URL="smedia/"REVERSE_PROXY_SENDFILE_MEDIA_ROOT="/django_path/to/smedia/"REVERSE_PROXY_SENDFILE_REVERSE_PROXY_ROOT="/nginx_path/to/smedia/"...models.pyfromdjango.contrib.auth.modelsimportUserfromreverse_proxy_send_file.storageimportReverseProxySendFileFileSystemStorageclassMyModel(models.Model):...user=models.ForeignKey(User,on_delete=models.CASCADE)my_file=models.FileField("My file",upload_to="my_files/",storage=ReverseProxySendFileFileSystemStorage(),)...views.pyfromdjango.httpimportHttp404fromreverse_proxy_send_file.viewsimportReverseProxySendFileViewclassReverseProxySendFileMyFileView(ReverseProxySendFileView):defcheck_permission(self,request,resource_url,*args,**kwargs):obj_qs=MyModel.objects.filter(my_file=resource_url)ifnotobj_qs.exists():raiseHttp404()returnobj_qs.filter(user=request.user).exists()urls.pyfromdjango.confimportsettingsfromviewsimportReverseProxySendFileMyFileViewurlpatterns=[...re_path(settings.REVERSE_PROXY_SENDFILE_MEDIA_URL+"(?P<resource_url>my_files/.*)$",views.ReverseProxySendFileMyFileView.as_view(),name="reverse_proxy_send_file",),...]User upload file. The file is stored in/django_path/to/smedia/my_files/blop.pdfUser access/smedia/my_files/blop.pdfA django request is performed and it check file access permission for current user (in check_permission).If the user is allowed return a HTTP response with header :X-Accel-Redirect=/nginx_path/to/smedia/my_files/blop.pdf(Nginx will use it to send the file to the client)If the file os not found return a404 note found.If the user id forbidden, return a403 response forbiddenSetup dev environnement# install dev dependenciespoetryinstall--no-root# install git pre-commitpre-commitinstallRun testsUsetoxcommand to run all tests on all supported python versions
Examples:tox
tox-epy38-django40
tox-fpy39Build package and publish on PyPIChange version number inpyproject.tomlpoetrybuild
poetrypublish