I want to make a Foo app that can work with other apps in a way where the other apps "inherit" models, views, and templates from the Foo app.
Set up
I'm making a Django app for generic foos. 80% of the time, the generic Foo
(and related) models will suffice to store the data, and the other 20% of the time, simple multi-table inheritance will suffice to extend the generic models. However, 99% of the time, the generic views will not suffice, and the type of the foo will determine which view to use for both that foo and all the models related to it. New foo types come into existence essentially every time I get a new client, so it's essential I keep business logic in separate apps.[1]
Note that all my models are related to the Foo
model, like so:
from django.db import models
class Foo(models.Model):
# ... model fields and generic business logic
class Bar(models.Model):
foo = models.ForeignKey(Foo)
# ... other model fields and generic business logic
class Baz(models.Model):
bar = models.ForeignKey(Bar)
# ... other model fields and generic business logic
Proposed solution
The Foo
model would contain a string name of the app that contains the custom code that describes the data and behavior associated with that foo type. Each such foo-type plug in would have in its models and views modules a line like from generic-foo.models import *
or from generic-foo.views import *
. Then I would include the following code in the generic Foo
code.
import sys
import importlib
from django.db import models
from myproject import settings
class Foo(models.Model):
FOO_APPS = [(app_name, app_name) for app_name in
settings.INSTALLED_APPS if 'foo' in app_name]
app_name = models.CharField(max_length=256, choices=FOO_APPS)
# ... other model fields and generic business logic
def get_app(self):
"Return the app from which to get the right models or views for this object."
return importlib.import_module(self.app_name)
Then any generic view gv
that uses a Foo
instance (or an instance of a Foo
subclass) obj
would first call app = obj.get_app()
and then call app.views.gv()
. Class-based views can take care of the rest of the work. (Remember that the common case is that the view is provided by the sub app anyway.) Because of the asterisk imports, I can look up the child Foo
(or related model) from the ContentType
table by running the query ContentType.objects.get(app=obj.app_name, model=obj.__type__.__name__)
.
Question
Am I doing this the hard way? (Also, is there a security hole here I'm not seeing?)
Related questions
- Making a multi-table inheritance design generic in Django
- architecting a django app that has a lot of common features between apps
- How do I find the "concrete class" of a django model baseclass
[1] I need to be able to share code with clients without revealing other clients' code.