Installation/Usage

Requirements

This application requires, and depends upon Django being installed. Only Django 1.7 and above is supported, but if you are still using 1.7 then you really should upgrade!

Postgres is required to allow schema to be used. psycopg2 or psycopg2cffi is required as per normal Django/Postgres integration.

Installation and Configuration

Install it using your favourite installer: mine is pip:

pip install django-boardinghouse

You will need to add boardinghouse to your settings.INSTALLED_APPS.

You will need to use the provided database engine in your settings.DATABASES:

'boardinghouse.backends.postgres'

django-boardinghouse automatically installs a class to your middleware (see Middleware), and a context processor (see Template Variables). If you have the admin installed, it adds a column to the admin django.contrib.admin.models.LogEntry class, to store the object schema when applicable.

It’s probably much easier to start using django-boardinghouse right from the beginning of a project: trying to split an existing database may be possible, but is not supported at this stage.

Usage

Shared Models

Some models are required by the system to be shared: these can be seen in:

boardinghouse.schema.REQUIRED_SHARED_MODELS = ['auth.user', 'auth.permission', 'auth.group', 'boardinghouse.schema', 'sites.site', 'sessions.session', 'contenttypes.contenttype', 'admin.logentry', 'migrations.migration', <function <lambda> at 0x7f77b6692ed8>, <function <lambda> at 0x7f77b66a3a28>]

These models are required to be shared by the system.

Other shared classes must subclass boardinghouse.base.SharedSchemaModel, or mixin boardinghouse.base.SharedSchemaMixin. This is required because the migration creation code will not pick up the _is_shared_model attribute, and will attempt to create the table in all schemata.

If a model is listed in the settings.SHARED_MODELS list, then it is deemed to be a shared model. This is how you can define that a 3rd-party application’s models should be shared.

If a model contains only foreign keys to other models (and possibly a primary key), then this model will be shared if all linked-to models are shared (or any of the above conditions are true).

All other models are deemed to be schema-specific models, and will be put into each schema that is created.

Management commands

When django-boardinghouse has been installed, it will override the following commands:

boardinghouse.management.commands.migrate

We wrap the django migrate command to ensure the search path is set to public,__template__, which is a special case used only during DDL statements.

boardinghouse.management.commands.flush

If django 1.7 or greater is installed, wrap the included flush command to ensure:

  • the clone_schema function is installed into the database.
  • the __template__ schema is created.
  • the search path to public,__template__, which is a special case used only during DDL statements.
  • when the command is complete, all currently existing schemata in the SCHEMA_MODEL table exist as schemata in the database.

boardinghouse.management.commands.loaddata

This replaces the loaddata command with one that takes a new option: --schema. This is required when non-shared-models are included in the file(s) to be loaded, and the schema with this name will be used as a target.

boardinghouse.management.commands.dumpdata

Replaces the dumpdata command.

If the --schema option is supplied, that schema is used for the source of the data. If it is not supplied, then the __template__ schema will be used (which will not contain any data).

If any models are supplied as arguments (using the app_label.model_name notation) that are not shared models, it is an error to fail to pass a schema.

Middleware

The included middleware is always installed:

class boardinghouse.middleware.SchemaMiddleware[source]

Middleware to set the postgres schema for the current request’s session.

The schema that will be used is stored in the session. A lookup will occur (but this could easily be cached) on each request.

There are three ways to change the schema as part of a request.

  1. Request a page with a querystring containg a __schema value:

    https://example.com/page/?__schema=<schema-name>
    

The schema will be changed (or cleared, if this user cannot view that schema), and the page will be re-loaded (if it was a GET). This method of changing schema allows you to have a link that changes the current schema and then loads the data with the new schema active.

It is used within the admin for having a link to data from an arbitrary schema in the LogEntry history.

This type of schema change request should not be done with a POST request.

  1. Add a request header:

    X-Change-Schema: <schema-name>
    
This will not cause a redirect to the same page without query string. It is the only way to do a schema change within a POST request, but could be used for any request type.
  1. Use a specific request:

    https://example.com/__change_schema__/<schema-name>/
    
This is designed to be used from AJAX requests, or as part of an API call, as it returns a status code (and a short message) about the schema change request. If you were storing local data, and did one of these, you are probably going to have to invalidate much of that.

You could also come up with other methods.

Template Variables

There is an included CONTEXT_PROCESSOR that is always added to the settings for a project using django-boardinghouse.

boardinghouse.context_processors.schemata(request)[source]

A Django context_processor that provides access to the logged-in user’s visible schemata, and selected schema.

Adds the following variables to the context:

schemata: all available schemata this user has

selected_schema: the currenly selected schema name

Changing Schema

As outlined in Middleware, there are three ways to change the schema: a __schema querystring, a request header and a specific request.

These all work without any required additions to your urls.py.