This is the best news I've heard for a long time! This was also my biggest disappointment with Django. This bit me in my first django project, which incidentally was also my first experience with ORM.
Basically I had the following class structure: Project ---- Art Project ---- Research Project ---- Lecture ... And I wanted to allow the projects to link each other for a "Related projects" feature... i figured it would be easy, just: Project.objects.all()...but no, impossible. Then I figured out that ORM != OO This elementary feature should be merged into the basic django Model class IMO. On Jan 22, 1:00 pm, rvdrijst <rvdri...@gmail.com> wrote: > Wow, amazing job! > > This addresses the big disappointment I felt when I found out django > Model Inheritance didn't do this by default. I used some ugly > workarounds to make it happen and this seems like the perfect > solution. Main problem is that it requires django 1.1, I'm working > with trunk/1.2, but I'm going to give it a try anyway. > > I'll keep tracking the developments on github, keep up the good work! > > - Robin > > On Jan 15, 8:55 pm, Bert Constantin <bert.constan...@gmx.de> wrote: > > > Hello everyone! > > > I just uploaded a simple but mostly complete implementation of model > > and queryset polymorphism onto github and bitbucket. > > > For enabled models, this implementation simply makes all references > > to the model's objects polymorphic (be it managers/querysets or > > relationship fields). > > > The prototype might be useful as a tool for concretely exploring the > > concept of polymorphic models within the Django framework (and > > perhaps might find use in real projects as well). > > > My impression is that fully polymorphic models and querysets > > integrate very well into the Django ORM and database API. Also, with > > Django's ORM and model inheritance system, all the heavy lifting > > has already been done; only a rather thin layer above seems > > to be required to get to a complete implementation of polymorphic > > inheritance. > > > Below I copied the docstring of the module. > > Near the top are a number of short examples that are good as a quick > > overview. > > > The docstring can be read in a much better format > > here:http://bserve.webhop.org/wiki/django_polymorphic > > > Suggestions and criticism are very welcome. > > > Kind Regards, > > Bert Constantin > > > GitHub:http://github.com/bconstantin/django_polymorphic > > Bitbucket:http://bitbucket.org/bconstantin/django_polymorphic > > Tar:http://github.com/bconstantin/django_polymorphic/tarball/master > > > +++++++ > > > Defining Polymorphic Models > > =========================== > > > To make models polymorphic, use PolymorphicModel instead of Django's > > models.Model as the superclass of your base model. All models > > inheriting from your base class will be polymorphic as well:: > > > from polymorphic import PolymorphicModel > > > class ModelA(PolymorphicModel): > > field1 = models.CharField(max_length=10) > > > class ModelB(ModelA): > > field2 = models.CharField(max_length=10) > > > class ModelC(ModelB): > > field3 = models.CharField(max_length=10) > > > Using Polymorphic Models > > ======================== > > > Most of Django's standard ORM functionality is available > > and works as expected: > > > Create some objects > > ------------------- > > > >>> ModelA.objects.create(field1='A1') > > >>> ModelB.objects.create(field1='B1', field2='B2') > > >>> ModelC.objects.create(field1='C1', field2='C2', field3='C3') > > > Query results are polymorphic > > ----------------------------- > > > >>> ModelA.objects.all() > > . > > [ <ModelA: id 1, field1 (CharField)>, > > <ModelB: id 2, field1 (CharField), field2 (CharField)>, > > <ModelC: id 3, field1 (CharField), field2 (CharField), field3 > > (CharField)> ] > > > Filtering for classes (equivalent to python's isinstance() ): > > ------------------------------------------------------------- > > > >>> ModelA.objects.instance_of(ModelB) > > . > > [ <ModelB: id 2, field1 (CharField), field2 (CharField)>, > > <ModelC: id 3, field1 (CharField), field2 (CharField), field3 > > (CharField)> ] > > > In general, including or excluding parts of the inheritance tree:: > > > ModelA.objects.instance_of(ModelB [, ModelC ...]) > > ModelA.objects.not_instance_of(ModelB [, ModelC ...]) > > > Polymorphic filtering (for fields in derived classes) > > ----------------------------------------------------- > > > For example, cherrypicking objects from multiple derived classes > > anywhere in the inheritance tree, using Q objects (with the > > slightly enhanced syntax: exact model name + three _ + field > > name): > > > >>> ModelA.objects.filter( Q( ModelB___field2 = 'B2' ) | Q > > ( ModelC___field3 = 'C3' ) ) > > . > > [ <ModelB: id 2, field1 (CharField), field2 (CharField)>, > > <ModelC: id 3, field1 (CharField), field2 (CharField), field3 > > (CharField)> ] > > > Combining Querysets of different types/models > > --------------------------------------------- > > > Querysets may now be regarded as object containers that allow the > > aggregation of different object types - very similar to python > > lists (as long as the objects are accessed through the manager of > > a common base class): > > > >>> Base.objects.instance_of(ModelX) | Base.objects.instance_of > > (ModelY) > > . > > [ <ModelX: id 1, field_x (CharField)>, > > <ModelY: id 2, field_y (CharField)> ] > > > Using Third Party Models (without modifying them) > > ------------------------------------------------- > > > Third party models can be used as polymorphic models without any > > restrictions by simply subclassing them. E.g. using a third party > > model as the root of a polymorphic inheritance tree:: > > > from thirdparty import ThirdPartyModel > > > class MyThirdPartyModel(PolymorhpicModel, ThirdPartyModel): > > pass # or add fields > > > Or instead integrating the third party model anywhere into an > > existing polymorphic inheritance tree:: > > > class MyModel(SomePolymorphicModel): > > my_field = models.CharField(max_length=10) > > > class MyModelWithThirdParty(MyModel, ThirdPartyModel): > > pass # or add fields > > > ManyToManyField, ForeignKey, OneToOneField > > ------------------------------------------ > > > Relationship fields referring to polymorphic models work as > > expected: like polymorphic querysets they now always return the > > referred objects with the same type/class these were created and > > saved as. > > > E.g., if in your model you define:: > > > field1 = OneToOneField(ModelA) > > > then field1 may now also refer to objects of type ModelB or > > ModelC. > > > A ManyToManyField example:: > > > # The model holding the relation may be any kind of model, > > polymorphic or not > > class RelatingModel(models.Model): > > many2many = models.ManyToManyField('ModelA') # ManyToMany > > relation to a polymorphic model > > > >>> o=RelatingModel.objects.create() > > >>> o.many2many.add(ModelA.objects.get(id=1)) > > >>> o.many2many.add(ModelB.objects.get(id=2)) > > >>> o.many2many.add(ModelC.objects.get(id=3)) > > > >>> o.many2many.all() > > [ <ModelA: id 1, field1 (CharField)>, > > <ModelB: id 2, field1 (CharField), field2 (CharField)>, > > <ModelC: id 3, field1 (CharField), field2 (CharField), > > field3 (CharField)> ] > > > Non-Polymorphic Queries > > ----------------------- > > > >>> ModelA.base_objects.all() > > . > > [ <ModelA: id 1, field1 (CharField)>, > > <ModelA: id 2, field1 (CharField)>, > > <ModelA: id 3, field1 (CharField)> ] > > > Each polymorphic model has 'base_objects' defined as a normal > > Django manager. Of course, arbitrary custom managers may be > > added to the models as well. > > > Custom Managers, Querysets & Inheritance > > ======================================== > > > Using a Custom Manager > > ---------------------- > > > For creating a custom polymorphic manager class, derive your manager > > from PolymorphicManager instead of models.Manager. In your model > > class, explicitly add the default manager first, and then your > > custom manager:: > > > class MyOrderedManager(PolymorphicManager): > > def get_query_set(self): > > return super(MyOrderedManager,self).get_query_set > > ().order_by('some_field') > > > class MyModel(PolymorphicModel): > > objects = PolymorphicManager() # add the default > > polymorphic manager first > > ordered_objects = MyOrderedManager() # then add your > > own manager > > > The first manager defined ('objects' in the example) is used by > > Django as automatic manager for several purposes, including accessing > > related objects. It must not filter objects and it's safest to use > > the plain PolymorphicManager here. > > > Manager Inheritance > > ------------------- > > > The current polymorphic models implementation unconditionally > > inherits all managers from the base models. An example:: > > > class MyModel2(MyModel): > > pass > > > # Managers inherited from MyModel > > >>> MyModel2.objects.all() > > >>> MyModel2.ordered_objects.all() > > > Manager inheritance is a somewhat complex topic that needs more > > thought and more actual experience with real-world use-cases. > > > Using a Custom Queryset Class > > ----------------------------- > > > The PolymorphicManager class accepts one initialization argument, > > which is the queryset class the manager should use. A custom > > custom queryset class can be defined and used like this:: > > > class MyQuerySet(PolymorphicQuerySet): > > def my_queryset_method(...): > > ... > > > class MyModel(PolymorphicModel): > > my_objects=PolymorphicManager(MyQuerySet) > > ... > > > Performance Considerations > > ========================== > > > The current implementation is pretty simple and does not use any > > custom sql - it is purely based on the Django ORM. Right now the > > query :: > > > result_objects = list( ModelA.objects.filter(...) ) > > > performs one sql query to retrieve ModelA objects and one additional > > query for each unique derived class occurring in result_objects. > > The best case for retrieving 100 objects is 1 db query if all are > > class ModelA. If 50 objects are ModelA and 50 are ModelB, > > ... > > read more » -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-develop...@googlegroups.com. To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/django-developers?hl=en.