I would like to have multiple django projects living at the same root url like this:
example.com/ # controlled by home django project
example.com/project-2 # controlled by a separate django project
example.com/project-3 # controlled by yet another django project
I am already redefining the LOGIN_REDIRECT_URL, etc. as suggested by this excellent answer, but I have discovered another hurdle. I am actually using the same apps in the projects that live at example.com/project-2 and example.com/project-3, which causes some non-trivial problems for linking to content inside of a django project that have thus far been solved with seemingly hacky solutions.
For example, you can never refer to '/' in any template in either example.com/project-2 or example.com/project-3 to return to the root of the django project hosted at either of these URLs --- this will link to the home django project at example.com. To get around this, I have made a context processor that correctly prepends the root url of the project based on a custom settings.py variable SCRIPT_NAME: '' (for example.com), '/project-2' (for example.com/project-2), or '/project-3' (for example.com/project-3). This is all fine and good except that you need to do the same thing in the get_absolute_url functions. Before I knew it, I had just turned a bunch of code that was very reusable (by people other than myself) into code that was not reusable at all.
Is there a way to accomplish the same effect without having to prepend absolute URLs with the SCRIPT_NAME? Perhaps something clever with apache or mod_wsgi configuration? I am at a loss and hoping someone can help...
EDIT:
My apache configuration for example.com looks like this:
# redirect un-'/'-terminated urls to the '/'-terminated root urls
RewriteEngine On
RewriteRule /project-2$ /project-2/ [R=302,L]
RewriteRule /project-3$ /project-3/ [R=302,L]
# mod wsgi setup
WSGIScriptAlias /project-2 /srv/project2/project-2.wsgi
WSGIScriptAlias /project-3 /srv/project3/project-3.wsgi
WSGIScriptAlias / /srv/project1/project-1.wsgi
You don't show how you're serving these projects from your Apache configuration, which would have been useful. But if you define them as separate WSGIScriptAlias directives, then SCRIPT_NAME is automatically passed through for you, and Django takes it into account when reversing and creating URLs.
WSGIScriptAlias /project-2 /srv/project2/project2.wsgi
WSGIScriptAlias /project-3 /srv/project3/project3.wsgi
WSGIScriptAlias / /srv/project1/project1.wsgi
Related
We have a site that is currently running on Wordpress. We are developing a Django site to replace it. Overtime, the goal is to slowly replace parts of the Wordpress site with Django. We would typically set this up for Django something like this:
ProxyPass /newcontent/static !
ProxyPass /newcontent uwsgi://127.0.0.1:3031/ retry=0
ProxyPassReverse /newcontent uwsgi://127.0.0.1:3031/newcontent/ retry=0
This will mount the Django/uWSGI app at ourwebsite.com/newcontent. However, this means that all Django URLs will begin at that root, so something like ourwebsite.com/newcontent/aboutus. Is there a way to configure Apache where all requests would go to Wordpress, unless specifically indicated in the conf? I can imagine that making numerous uWSGI entries would be one way to do it, but then Django is seeing all sorts of base paths, which doesn't work so well internally.
In the end, it would be best if I could do something like:
# Normal Wordpress config, DirectoryIndex, etc
# Django Specific Stuff
/about-us # Goes to Django
/admin/* # Django admin
/our-products/* # This and all subpaths to Django
/static/* # Same, all static content
Additionally, we serve httpS always on Django sites, so It would be preferable to also redirect any Django served URLs to https within Apache.
Over time, we'll just slowly replace wordpress urls until finally, Django is the only thing being served. At this point, we can just clean up the config to send all URLs to Django.
One solution would be to use ProxyPassMatch. Here is an untested example:
ProxyPassMatch "^/newcontent/((one|two|three|four)(/|$).*) uwsgi://127.0.0.1:3031/$1 retry=0
In this, example, one, two, three and four are URLs that should be served by Django.
If ProxyPassMatch can't do it, it can certainly be done with mod_rewrite.
Regular expressions are hard to understand. Even if you are OK, other people around you will be not. So it's best to avoid them. So an alternative solution, if possible, is to list the Wordpress URLs instead of the Django URLs:
ProxyPass /newcontent/five !
ProxyPass /newcontent/six !
ProxyPass /newcontent uwsgi://...
where five and six are to be served by Wordpress.
Update: I slept over my answer and I wonder; you say
I can imagine that making numerous uWSGI entries would be one way to do it, but then Django is seeing all sorts of base paths, which doesn't work so well internally.
So what would be the problem with the following?
ProxyPass /newcontent/one uwsgi://127.0.0.1:3031/one
ProxyPass /newcontent/two uwsgi://127.0.0.1:3031/two
So I am converting the Django tutorial to fully work with Apache instead of using the built-in "runserver" command. I got step one working; getting Apache to serve the static files (css). Now I need to get it to serve the static files for the admin.
My code so far in the httpd.conf file for Apache 2.4.
#static files for site
Alias /static/ "C:/mysite/polls/static/"
<Directory "C:/mysite/polls/static">
Require all granted
</Directory>
#static files for admin
Alias /static/ "C:/Python27/Lib/site-packages/django/contrib/admin/static/"
<Directory "C:/Python27/Lib/site-packages/django/contrib/admin/static">
Require all granted
</Directory>
Obviously having the same alias for the 2nd block does not work and the CSS will not load for the admin. The site (1st block) loads fine. Now this page in the Django tutorial details the entire process on how to make it work. I just cannot figure it out. Maybe I am doing a syntax error and I have read countless posts about this both here and elsewhere.
The doc mentions 3 ways to do it. I want to do it the 2nd way; by way of using the alias directive: "Use an Alias directive, as demonstrated above, to alias the appropriate URL (probably STATIC_URL + admin/) to the actual location of the admin files."
Now I don't understand the exact part where it says "STATIC_URL + admin/). I tried various variations of that but it won't work. My link to the admin page is exactly this:
http://127.0.0.1/admin/
Can we figure this out in specific to WINDOWS and DJANGO 1.6? I know prior to DJANGO 1.4 there was a different way using "ADMIN_MEDIA_PREFIX" in the settings.py file. That way is deprecated now and I want to use the alias. And bonus. How do aliases exactly work?
Thanks all.
EDIT:
Link that mentions how to do it. Under "Serving the admin files" I need to figure out the 2nd way using alias.
https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/modwsgi/
This is what the "static" app is for. You should do manage.py collectstatic on deployment, and this collects all your static content - both for your apps and for the built-in/contrib ones - into one place, which is where you point your Apache alias to.
But if you really want to hard code it, STATIC_URL + admin just means exactly that: the value of STATIC_URL, suffixed with "admin", so Alias /static/admin.
This is the code that finally works:
Alias /static/admin "C:/Python27/Lib/site-packages/django/contrib/admin/static/admin/"
<Directory "C:/Python27/Lib/site-packages/django/contrib/admin/static/admin">
Require all granted
</Directory>
Alias /static/ "C:/mysite/polls/static/"
<Directory "C:/mysite/polls/static">
Require all granted
</Directory>
Note that ORDER matters greatly. I have to Alias the admin static BEFORE aliasing the site static. Sounds like a cascading type issue and makes sense the more specific gets precedent.
Also I had my link incorrect for the admin. It was ending in ../admin/static/. It should go deeper into ../admin/static/admin/.
Finally 2 areas working to serve static files. The admin comes first and then the site static 2nd.
Thanks to all and this should be really documented and might be a pitfall for some.
Regarding this documentation page from the Django website,
https://docs.djangoproject.com/en/1.2/howto/static-files/
where it says for development "With that said, Django does support static files during development. You can use the django.views.static.serve() view to serve media files."
So my question is, if I use this method, How much work is required to move to apache.
Currently I have a symbolic link to my image folder in the /var/www folder, and in the Django settings I have set the media url to :
MEDIA_URL = 'http://127.0.0.1:80/Images/'
This seems like a fairly easy hack but my project is going to get very big (with lots of css, js and pdfs) and I doubt if this method is good.
My approach was to have apache itself intercept the static files urls and serve them directly without invoking django at all. So my apache config looked something like this:
<VirtualHost *:80>
ServerName www.myproject.com
Alias /static /docs/my_website/static
<Directory /docs/my_website/static>
Order allow,deny
Allow from all
</Directory>
Alias /favicon.ico /docs/my_website/static/images/icons/favicon.ico
Include "/13parsecs/conf/django.conf"
</VirtualHost>
Then you can just keep doing whatever you're doing in the dev environment, and when you get to apache it won't invoke django at all for static content, which is what you want.
This is a perfectly good way of doing things. The only change you'll need to make is to put the actual URL of your site, rather than the localhost IP.
Don't "move to Apache", start using it in the first place. None of the software needed has licensing fees and runs on almost any platform, so the only excuse you could have is "I'm too lazy".
I have a Django site set up that uses the Django admin panel, prefixed with /media/, as well as static site content in a directory called /static/. The admin media stuff, of course, lives within the Django package, and the site's static content is stored along with the Python code for the site.
Currently, my public_html just contains appropriately-named symlinks to the directories that actually hold the static content, as follows:
~/public_html/
.htaccess
media -> $HOME/usr/lib/python2.4/site-packages/django/contrib/admin/media/
site.fcgi
site -> $HOME/mysite/public/static/
And these are the rewrite rules I'm using in my .htaccess file:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ site.fcgi/$1 [QSA,L]
However, using symlinks in this way feels like a...hack, and it seems like I could use rewrite rules in the .htaccess to avoid using symlinks. (I also want to eventually add a robots.txt file and a favicon file, without having to add -- and maintain -- a bunch of symlinks.) Is this a good idea, and if so, how do I do that?
For future reference, I ultimately did something akin to how Rails projects are generally set up. My Django project contains a public directory, which includes static site content, the FastCGI script, and the .htaccess file, among other things, so it looks sort of like this:
~/
django/
public/
.htaccess
content/
favicon.ico
media# -> /symlink/to/django/admin/media/
site.fcgi
static/
And then, ~/public_html is just symlinked to ~/django/public. Everything works fine, so I'm happy.
Symlinks are not a "hack" - they're legitimate and useful entities in the filesystem. They're no or more less fragile than any kind of file, they reduce redundancy, and reduce the amount of apache configuration you need to do. I'm not quite following why it is you'd want to avoid them. The symlink solution is far more elegant than writing apache rules, IMO.
I just use
Alias /media /home/akaihola/usr/lib/python2.4/site-packages/django/contrib/admin/media/
Alias /static /home/akaihola/mysite/public/static/
but I do it in a real Apache configuration file instead of .htaccess and I use mod_wsgi, although I don't know if it makes a difference.
I don't symlink for either...
I use the webserver's rewrites to point /media/(.*) directly to my media directory and /admin\-media/(.*) directly to my admin media. I should stress that these rewrites occur before it gets to the django fastcgi rewrite. I'd give you my code, but I'm using Cherokee instead of Apache.
I don't see why you need to have a "physical" representation in your site root...
What options are there for installing Django such that multiple users (each with an "Account") can each have their own database?
The semantics are fairly intuitive. There may be more than one User for an Account. An Account has a unique database (and a database corresponds to an account). Picture WordpressMU. :)
I've considered this:
External solution - Multiplex to multiple servers/daemons
Multiple Django installations, with each Django installation / project corresponding to an account that sets its own DATABASE_NAME, e.g.
File system:
/bob
/settings.py (contains DATABASE_NAME="bob")
/sue
/settings.py (contains DATABASE_NAME="sue")
Then having a Django instance running for each of bob and sue. I don't like this methodology- it feels brutish and it smells foul. But I'm confident it would work, and based on the suggestions it might be the cleanest, smartest way to do it.
The apps can be stored elsewhere; the only thing that need be unique to the django configuration is the settings.py (and even there, only DATABASE_NAME, etc. need be different, the rest can be imported).
(Incidentally, I'm using lighttpd and FastCGI.)
Internal solution - Django multiplexing database settings
On the other hand, I've thought of having one single Django installation, and
(a) Adding a "prefix_" to each database table, corresponding to account of the logged-in user; or
(b) Changing the database according to the account of the User that is logged in.
I'd be particularly interested in seeing the "Django way" to do these (hoping that it's something dead-simple). For example, middleware that takes a Request's User and changes the django.conf.SETTINGS['DATABASE_NAME'] to the database for this user's account.
This raises red flags, viz. Is this thread-safe? i.e. Does changing django.conf.SETTINGS affect other processes? Is there just an inherent danger in changing django.conf.SETTINGS -- would the DB connection be setup already? Is restarting the DB connection part of the public API? -- I'm going to have a look at the Django source when I look to this problem again.
I'm conscious that 2(a) and (b) could require User authentication to be stored and accessed in a different mechanism that the core.
For now, I'm going to go with the external mapping at the webserver layer- it's simplest and cleanest for now. However, I don't like the idea of FastCGI daemons running for every account- it seems to needlessly waste memory, particularly if there will be 2000+ accounts. However, I'd like to keep this discussion open as it's an interesting problem and the solution doesn't seem ideal for certain cases.
Comments duly appreciated.
Cheers
The Django way would definitely be to have separate installations with their own database name (#1). #2 would involve quite a bit of hacking with the ORM, and even then I'm not quite sure it's possible at all.
But mind you, you don't need a WHOLE new installation of all the site's models/views/templates for each user, just a new settings.py with all the appropriate paths to the common source files. Plus, to run all these installations in Apache, do it the way I do here:
<VirtualHost 1.2.3.4>
DocumentRoot /www/site1
ServerName site1.com
<Location />
SetHandler python-program
SetEnv DJANGO_SETTINGS_MODULE site1.settings
PythonPath "['/www'] + sys.path"
PythonDebug On
PythonInterpreter site1
</Location>
</VirtualHost>
<VirtualHost 1.2.3.4>
DocumentRoot /www/site2
ServerName site2.com
<Location />
SetHandler python-program
SetEnv DJANGO_SETTINGS_MODULE site2.settings
PythonPath "['/www'] + sys.path"
PythonDebug On
PythonInterpreter site2
</Location>
</VirtualHost>
assuming you've got /www/site1/settings.py, www/site2/settings.py and so on...
Of course, you now need to have a main site where people log in, that then redirects you to the appropriate site (here I've just put it as "site1.com", "site2.com", but you get the idea.)
The Django ORM doesn't provide multiple database support classes, but it is definitely possible - you'll have to write a custom manager and make a few other tweaks. Eric Florenzano has a great article with detailed code samples:
http://www.eflorenzano.com/blog/post/easy-multi-database-support-django/