1

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

[1] I need to be able to share code with clients without revealing other clients' code.

4

0 回答 0