Django serve files outside the web root - django

I currently have Django set up to upload files to:
/path/to/project/uploads
This works great. This folder is in the root folder of the project so the files cannot be served directly from a web URL, which is what I want, the files are "CVs" uploaded by users.
I've had a look at a third-party django app called filetransfers which would do the job, but I'm wondering if there is a way with Django core to serve files from outside the media folder.
Any help would be great.
Andy

Depending on what web server you are using I would recommend using X-sendfile if you use Apache or X-accel-redirect if you use Nginx. But remember you will need to change setting in your web server. But this is far more efficient way of serving files than using Django to do it.

If what you want is to keep control on how your files are served / who can see them etc, then the simplest solution is to write a custom view serving theses files. You just have to provide the file's content as the response body and set the appropriate response headers (file type, content length etc). Reading the FineManual(tm) part about the Response object should be a good starting point.

Resolved using FileWrapper().
Thanks anyway.

Related

Content negotiation with Django staticfiles in runserver

I'm managing static files (JS, CSS, images, etc) in my Django application using staticfiles. This works fine, but I'd like to start dynamically serving pre-compressed sources when the user's browser is capable.
I went through the linked tutorial and, in production (on Apache) this works fine. I can include files using
<script src="/static/js/my-site"></script>
and it will load my-site.js in older browsers and my-site.js.gz when GZip encoding is supported. Great! But: this breaks local development using runserver. Of course, the staticfiles default view has no idea how to turn /js/my-site into /js/my-site.js (or .gz). To get runserver working, I need to specify the extension, which breaks content negotiation.
Is there a better way to configure Apache, so that I can always request .js (or .css, etc) and get served the compressed version transparently? Or can I tell Django how to find the requested resource without specifying an extension? I wouldn't think I'm the only one trying to do this...
there is no simple resolution. mostly because you are using something that was designed for the apache web server only (afaik).
i my opinion there are 3 solutions:
keep source .{js,css} files in separate directory, in development you can serve them from source dir or compressed one - simple, transparent and you can hide your uncompressed and non-obfuscated sources far from the reach
compress files with the .min.{js,css} ending - no need for separate directory, you can hide sources in apache (mod_rewrite)
write your own small middleware that will be simulating what apache does (it is few lines to select and rewrite path, you can even have different behavior depending on DEBUG config var)
use some dynamic solution e.g Django Compressor which will compile those files on-demand
(I'm using option 4 :) )

Django: How to use static files (simple case, jquery)

I am trying to use jQuery on a Django site. I need to include the jQuery.js library. I have read a lot about Django static files, but I don't think anyone has asked this particular question. I have only three static files to serve: jquery.js, anothersmallfile.js, and styles.css. The Django docs on static file serving say:
"For small projects, this isn’t a big deal, because you can just keep the static files somewhere your web server can find it. link
I would like to "just keep them somewhere my webserver can find them" because elsewhere the Django docs clearly state (warn) that their static-files serving method is only for a development environment. I only have a few static files and I just want the simplest secure solution.
Unfortunately I can't get it working. No matter where I put the files, Django can't find them. Debugging through Chrome web developer console I see I'm getting a 404 error:
GET http://127.0.0.1:8000/templates/polls/jquery.js 404 (NOT FOUND)
I am new to running a server. Do I A.) need to tell my urls.py file where to find static files? or perhaps the problem is B.) that I have misunderstood this issue - Django is my webserver (for production) so right now I must use the Django static files solution?
Doesn't seem like it ought to be very difficult to get my templates to simply recognize a .js file that's in the same directory as they are. Am I missing something?
Edit, before I get more downvotes: I am talking about this passage from the page linked above:
///////////////////////
Django developers mostly concern themselves with the dynamic parts of web applications – the views and templates that render anew for each request. But web applications have other parts: the static files (images, CSS, Javascript, etc.) that are needed to render a complete web page.
For small projects, this isn’t a big deal, because you can just keep the static files somewhere your web server can find it. However, in bigger projects – especially those comprised of multiple apps – dealing with the multiple sets of static files provided by each application starts to get tricky.
That’s what django.contrib.staticfiles is for: it collects static files from each of your applications (and any other places you specify) into a single location that can easily be served in production.
///////////////////
Emphasis added
So if that's what django.contrib.staticfiles is for, what's the simpler solution? I dispute that this is a repeat of prior questions.
You need to read that documentation more closely. That warning is for production. In development, you do use that static-serving method, ie putting it in your urls.py. And, that documentation will also show that the templates directory is not the right place to put them: a separate static or media directory is.
Edit after comment I really don't understand your comment. Either you do it in development via the static serving view, or you use your production server. But you say you don't have a production server. When you get one, whether it's Apache or Nginx or whatever, you put your static files in a directory and tell that server to serve files from there. That is the simple solution. The staticfiles app, exactly as in the docs you quoted, are for when you've got lots of files in different apps (and it simplifies the move from development to production, not complicates it as you seem to think).
Suppose your app is www.
setting.py -> STATIC_ROOT = 'static/'
make dir www/static
make file www/static/some.html
in browser localhost:8000/static/some.html
That's all.

