Mounting a ProxyPass site at the same root url as wordpress - django

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

Related

Make django handle subdomain suffix

We're hosting several dockerized web-apps on our webserver, let's call it group.example.com. Our subdomains are handled via nginx as suffixes though, which translates to something like group.example.com/app1/ group.example.com/app2/ as root urls.
When using Django, we run into problems though, as all its urls generated by url in the templates such as home will be relative links, so rendered to home. This relative link will not be interpreted correctly, leading to the main, non-app page group.example.com.
So the goal is to have an app based prefix such as /app1/ for all links. I can hardcode these for static links, but there has to be a more elegant way. Also this leads to problem for the used forms submitting to the wrong page - redirecting again back to the main, non-app page group.example.com.
I tried adding /app1/ to all registered urls as prefix, but that doesn't seem to work either - that way the app is running but user would need to visit group.example.com/app1/app1/ to get to the index, and the relative links still don't work correctly.
In the app docker-container we're running the web-app with nginx and uwsgi. It works fine when using correct subdomains such as app1.example2.com - but we don't have that capability on our new faster webserver we want to host the app on.
Is there a way to resolve this using the app containers nginx, uwsgi or django / middleware config to get the links to resolve to group.example.com/app1/ as root?
As far as I know, there is two ways to resolve it.
One use SCRIPT_NAME in the NGINX configuration. For example, based on this server fault answer:
location /app1/ {
SCRIPT_NAME /app1;
# rest of the config
}
Two You can add FORCE_SCRIPT_NAME in your settings.py:
FORCE_SCRIPT_NAME = '/app1'
FYI, I would prefer using first solution.

Django moving from Development server to Deployment Server

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

multiple django projects at same url

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

Django, how to access request object in settings.py

Is it somehow possible to access the request object inside settings.py?
Maybe by creating a temporary settings object, modifying it and then telling the rest of the "chain" to use that instead of the normal settings.py?
I need it to decide which DB-connection to use.
As an extra question. If I were to have something like 5000 database connections, would settings.py be just as efficient as storing them in a sqlite db on the web-frontend?
And would it be just as painless to update the connections? Or does the server have to be reloaded to catch the changes in settings.py?
Edit: To clarify why I might be needing that many connections.
I am building a webapp. It's SaaS and like many others the accounts will each have a subdomain that they can create users on and will have no need to interact with any other subdomain/account.
It would then be nice to confine each account to a DB all of its own. This grants some extra security and simplifies the app. There are many more advantages to it, but this should illustrate it just fine.
This is why I might end up with that many different databases (but not that many different physical servers if that makes any difference).
If i understand this right, you could use django's new db-routing system and select database on-the-fly based on model instance (e.g. your user) without the need of using() call.
Just adding this for anyone else looking for the same.
It is not currently possible. I have created a feature request on the Django bug-tracker (#13056 i think) and submitted a prototype for a fix, but I don't think it will be included anytime soon and it probably has a lot of bugs in it.
I have moved the project to Flask as it has the g object that is perfectly suited for this.
Django's ORM is not designed to switch database credentials mid-stride. Perhaps you would be happier with something a bit more DIY, such as SQLAlchemy.
I've addressed this problem on a site I've been using recently, and decided to let Apache/mod_wsgi do the work. This solution adds a bit of memory and CPU overhead, but for my app it was the best way to keep everything flexible.
Apache .conf:
SetEnv DJANGO_TEMPLATE_DIR '/usr/local/www/apache22/data/django/templates/'
<VirtualHost *:80>
ServerName encendio.whatever.com
ServerAdmin your_admin#whatever.com
DocumentRoot "/usr/local/www/apache22/data"
SetEnv DJANGO_DATABASE_NAME monkeys
SetEnv DJANGO_DATABASE_USER root
SetEnv DJANGO_DATABASE_PASSWORD secretPass
SetEnv DJANGO_DATABASE_PORT ''
SetEnv DJANGO_DATABASE_HOST ''
WSGIScriptAlias / /usr/local/www/apache22/data/django/wsgi_handler.py
</VirtualHost>
settings.py:
DATABASE_NAME = os.environ.get('DJANGO_DATABASE_NAME', '')
DATABASE_USER = os.environ.get('DJANGO_DATABASE_USER', '')
DATABASE_PASSWORD = os.environ.get('DJANGO_DATABASE_PASSWORD', '')
DATABASE_HOST = os.environ.get('DJANGO_DATABASE_HOST', '')
This allows you to set up each site as a VirtualHost in the httpd.conf.

How does one set up multiple accounts with separate databases for Django on one server?

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/