I am working on a project that has two separate but interrelated
Django web sites (projects in Django’s parlance). In an earlier blog post,
I described setting up the second project (mk_ai) to have read-only
access to the first project’s database (mk_web_core) in dev but then
getting around those access restrictions for testing. The main thing I
need for testing is a big, set of hierarchical data to be loaded into
the first project’s test database. I can use the manage commands
dumpdata and loaddata to preserve date in my development environment,
but when I tried to load that same data into the test database, I ran
into problems.
We are using GenericForeignKeys and GenericRelations.
Django implements GenericForeignKeys by creating a database foreign
key into the django_content_type table. In our mixed database setup,
my django_content_type table is in the mk_ai schema. So, even if I set
up my database router to allow_relation across databases AND the
postgres database adapter would even attempt to make that join, the
content types in the references in mk_web_core would not be in mk_ai’s
django_content_type table. So we can’t use Django’s GenericForeignKeys.
What shall we do instead?
Rails implements a similar type of relationship with a feature it
calls Polymorphic Associations.
Django stores the object’s id + a FK link to row in the content_type
table representing the the object’s model. Rails store’s the object’s
id + the object’s class name in a field it calls
_type. I decided to use the Rails method to set up
my database representations. That replaces the GenericForiegnKey
aspect. To replace the GenericRelation part, I just created a case
statement that allows queries to chain in the approrpriate related
model based on the ... content type. Perhaps showing an example will
make this clearer.
The original way, using Django's GenericForeignKey:
The 'rails' way, using a block_type name field that can be read
directly in the mk_ai schema.
GenericForeignKey and GenericRelation are two sides of the coin - they
allow you to easily make queries both directions. In our domain, I
don't really have much occaision to go from Block to Page, so I don't
really need to GenericRelation. However, if you need to replace it,
you can create a method to do the appropriate query.