BEWARE! THIS IS AN EXPERIMENTAL CODE! Created this as a proof of concept and never had a chance to test it thoroughly, not speaking about the production run, as our team changed the plans. While I was very excited during coding it, I unfortunately have no use for schemata currently. I'd love to hear how the code is really doing and if you find something that should be fixed, I'll gladly review and pull your patches.
This project adds the PostgreSQL schema support to Django. The schema, which can be seen as a namespace in which any database object exists, allows to isolate the database objects even when they have the same names. You can have same set of tables, indices, sequences etc. many times under the single database.
In case you're not using schemata, your objects lie in the default schema
public
and because the default search_path
contains public
,
you don't have to care.
It's simple:
- One code
- One instance
- One shared buffering
- One connection
- One database
- One schema for one customer
- You scale up to the stars
Using schemata can be very useful if you run the Software as a service (SaaS) server for multiple customers. Typically for multiple databases you had single project code, cloned many times and that required strong maintenance effort.
So until recently you were forced to maintain multiple Django instances even when the code did the same things, only the data varied. With the invention of multiple databases support in Django it was possible to use it for SaaS, yet using schemata was found to bring even more advantages.
This code was inspired by the A better way : SaaS with Django and PostgreSQL Schemas blog post and the django-appschema application.
Like django-appschema
this project infers the proper schema to switch to
from the hostname found in each web request. You're expected to point
multiple HTTP domains of your customers handled by your (Apache/WSGI) server
to the single Django instance supporting schemata.
Warning: This application was not tested in the multithreading environment, we configure our mod_wsgi to run each Django instance as mutiple separated processes.
Unlike django-appschema
, this project seeks for the maximum simplicity
(added layer and toolset must be as thin as possible so the data path is clear):
- Minimalistic code.
- No hacking of
INSTALLED_APPS
,syncdb
ormigrate
commands... (they had enough with South). - Schema definitions are not stored in the database, but in
settings
's dict. That allows you to flexibly and uniformly configure the differences between individual domains.django-schemata
only requiresschema_name
sub-key, but you're free to store additional configuration there.
Not yet.
The reason why django-appschema
became hackish is that it tries to
sync/migrate both isolated and shared applications in a single run. The app is
shared if it has its tables in the public
schema, hence they're accessible
by every domain. That's because public
schema is always checked after the
object was not found in its "home" schema.
The support for shared application will be added to django-schemata
as soon
as it becomes clear it is required. And we strive to add the support
in a more simple way: ALTER TABLE table SET SCHEMA schema
looks
very promising. We believe it's bearable for the admin to do some extra
setup steps, when the code stays simple.
django-schemata
requires the following settings.py
modifications:
# We wrap around the PostgreSQL backend.
DATABASE_ENGINE = 'django_schemata.postgresql_backend'
# Schema switching upon web requests.
MIDDLEWARE_CLASSES = (
'django_schemata.middleware.SchemataMiddleware',
...
)
# We also offer some management commands.
INSTALLED_APPS = (
...
'django_schemata',
...
)
# We need to assure South of the real db backends for all databases.
# Otherwise it dies in uncertainty.
# For Django 1.1 or below:
#SOUTH_DATABASE_ADAPTER = 'south.db.postgresql_psycopg2'
# For Django 1.2 or above:
SOUTH_DATABASE_ADAPTERS = {
'default': 'south.db.postgresql_psycopg2',
}
# This maps all HTTP domains to all schemata we want to support.
# All of your supported customers need to be registered here.
SCHEMATA_DOMAINS = {
'localhost': {
'schema_name': 'localhost',
'additional_data': ...
},
'first-client.com': {
'schema_name': 'firstclient',
},
'second-client.com': {
'schema_name': 'secondclient',
},
}
As soon as you add your first domain to settings.SCHEMATA_DOMAINS
, you can
run this. PostgreSQL database is inspected and yet-not-existing schemata
are added. Current ones are not touched (command is safe to re-run).
Later more capabilities will be added here.
This command runs the syncdb
command for every registered database schema.
You can sync all of your apps and domains in a single run.
The options given to sync_schemata
are passed to every syncdb
. So if you
use South, you may find this handy:
./manage sync_schemata --migrate
This command runs the South's migrate
command for every registered database
schema.
The options given to migrate_schemata
are passed to every migrate
. Hence
you may find
./manage.py migrate_schemata --list
handy if you're curious or
./manage.py migrate_schemata myapp 0001_initial --fake
in case you're just switching myapp
application to use South migrations.
We're happy to incorporate your patches and ideas. Please either fork and send pull requests or just send the patch.
Discuss this project! Please report bugs.
Success stories are highly welcome.
Thank you.