On Tue, Jan 3, 2012 at 11:43 AM, Carl Meyer <[email protected]> wrote:
> -----BEGIN PGP SIGNED MESSAGE----- > Hash: SHA1 > > Hi Zachary, > > On 01/02/2012 10:55 PM, Zachary Voase wrote: > > At the moment it's very easy to add methods to individual models, just > > by putting a method on the model class itself which accepts 'self'. > > However, defining business logic on collections of records is > > currently pretty complicated — you have to create at least a custom > > Manager subclass, and if you want to chain those methods together > > you'll need a QuerySet subclass. An example of the desired behaviour, > > and the steps required for it, is shown in [1]. > > > > I originally created django-qmixin [2] to tackle this problem; you can > > define methods which will be present on the manager and all querysets > > produced therefrom, including on relations. However, the django-qmixin > > approach of creating a mixin and then including that on the Manager > > class object doesn't really gel with the rest of Django core. I've > > worked out two approaches which are easier for novices to understand, > > and match the idioms of the rest of Django. They both involve adding a > > @models.querymethod decorator, which would be applied to methods which > > operate on collections of records (i.e. querysets). It's an analog to > > Python's @classmethod. > > > > The first approach [3] involves adding these querymethods to the model > > class itself; the second [4] adds them to a manager subclass (but > > without the trouble of the QuerySet subclass). I prefer the former, > > for simplicity, but you may believe otherwise. > > > > I'm working on a proof-of-concept implementation, but I feel it's more > > important to agree on the interface and rationale beforehand. Any > > thoughts? > > Thanks for working on this. I think the decorator API you've selected is > a pretty good one for this; I agree with Russell that the methods belong > on a custom Manager, not on the model itself. > > There will be some tricky points in the implementation. In particular, > QuerySets must remain pickleable (so they can be cached), which is > problematic if you are dynamically creating the QuerySet subclass. As > Donald Stufft points out on the ticket, we previously had an approach in > django-model-utils (manager_from) that was based on dynamically-created > QuerySet subclasses, and we moved away from it because it broke pickling > of QuerySets. There may be another way around this; I didn't look at the > problem in depth. > > I have to say, this all feels to me a bit like polishing a turd; adding > ever-more complex hacks with metaclasses, dynamic subclasses, etc., all > to paper over what is really a more fundamental design problem. To wit: > a Manager is no different from a QuerySet in practice - it's just a sort > of "starter" queryset accessible from the model. If in practice people > pretty much always want to pair a custom Manager with a custom QuerySet > that has the same extra methods (and that is my experience), I think > it's telling us that those shouldn't be two separate classes at all. > > I can't help but wonder if it would be possible to solve the problem > more thoroughly and remove the need for magic decorators by eliminating > the Manager class entirely and making it possible to simply assign a > QuerySet to a model, perhaps with a helper method: > > objects = manager(PersonQuerySet.filter(active=True)) > > I'm sure there are devils in the details here, too, but on cursory > inspection of the Manager code, it seems like it might be doable. > > Carl > -----BEGIN PGP SIGNATURE----- > Version: GnuPG v1.4.10 (GNU/Linux) > Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ > > iEYEARECAAYFAk8DPlYACgkQ8W4rlRKtE2e+TQCffZZmaqKRc4Hyn3reUzYj6Cga > ja8AoNyIutFq4GuUfTgn5RgBMQaW/rJk > =AIQa > -----END PGP SIGNATURE----- > > -- > 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. > > I haven't analyzed your suggestion in detail Carl, but there is a good reason for managers to exist: querysets cache internally on iteration, managers are not directly evaluable, but were they you could end up doing something like: for instance in Model.objects: pass and you'd cache those results in global state. Alex -- "I disapprove of what you say, but I will defend to the death your right to say it." -- Evelyn Beatrice Hall (summarizing Voltaire) "The people's good is the highest law." -- Cicero -- 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.
