Django-cms for multiple websites - django

How to setup a django-cms project to support multiple websites?
There's no reference to this in the official documentation and only limited information in the mailing list, but it's in the headline "A Django application for managing hierarchical pages of content, possibly in multiple languages and/or on multiple sites." and through the Django Sites Framework there's already built in support, and in the admin pages can be associated to different sites.
Related:
Django-CMS: Multiple domains on same project

there are a few different options to manage different websites (and, thus, templates and page contents) in Django-cms.
The basic approach
My favorite is probably the simplest:
In my virtualenv I have a single django-cms installation AND a single "project" that contains ALL the templates I use.
I have a global settings file plus one for each website that does only import all global settings and set "SITE_ID".
from base import *
SITE_ID = XXX
For structure i usually have a settings folder, an empty __init__.py inside, a base.py with all the common settings - including django-cms settings, and then the different websites eg. site1.py site2.py etc. (sometimes my structure is even slightly more complex to also account for dev/production, different machines, etc. but that's not relevant here).
I launch each website as a different instance - I use gunicorn so that's extremely easy too, each one of a different port.
I have an nginx fronted with a separate server configuration for each of my websites, and each of these points to a different gunicorn.
server {
listen 80;
server_name example1.com www.example1.com;
...
location / {
proxy_pass http://localhost:PORT;
}
}
Any of the gunicorn instances can access the admin, and all the data is shared in a single database, but for simplicity
That's all!
Of course it can be done similarly with Apache, mod_wsgi and different virtualhosts.
Advanced
Themes
I actually structured my folders to have an apps folder called themes. Each theme is actually an APP, though mostly contains only the templates and static folders, and it's added to the INSTALLED_APPS.
This allows for cute things such as inheritance and/or overriding between different themes.
Dynamic SITE_ID
It's also possible to use a middleware that will dynamically extract and set the SITE_ID from the URL. This allows to have one single instance... but I don't see any real advantage in this solution and rather find it a potential source of risks.

Related

How to do site specific configuration with Python Django

At the moment i run some django sites with site specific config by using multiple settings.py with different SITE_ID in it and application specifig APP_OPTION="foo" settings.
Now i would like to run the sites from one process selecting the site by domain (which is done by get_current_site). But in this case they share the global settings.
One option would be of course to patch the applications to use APP_OPTION[site_id]="foo", another option would be to place the settings in the database. Both seem not to be the best solutions to the problem.
Which is the most elegant way to have such site specific config values?

How to setup django with unique settings.py per SITE_ID

I have been researching the various (and there are many) ways to have multiple sites under a single Django framework.
I still don't see a solution that fits well for my use case. The use case being:
A single database, as the majority of data (95%+) will be shared between two
apps
Two distinct user types, that each login via different domains,
and in fact interact with the same raw data, differently
What I want to achieve is this:
When a visitor comes to example.com, the settings for SITE_ID = 1 are in effect.
When a visitor comes to training.example.com, the settings for SITE_ID = 2 are in effect.
I want to do this because:
I want to use explicitly different UserProfile objects for the different users
I want to mix and match views and apps at my will between the different domains
Django docs on the Sites framework don't seem to help me, even though with this and some other articles around, I can see a few possibilities.
My current thinking is to actually solve it using the wsgi server (uWSGI in my case), where I'd take Django's default wsgi.py, duplicate it, and each wsgi conf wiill have its own Django settings.py.
Then the server will in fact be serving two distinct wsgi apps, even though they use much of the same code.
So, in this scenario, my Django project will have:
example.com.settings.py (SITE_ID = 1)
training.example.com.settings.py (SITE_ID = 2)
example.com.wsgi.py (uses example.com.settings.py)
training.example.com.wsgi.py (uses training.example.com.settings.py)
My scenario here should work but it will be twice the memory of solving this within the same Django instance.
Any better implementation for what I need to achieve?
For what I know settings.py is unique for every django project, and the SITE_ID is defined at this level. IMHO the best approach is to use many django projects with database routers. In each project you can define the SITE_ID for use with the django sites framework.
https://docs.djangoproject.com/en/dev/topics/db/multi-db/#database-routers

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 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.

Making static file serve location configurable in Django?

I'm developing with Django on my computer, and the location of all my static files are different than on my host. Is there a way to make this a configurable parameter?
For example, on my computer, I have to include jquery.js in my templates, which is located in /includes/jquery.js, but on my host, it's located at ../static/jquery.js, but I don't want to make all of these changes for every template page.
There are two questions here. The first is how to configure where Django finds static files, and the URL prefixes used when linking to/including static resources. The answer to that question is to use the MEDIA_URL and MEDIA_ROOT settings to control the URL mapping and on-disk path info for static media. See the Django setting reference docs for more info on that task.
Then, your second implicit question is how to maintain different settings for your local development environment and the production deployment. There are many different "recipes" for maintaining multiple parallel configuration environments for Django projects, but I find the simplest method to simply be adding something like this to the bottom of my settings.py:
try:
from settings_local.py import *
except ImportError:
pass
Then, if either system (dev or production) has a file called settings_local.py in the root project directory, configuration options set there will override those made in the main settings.py. I then usually add the local file to the ignore list for my version control, and put machine-dependent or security-sensitive data (like database passwords) into it, while the bulk of the configuration can live in the main version-controlled settings.py.
Well, Django config files are python scripts, so you have a great fidelity in them. For example, you may want to create list of locations for every host, and read them in your configuration files.
See the djangodose article on configuring development and production environments and specifically the fourth comment. The instructions given specifically address your question of keeping all settings in the VCS - But what if I'm changing the file that has this configurable location? I don't want to put it on my ignore list.