Can I draw your attention to Sebastian Vetter's investigation of the relative scalability of different model polymorphism approaches : https://github.com/elbaschid/talks/tree/master/2013-12-12_MelbDjango_MTI.Performance
Basically, the "select_related then resolve" approach [used in django-model-utils InheritanceManager] doesn't scale nearly as well as django-polymorphic's more pre-fetch-related "1+N queries" approach. -- Curtis On 7 June 2014 01:00, Luis Masuelli <[email protected]> wrote: > Don't know if it's a big patch at all. A polymorphic call could be like > this: > > 1. Check if the class is polymorphic by itself or by inheritance: > > Traverse the inheritance D-Graph (we have to remember it's not a tree > anymore) starting from the current class - It would stop on (and not count) > models.Model (abstract=True and proxy models are also not counted). It > should stop on the first parent having a Meta definition as I exposed > before. > Having multiple (concrete) ancestors defining a Meta like that, would > raise an exception. > Defining such Meta while an ancestor already defined it, would raise the > same exception. > Not finding such Meta in the dgraph would have no effect, and the entire > process would be ignored (i.e. a norma query could be executed over the > current model). It could alternatively throw an exception or leave it as a > settings option (CONTENTTYPE_POLYMORPHIC_EXCEPTION = True #you get the idea) > > 2. If the Meta was found, the polymorphic query could be done. Traverse > the models down from the initial model class (i.e. the one from which the > PQ was done on) enumerating concrete and nonproxy models. Basing in your > idea, a narrow=(Model1, Model2, ...) argument could be specified to only > include those models in the list, ignoring the rest (and stopping when all > those model classes were iterated and found). As complement, an > exclude=(Model1, Model2) could be alternatively specified to skip those > classes (as skipping proxy and abstract classes in the enumeration). > > 3. Perform a select_related or prefetch_related query with the enumerated > classes. This would do a join or prefetch perhaps only on the classes of > interest (narrow=/exclude=) instead of doing the biggest possible join. > > An alternative could be that to define a polymorphic model, the parent > model could be a brand new contenttypes.models.PolymorphicModel (itself > being abstract=True) and the nearest concrete ancestors must implement such > Meta attributes (or an exception should be throw). Perhaps this (abstract) > model could have a metaclass defining a new Manager for 'objects' attribute > which could generate a queryset implementing this polymorphic() method. > > Such model could have the widely-mentioned get_real_instance (as in > django-polymorphic) or narrow() as mentioned in the post. The > implementation could vary: it starts by getting the current object's > contenttype from the discriminator and get the model class for it. if > narrow-style is implemented, issubclass() could be called to determine > whether the object belongs to any of those classes and return the real > instance if so (it could avoid loading a non-specified class lazily). > implementing get_real_instance class could load lazily the class if was not > specified. > > As I see, an implementation like I described (which is not new at all) > could let you leverage the polymorphism level and let you suffer the > tradeoffs you choose. > > Remember that, with this (rant-styled, but improved from reading the post > you pointed me to) proposal, anyone could choose to use the polymorphism in > the queries or not, by calling explicitly such method on the query. Not > using it would behave as normal queries. > > > > El jueves, 5 de junio de 2014 20:03:14 UTC-5, Russell Keith-Magee escribió: > >> >> On Fri, Jun 6, 2014 at 6:49 AM, Luis Masuelli <[email protected]> >> wrote: >> >>> What about integrating polymorphic features in the ORM? It's like having >>> the features of django-polymorphic but in the core. >>> >>> The polymorphism could be acheved by: >>> 1. Having contenttypes installed (this is a common pattern). >>> 2. Specifying a root (first ancestor) model class like: >>> >>> class MyParentModel(models.Model): >>> ... >>> >>> class Meta: >>> polymorphic = True >>> discriminant = "somefield" #it could default to >>> 'content_type' if not specified. This field could be created. >>> >>> To achieve the polymorphism a query could be like: >>> >>> objects = MyParentModel.objects.filter(foo=bar,baz=clorch,...). >>> polymorphic().more().calls().ifneeded() >>> >>> Such method could complain if the contenttypes application is not >>> installed; it could be based on many select_related() arguments (which are >>> collected by tree-traversing the hierarchy, perhaps ignoring proxies). >>> Alternatively, this could be an util in the contenttypes app instead of >>> the core apps: >>> >>> objects = contenttypes.utils.polymorphic(MyParentModel. >>> objects.filter(foo=bar,baz=clorch,...)).more().calls().ifneeded() >>> >>> Sorry if this was posted before, but it's my first time here and I >>> always asked why does Django not have this feature in the core. >>> >> >> If you set your time machine to go back 6 years, you'll find the original >> discussions about model inheritance (implemented by Malcolm Tredinnick, and >> I did a whole bunch of design/implementation review): >> >> https://groups.google.com/forum/#!topic/django-developers/fUCtNz6_qRI >> >> In those discussions, we discussed the idea of introducing a CORBA-style >> narrow() function (which is what you're talking about here) due to the need >> to add and maintain extra columns, which aren't required for many >> applications. >> >> That said - the decision was at least partially in the interests of >> landing *something*. We've had 6 years to digest that design, and a bunch >> of internal API cleanups in the process. Personally, I'm not fundamentally >> opposed to revisiting this issue - I've had a bunch of places where a >> narrow() call would have been useful. However, I *would* want it to be an >> opt-in feature of the model API. >> >> But I'd also warn - this isn't a small undertaking. This is going to be a >> big patch, and you're going to need a champion on the core team if you want >> to make serious progress in getting this into core. >> >> Yours, >> Russ Magee %-) >> > -- > You received this message because you are subscribed to the Google Groups > "Django developers" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to [email protected]. > Visit this group at http://groups.google.com/group/django-developers. > To view this discussion on the web visit > https://groups.google.com/d/msgid/django-developers/2287ac72-c541-44ec-a268-f49aec03cb64%40googlegroups.com > <https://groups.google.com/d/msgid/django-developers/2287ac72-c541-44ec-a268-f49aec03cb64%40googlegroups.com?utm_medium=email&utm_source=footer> > . > > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Django developers" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/django-developers. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CAG_XiSAwHYVfG8NWAztsp_B3kw-j39OSLXz%3Dn0bZAsiFUvd9rw%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.
