How do you serve vanilla/custom pages in an MVC based site? - django

Let's say you've setup your site using Pylons, Django and most of the site runs fine and according to the framework used. However, what if you had a custom section that was entirely say, composed of flat html files and its own set of images, which you didn't have time to actually incorporate using the framework and were forced to basically support, under the same domain? Should there be some sort of default controller/view that's super bare minimalistic or do frameworks such as these somehow offer support in some smart way?
I realize also that potentially one could setup a new subdomain and reroute it to an entirely different directory, but I'm just curious as to how one would solve this when forced to deal with a framework.

When serving static pages I'd rather avoid having Django or Pylons handle the request, and handle it with the web server only. Using Nginx, you'd use a directive like:
location / {
root /whatever/the/path/is/;
# if the file exists, return it immediately
if (-f $request_filename) {
break;
}
# pass requests to MVC framework
# i.e. proxy to another server on localhost:
proxy_pass http://127.0.0.1:80;
}

For pylons you should be able to drop your static html files in the public directory. If there isn't a controller for a url then I think pylons looks in the public folder next.

For Django, I would serve these in exactly the same way as you serve your static assets - in your site_media directory, along with subdirs for js, css and img, you could have an html directory. Then the URL would just be /site_media/html/whatever.html.

In Django take a look at flatpages. It's part of the django.contrib package and uses flatpages middleware to serve up flat HTML controlled through the admin interface. For basic purposes, serving up additional about pages or the like this should do the trick.
You could also just create an HTML folder and - using mod_python, at least - set no handler for that path in the Apache configuration file (e.g. vhost.conf).

Related

Django serve files outside the web root

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.

Serve media file from Django

I know that it's not a good way to serve directly file and picture from django via views and urls dispatch, but if these files and pictures are served via the server (Apache), the whole world can see them. What if some files and pictures are private for the user, and only the connected user can see these files or pictures? In this case, I need to serve by django itself?
To serve private documents, you should use a Python view that does the security checks.
Here is an example.
If you are using Apache with mod_wsgi then you can use mod_xsendfile
You are essentially looking to run the authorisation for some resources via Django, pass a header back to Apache saying 'Hey dude, lighten up. This user is okay to access this' Apache will then handle returning the resource.
Rough steps (as in, rough enough that you will need to do a little more research using the links I provide as a starting point)
Apache needs to know which resources are public and which aren't. Create a sub directory under media for both of these types (Why not go crazxy and call them /media/public/ and /media/private/)
Set up an alias for the public directory and a WSGIScriptAlias for the protected dir, the protected alias will be pointing to your main site handler (probably django.wsgi)
Add settings to vhost:
XSendFile On
XSendFileAllowAbove On
Add an urlconf to your Django app that handles /media/protected/{whatever} and routes it through your auth Django app auth logic. An example of this is here
A useful snippet for the above is here
and another example for good measure here

Nginx and Django on Dotcloud

I currently have a dotcloud app that uses django to serve everything. It works great, however, we recently had our site redone in angular.js, and I don't want to use django to serve the actual html pages (I want to just use nginx for that), but I want django to serve some links for the API we built for the angular code to use.
Is it possible for me, in the same app, to configure nginx to serve some static files for particular urls, and have it send other urls for django to serve?
I want nginx to serve my index.html page is a request comes in to wwww.example.com, but if a request for example.com/api/login/ comes in, I want that to be handled by django. Is this possible?
Yes, you can do what you are looking for, you just need to add an nginx.conf to your project and then specify which urls you want nginx to serve and which ones you want django to serve, by default they will all go to django, so you just need to specify which ones you want to be served by nginx.
Here is a link to the documentation: http://docs.dotcloud.com/0.4/guides/nginx/
Link to the nginx documentation on location blocks: http://wiki.nginx.org/HttpCoreModule#location
Here is an example for serving static files from nginx, you can use this as a guide to do what you need.
location /media/ {
root /home/dotcloud/data ;
}
location /static/ {
root /home/dotcloud/volatile ;
}

Django and Serving Static Files

