Changing Django settings variable dynamically based on request for multiple site - django

Please advice whether is it correct method to change the urlconf and templatedir variables of a django settings file dynamically within a custom middleware function based on the site requested.

No. I don't know why you would want to do this. If you have multiple sites, the correct way to serve them is with multiple WSGI instances, each pointing at separate settings.py and urls.py files.
Edit after comment: This has nothing to do with the sites framework, which is completely optional. As I say, if you want to serve multiple sites, use multiple .wsgi scripts each pointing to a separate urls.py and settings.py. All the rest of the code can be the same.

Related

Integrating Sphinx and Django in order to require users to log in to see the documentation

I am curious if it is possible to hide sphinx documentation inside a django app so that only people who log in can see it. It seems to me that since sphinx creates its own structure and that Django uses the urlconf to define which pages a user can see, that it wouldn't be possible to combine the two. Although there must be some combining since the Django website likely uses django and sphinx. I am wondering if anyone has any insight or if they can point me in the right direction.
Thank You in Advance!
Sphinx builds your docs into HTML files, so in most cases this docs should be served by your web server rather then Django. However Django is able to serve static files as well.
You can use the django.views.static.serve function to do this and wrap this function with login_required. E.g:
from django.views.static import serve
from django.contrib.auth.decorators import login_required
urlpatterns += patterns('',
url(r'^docs/(?P<path>.*)', login_required(serve), {'document_root': '/path/to/sphinx/build/html'}, 'docs'),
)
However this configuration will be considered a bad practice in production environment as in this case Django will serve both html and css/js files from your sphinx theme.
The first improvement you can do here is to serve /path/to/sphinx/build/html/_static/ with apache/nginx or whatever you use.
The more proper way is to serve docs with apache/nginx and make it handle the auth itself. Unfortunately I made a quick Google search but did not find a way to use Django's User model to handle http_auth in apache or other. Alternatively you can use something like mod_sendfile or X-Accel modules - http://www.wellfireinteractive.com/blog/nginx-django-x-accel-redirects/ In a nutshell - Django app checks permission if user can view the file and add special header to response containing file path. Webserver will serve this file instead of original message from django

Change "ROOT_URLCONF" in Django depending on site

I just need some advice pointing me into the right direction using Django with multiple sites / clients.
Basically depending on the domain name I want to use multiple sites with only one Django instance.
For example a directory structure.
mysite/
manage.py
settings.py
client1/
url.py
client2/
url.py
So what I am thinking is, inside settings.py depending on the domain name I can change the
ROOT_URLCONF = 'mysite.clientx.urls'
The site will match about 95% so I don't see the point of changing all other settings as well.
How would I do this? I did go through site management in the Django documentation although it seems like an overkill for what I want to accomplish.
Also keep in mind I am using Apache with "django.wsgi".

How do I make Django figure out which Site object to use based on "Host" header in the HTTP request?

Consider a Django app built to serve multiple sites with slightly differing content using the standard Django sitesframework.
The traditional way to host this would be to configure multiple Site objects and setup the app in multiple Django projects with each project pointing to a different SITE_ID in their respective settings.py:s.
For various reasons I'd like to avoid having to create a new project for each new site. I want to be able to setup one project and have Django figure out which Site object to use based on the hostname referenced in the incoming HTTP request.
What is the recommended way to achieve this functionality?
Clarification: I want the site framework to ignore settings.SITE_ID (which is hard-coded in settings.py) and instead dynamically fetch Site objects based on what is in the Host header. Why this requirement? I'll be adding and removing sites multiple times per hour and the total amount of sites will exceed 10,000, so setting up a Django project for each site is not an option. Is this a problem that is solvable in Django? If so, what is the best way to achieve it?
The recommended way is to not attempt it at all, since settings should never change at runtime. Instead, set a variable in your virtual host configuration and have the WSGI adapter script or settings module pick one of the sites based on that.

How to make Django url dispatcher use subdomain?

