Reputation: 4367
We have two applications.
TheApp is an incredible app which customers love. Each customer gets his own instance of the application, which means each customer will use a different database (name,user,password). The database connection should be decided on the domain from which the request comes in.
req: customerA.foo.tld -> db:(app_cust1, cust1, hunter2)
req: customerB.foo.tld -> db:(app_cust2, cust2, hunter3)
Should be able to create/delete TheApp instances for the customers. Therefore it has to setup the new database and write the config to somewhere. The way which decides which db is used for the incoming request should perform well and be easy manageable.
Which is the best way to decide which database connection should be used for an instance? What performs the best? What scales best?
I read stuff and those are the ways I came up with:
Each customer will get his own settings.py with the database credentials. The settings may inherit some common stuff from a shared settings file.
For each new setting file a new wsgi instance of the application has to be started. This may scale badly if we have many customers? Also creating the apache vhost files is ugly.
I could do it like
MyModel.objects.using(THE_CURRENT_DB).all()
and set THE_CURRENT_DB
somewhere (middleware thingy?) per request. But it seems ugly to have to do this
everywhere. Also the settings.py/app has to be rewritten everytime a customer gets his
instance.
I didn't yet have a look if I can access any information about the request in the router, but if so, I maybe could decide which of the dbs in settings.py should be used. Kind of like https://docs.djangoproject.com/en/1.3/topics/db/multi-db/#an-example but not per model but per request.
Just had the idea that maybe the db setting could be altered in a middleware. Didn't yet have a look how middleware works in Django and what's possible there.
As I'm pretty new with Django I may have missed some points or some of them are just totally silly and bad. What would jes^wyou do?
Well. Because I think separation of stuff is good. And if bad things happen not everybody is suddenly affected.
Upvotes: 8
Views: 3955
Reputation: 685
This is easily done with middleware and Postgres namespaces. Here is a quick and dirty example with absolutely no error handling:
class NamespaceMiddleware:
def process_request(self, request):
# Get the subdomain. You could also use the domain name, but you'll have to remove special characters.
host = request.get_host()
parts = host.split('.')
if len(parts) >= 3:
subdomain = parts[0]
# Set the namespace (aka "schema"). This will throw a DatabaseError if the namespace does not exist.
from django.db import connection
cursor = connection.cursor()
cursor.execute("SET search_path TO ", subdomain)
With this middleware enabled, each customer can have completely separate data, and no mopery is required to make it work. There are a few things to know, though:
Upvotes: 2
Reputation: 4916
That is one of those scenarios that show the weakness of django configuration module (settings). There is no "django supported" way to do that.
I think you could choose to go with an option that has minimal impact to code maintenance and portability. So I suggest to:
Upvotes: 1