I'm hosting a site on WebFaction using Django/mod_python/Python2.5. I've recently run into the concept of static files (when setting up my Django admin).
From what I understand, serving static files is simply the idea of telling the server to serve files directly from a specific directory, rather than first routing the request through apache, then mod_python, then django, and finally back to the user. In the case of WebFaction this helps especially since there are two Apache servers that your request must go through (your app's server and the main public server).
Why is it that when I setup Django's static files, it only needs the /media folder in /contrib/admin? Is it just that all of Django's static content is related to the admin panel?
When I want to serve my own static content (images, css, etc.) should I include it in the same /media folder or set up another alias for my own content (/my_media)?
Yes, the static files used by Django are pretty much related to images, javascript and css for the admin. All other static content comes from your application. You can keep both sets (yours and the admin) under the same server. Just set the appropriate folders in the settings file.
http://docs.djangoproject.com/en/dev/ref/settings/#admin-media-prefix
http://docs.djangoproject.com/en/dev/ref/settings/#media-root
http://docs.djangoproject.com/en/dev/ref/settings/#media-url
See this post for a little more information:
Django and Static Files
Django's static files (e.g. js, css, images, etc.) are all in the media folder, and are related to the admin panel.
On WebFaction to save processing power, and more importantly memory, it is better to serve these from your secondary apache server (or even better from nginx or lighttpd) without having to go through mod_python and Django.
I use the following folder setup for my files:
media
css
js
img
etc
admin
css
js
img
See http://forum.webfaction.com/viewtopic.php?id=1981 for how to setup nginx as your secondary server on WebFaction if you are interested.

How do you Require Login for Media Files in Django

I'm serving "sensitive" information in downloadable PDF's and Spreadsheets within a user registration section of a site.
Is there a way to allow the django authentication to secure this media without serving it (and not have to manually login using basic auth)?
I'm guessing theres (fingers crossed) not a way to do it with the psuedo code below, but it helps better illustrate the end goal.
#urls.py
(r'^protected_media/(?P<filename>.*)$', 'protected_media')
#views.py
from django.contrib.auth.decorators import login_required
#login_required
def protected_media(request, filename):
# #login_required bounces you out to the login url
# if logged in, serve "filename" from Apache
It seems to me that the method you outlined in your code should work. It's really no different than any other protected resource: your views can serve files from disks, records from databases, rendered templates or anything. Just as the login_required decorator prevents unauthorized access to other views, it will prevent such access to your view serving protected media.
Am I missing something from your question here? Please clarify if that's the case.
EDIT: With regard to the django doc link in your comment: that's the method for simply serving any request file from a particular directory. So, in that example URLS like /site_media/foo.jpg, /site_media/somefolder/bar.jpg will automatically look for files foo.jpg and somefolder/bar.jpg under document_root. Basically, every thing under document_root will be publicly available. That's obviously insecure. So you avoid that with your method.
It's also considered inefficient because django is just adding a lot of unnecessary overhead when all you need is something like Apache to take a URL request and map it to a file on the hard drive. (You don't need django sessions, request processing, etc.)
In your case, this may not be such a big concern. First, you've secured the view. Second, it depends on your usage patterns. How many requests do you anticipate for these files? You're only using django for authentication -- does that justify other overhead? If not, you can look into serving those files with Apache and using an authentication provider. For more on this, see the mod_wsgi documentation:
http://code.google.com/p/modwsgi/wiki/AccessControlMechanisms
see the section "Apache Authentication Provider" and search for django
There are similar mechanisms available under mod_python I believe. (Update: just noticed the other answer. Please see Andre's answer for the mod_python method.)
EDIT 2: With regard to the code for serving a file, please see this snippet:
http://www.djangosnippets.org/snippets/365/
The send_file method uses a FileWrapper which is good for sending large static files back (it doesn't read the entire file into memory). You would need to change the content_type depending on the type of file you're sending (pdf, jpg, etc).
Read this Django ticket for more info. Start at the bottom to save yourself some time. Looks like it just missed getting into Django 1.2, and I assume also isn't in 1.3.
For Nginx, I found this Django snippet that takes advantage of the X-Accel-Redirect header, but haven't tried it yet.
If I understand your question correctly you want to restrict access to files that are not being served by Django, for example, with an Apache server?
What you would then require is some way for this Apache server to use Django as an authentication source.
This django snippet describes such a method. It creates an access handler in Django which is used by Apache when a request for a static file comes in that needs to be protected:
<Location "/protected/location">
PythonPath "['/path/to/proj/'] + sys.path"
PythonOption DJANGO_SETTINGS_MODULE myproj.settings
PythonOption DjangoPermissionName '<permission.codename>'
PythonAccessHandler my_proj.modpython #this should point to accesshandler
SetHandler None
</Location>
Hope this helps, the snippet was posted a while ago, so things might have changed between Django versions :)
More efficient serving of static files through Django is being looked at currently as part of Google SOC project. For WSGI this will use wsgi.file_wrapper extensions for WSGI if available, as it is for mod_wsgi, and req.sendfile() if using mod_python. It will also support returning of headers such as 'Location', 'X-Accel-Redirect' and others, which different web hosting mechanisms and proxy front ends accept as a means of serving up static files where location is defined by a backend web application, which isn't as effecient as front end for serving static files.
I am not sure if there is a project page for this in Django wiki somewhere or not, but the code changes are being committed into the branches/soc2009/http-wsgi-improvements branch of Django source code repository.
You needn't strictly wait for that stuff. It is just putting a clean and portable interface in place across the different mechanisms. If using nginx as front end in front of Apache/mod_wsgi, you could use X-Accel-Redirect now. If using Apache/mod_wsgi 3.0 and daemon mode, you could use Location now, but do need to ensure you set up Apache correct. Alternatively, you could implement your own WSGI middleware wrapper around the Django application which looks for some response header of your own to indicate file to be returned and which uses wsgi.file_wrapper to return that instead of actual response returned from Django.
BTW, the authentication hook mechanisms listed for both mod_python and mod_wsgi by others would use HTTP basic authentication, which isn't what you wanted. This is presuming you want files to be protected by Django form based login mechanism using cookies and backend sessions.