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.

Reply via email to