Django where to put static files

I am using Django to create a small web app, however I do not know where i must put my HTML and JS files. I don't want to use the templateing system because I have no need to pass the values from Django directly to the HTML template, Instead the HTML will be static and I will fetch all the data necessary and send the data to be input back into the database using AJAX with Jquery.
My Question is where must I put my HTMl and JS files so they are accessible from the web browser and will be in the same directory so that I can send my ajax requests to something like
http://localhost:2000/webapp/RPC/updateitem/ (more stuff here)
and where the HTML files are
http://localhost:2000/webapp/index.html
Thanks,
RayQuang
You let your main webserver (the one you're running django on) deal with the static files. In most cases this means that you simly server the files through apache (or lighttpd or cherrypy or whatever). Django is only ment for the rendering of dynamic things and thus should not be used for serving static files.
If you're running from a development server (which I can't recommend), this tutorial will help you through setting it up: Serving static files

Serving static files with logic in django (keeping a downloadcount)

I have a site which enables the user to download certain files. However I want to keep a download count for each file so going the usual way by putting the static files on a different subdomain and then letting apache do the heavy lifting is not a way as well as HttpResponseRedirecting the user to a subdomain isn't good because then the user 'sees' the proper download url and can therefore download the file without incrementing the download count. I could just build a view which then serve()s the file however i am worried about that "big fat disclaimer". How would you/did you implement this? I am quite shure I am not the only one with that problem.
About the Platform: I am using apache and mod_wsgi.
Thank you
We've implemented a system where we needed to control download access to (largish) static files, naturally not wanting Django to serve them itself. We came up with a scheme whereby the Django app, after validating that the user was allowed to download the file (or increment a counter, in your case) we would create a randomly-named symlink to the file, which Apache had access to (be careful: make sure directory indexing is off etc), and then redirect the user to that symlink to be served by Apache.
We have a "cleanup" cronjob that cleans up symlink a minute after they're created, so if they want to download it again, they have to go through Django and have it counted again. Now, theoretically they could download it more than once in that time, but is that likely to happen? You could clean up more than every minute: Apache just needs the symlink to exist at the beginning of the download, not throughout the whole thing.
I'd be curious to know how others address this problem, as I agree with the OP that it is a common scenario.
psj's answer is definitely one viable option. Another option you should investigate is putting a reverse-proxy server in-front of apache like Perlbal which supports "X-REPROXY-URL" headers.
Once you have the reverse-proxy server in place, instead of sending the user a redirect response, you can send a response with the "X-REPROXY-URL" header set to a URL where the proxy server can access but the user can't. The proxy server will then read in the file from the location you sent in the header, and then serve it out to your client. They'll do so in an efficient way and since all your Django app server needs to send is a response with a header set, it is free to handle another request.
The easiest way to do this is to use Apache's X-Sendfile header. Just set the value of the header to the file path and Apache will send the file for you. This blog post has some more details: http://francoisgaudin.com/2011/03/13/serving-static-files-with-apache-while-controlling-access-with-django/ .
I did this with django-counter not to long ago. Lets you keep track of the counts in the admin.
http://github.com/svetlyak40wt/django-counter/

Django's admin pages are missing their typical formatting/style, have I set it up wrong?

I finally got my django install working, however I'm noticing that the typical look and feel of the admin pages are missing, and it's as if there are no styles applied to the structure of the pages. Do I have some kind of setup issue or pathing issue that's preventing the style sheets from being found? Where are they stored? My pages look like they are from 1994.
Sounds like your admin media isn't being served correctly. In your settings.py, there's a variable called ADMIN_MEDIA_PREFIX, which specifies the URL where Django should look for them. The actual media files are in "[path to your Python site-packages]/django/contrib/admin/media". When using manage.py runserver, the files are served "automagically". However, when using Apache/nginx/etc it's your responsibility to make sure that your server makes the files available at that URL (using rewrite rules, symlinks, etc). More info can be found here.
I've solved this issue simply with the alias on apache:
Alias /static/admin/ /usr/local/lib/python2.6/dist-packages/django/contrib/admin/media/
Alias admin/media/ /usr/local/lib/python2.6/dist-packages/django/contrib/admin/media/
You need to provide more info for use to help you properly. However, this is most probably because didn't set up your Web server to serve static file, and therefor, the admin CSS is not loaded.
To solve this, got the the admin and look at the HTML source. You'll css the path to the admind css. Make your web server service this file on this path.