Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

In principle, a single Django application can be reused in two or more projects, providing functionality relevent to both. That implies that the same database structure (tables and relations) will be re-created identically in different databases, and most times this is not a problem (assuming the projects/databases are unrelated - for instance when someone downloads a complete app to use in their own projects).

Sometimes, however, the models must be "tweaked" a little to better fit the problem needs. This can be accomplished by forking the app, but I wondered if there wouldn't be a better option in cases where the app designer can anticipate the most common customizations.

For instance, if I have a model that could relate to another as one-to-one or one-to-many, I could specify the unique property as a parameter, that can be specified in the project's settings:

class This(models.Model):
    other = models.ForeignKey(Other, unique=settings.OTHER_TO_THIS)

Or if a model can relate to many others, I could create an intermediate table for each of them (thus enforcing referential integrity) instead of using generic fks:

for related in settings.MODELS_RELATED_TO_OTHER:
    model_name = '%s_Other' % related
    globals()[model_name] = type(model_name, (models.Model,) {
        me:models.ForeignKey(find_model_class(related)),
        other:models.ForeignKey(Other),
        # Some other properties all intersection tables must have
    })

Etc. Let me stress out that I'm not proposing to change the models at runtime nor anything like that; once the parameters were defined and syncdb called for the first time, those parameters are not to be changed again (unless you're doing a schema migration).

Is this a good design? Are there better ways to accomplish the same thing, or maybe drawbacks I coulnd't anticipate? This technique is meant to be used sparingly (only on apps meant to be reused in wildly different contexts, and only when a specific need of customization can be detected while the app model is being designed).

share|improve this question
add comment

1 Answer

up vote 1 down vote accepted

I'm thinking the models should be abstract and users of the library should extend them into concrete classes which relate to their specific classes.

If some relationship needs to have different cardinality, you can handle that using model inheritance- have a base class which does not define the relationship and which has template methods for the code involved in the relationship and have subclasses define the different cardinality and implement the template methods. Unless you have lots of different variations within the same class (which doesn't seem like a common thing to me), this should work.

If this doesn't suit your requeriments, yea, you might have to build your models programatically, sounds doable but complex.

As a final comment, stay away from generic foreign keys. They might work somewhat if you never stray out of Django, but...

share|improve this answer
    
Thanks, that really makes more sense. Afterall, if I'm creating a reusable component, it might well be possible I want to use it more than once in the same project, so if I made the customizations at the base classes that would limit what I can do to them afterwards. However, I think it's better to keep the base models concrete, since the whole point is having a framework of related models, and I can't set foreign keys to an abstract model. –  mgibsonbr Jul 21 '12 at 10:38
    
You could have the users extend the other classes too to add the ForeignKeys to their subclasses, but that'd be pretty ugly... –  alex Jul 22 '12 at 11:12
    
generic foreign keys are completely allright. No need to discourage from them. –  clime Nov 8 '13 at 15:01
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.