I have a vague idea on how to solve this, but really need a push :)
I have a Django app running with apache (mod_wsgi). Today urls look like this:
http://site.com/category/A/product/B/
What I would like to do is this:
http://A.site.com/product/B
This means that the url dispatcher some how needs to pick up the value found in the subdomain and understand the context of this instead of only looking at the path. I see two approaches:
Use .htaccess and rewrites so that a.site.com is a rewrite. Not sure if this does the trick since I don't fully understand what the django url dispatcher framework will see in that case?
Understanding how the url dispatcher DO work I could write a filter that looks at valid sub domains and provides this in a rewritten format to the url dispatcher code.
Any hints or solutions are very much appreciated! Thanks.
Have you looked at django.contrib.sites? I think a combination of that, setting SITE_ID in your settings.py, and having one WSGI file per "site" can take care of things.
EDIT: -v set.
django.contrib.sites is meant to let you run multiple sites from the same Django project and database. It adds a table (django.contrib.sites.models.Site) that has domain and name fields. From what I can tell, the name can mean whatever you want it to, but it's usually the English name for the site. The domain is what should show up in the host part of the URL.
SITE_ID is set in settings.py to the id of the site being served. In the initial settings.py file, it is set to 1 (with no comments). You can replace this with whatever code you need to set it to the right value.
The obvious thing to do would be to check an environment variable, and look up that in the name or domain field in the Site table, but I'm not sure that will work from within the settings.py file, since that file sets up the database connection parameters (circular dependency?). So you'll probably have to settle for something like:
SITE_ID = int(os.environ.get('SITE_ID', 1)
Then in your WSGI file, you do something like:
os.environ['SITE_ID'] = 2
and set that last number to the appropriate value. You'll need one WSGI file per site, or maybe there's a way to set SITE_ID from within the Apache setup. Which path to choose depends on the site setup in question.
The sites framework is most powerful where you use Site as the target of a ForeignKey or ManyToManyField so that you can link your model instances (i.e. records) to specific sites.
Mikes solution is correct if you want to have multiple sites with same apps with different content (sites module) on multiple domains or subdomains, but it has a drawback that you need to be running multiple instances of the Django process.
A better solution for the main problem about multiple domains or subdomains is to use a simple middleware that handles incoming requests with the process_request() function and changing the documented urlconf attribute (link) of the request object to the URLconf you want to use.
More details and an example of the per-request or per-domain URL dispatcher can be found at:
http://gw.tnode.com/0483-Django/
Try adding a wildcard subdomain: usually *.

How do you setup a Django project with different sites using the same data?

I'm currently looking at the the documentation for Django sites:
http://docs.djangoproject.com/en/dev/ref/contrib/sites/#ref-contrib-sites
which explains how to associate content with multiple sites. The example used is LJWorld.com and Lawrence.com.
What does the Django project structure look like for the above? Is each site an app on its own, for instance:
project/
manage.py
settings.py
urls.py
ljworld/
models.py
views.py
lawrence/
models.py
views.py
If ljworld has SITE_ID=1 and lawrence has SITE_ID=2, does the SITE_ID variable has to be explicitly set in ljworld/settings.py and lawrence/settings.py?
How do you run the dev server of either ljworld or lawrence?
Update:
I used two sites with shared content in the above. What should be done if there are n different sites who are sharing the same content? Do I really need n different Django projects on n different servers, all connected to the same database server?
Moreover, if I need to make a change in settings.py which should affect all those web sites, it will be very tedious to change each of those files manually.
No, each site is not an app on its own; each site is a project on its own. The whole idea is to have different projects with a (fully or partially) shared content. So you might have a structure such as:
ljworld/
manage.py
settings.py
urls.py
ljworld_specific_app1/
...
lawrence/
manage.py
settings.py
urls.py
lawrence_specific_app1/
You would normally use two Web servers to serve the projects - though normally both would refer to the same DB server. Naturally you can also have apps which are shared between the two projects - just keep them somewhere in the server's PYTHONPATH.
Edit:
"Two Web servers" of course doesn't necessarily mean two physically different servers. They could well be two virtual hosts running under the same Web server instance - heck, you could even map the two projects to two different directories under the same virtual host.
For shared settings, you could use the same technique as for shared apps. Have a global_settings module which contains the shared settings available somewhere on the PYTHONPATH and import it from each of the settings.py.
And if you wanted something really hackish, you could probably even drop all the different projects, use just one and create a middleware that changes settings on the fly. But I would advise against it.