Dear List, This is my first time writing to the list. I've been working with Django for the last two years and recently started hacking on Django itself.
For a while I have felt restricted by the fact that I cannot replace the user model. I use the profile feature for additional methods and attributes. However, it is inelegant, particularly when I wish to modify an existing user method. Also, as I develop a library of applications, and try to use apps I find on the web, I find it difficult to reuse apps because they expect certain models to be imported from certain places. For example, two years ago I created an app that integrated with the US postal service web APIs. I recently was working on a crm-type website that I would like to add shipping functionality to. However, the shipping app had its own Package model that needed to tightly integrate with a ShippingEvent model. My crm already has its own Letter model that tightly integrates with the UserProfile model and the reports views. I have no easy way to integrate these two applications. The only way I can see is to completely fork my USPS app and integrate its functionality line-by-line with my crm. I think this problem could be solved by making models pluggable. I realize that this has been proposed before ( http://groups.google.com/group/django-developers/browse_thread/thread/2dd8fb9ea1fd3763/ef7db33f2fe713a3). I have been thinking about how to bring the advantages of a pluggable architecture to django's models without any of the disadvantages described in the thread. It would need to: 1) be completely backwards compatible 2) not require additional unpythonic behavior (such as interfaces) 3) Existing models should be pluggable with no modification 4) Not require any significant change in code base I think I may have a system that meets these requirements. All it would require of the developer is to place a dictionary of components in her project's settings.py file. Each key would be the dotted path to an original model, each value would be the dotted path to the model that will replace the original model. When the original model is imported, the replacement model would instead be returned completely transparently to the application importing the model. With this system in place, I could simply move all the functionality in my package model in my USPS app to a base class, then my letter model in my crm could inherit from that base model. I set my settings.COMPONENTS={'usps.models.package':'crm.models.letter'} and magically, my USPS app and letter app work together. Every time my USPS app gets a usps.models.package it actually receives a crm.models.letter that does the same thing. My ShippingEvents is now This system definitely meets the first three requirements. 1) it is completely backwards compatible. If there is no COMPONENTS dictionary, everything works exactly the way it did before plugging was added. 2) there is no need for interfaces or getter functions that get the appropriate class or object, you simply import and call as usual. 3) existing models can be overridden with no extra work. 4) is the only part I cannot answer fully. I started an implementation, just to see if it was even possible, and I've made some progress - it works with quite a few of my test models. However, I am just learning the internals of Django, and there are still errors with my implementation. I wanted to put this to the list before going further. As far as I've gotten with actual implementation: When a project imports the original model (original.model), django.db.models.base.ModelBase.__new__ checks to see if "original.model." is in the COMPONENTS dictionary. If it is, it gets the path to the replacement model ("replacement.model2"), and gets the replacement class. It calls django.db.models.register_models('original', model=<class "model2">) which registers the replacement model class under the original application and with the name 'model'. Now, there are multiple copies of replacement.model2 in django.db.models.loading.cache, so django.db.models.get_models() removes duplicates before returning all models. There are other internals that will need to be modified, besides these three methods, in order to eliminate the occasional errors I'm getting in syncdb; I'm still figuring out what those are. Your feedback is appreciated. David Greisen -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.
