On Jun 1, 12:26 pm, Russell Keith-Magee <russ...@keith-magee.com> wrote: > Is this really something that's going to be able to be managed at the > routing level? It seems to me that the decision about exactly which > set of objects you want returned needs much finer control that a > router method will allow. > > It might not happen in your case specifically, but I wouldn't think it > would be unusual to have a single view in which both "full" list and > the "filtered" list are retrieved. If you're working with the managers > directly, that's easy: > > selected_canddiates = Candidate.objects.all() > all_candidates = Candidate.objects_all.all() > > but if you want to go through the relation for objects related to a > specific race, it's not: > > selected_canddiates = race.candidates.all() > all_candidates = race.candidates.all() # this won't give the right results... > > If I'm understanding your proposal correctly, I'd need to either tweak > the _state of race between the two calls to switch the context, or > write a router that was able to differentiate between the two uses > based on some other contextual cue (I'm not sure what could be > provided to give that differentiation, though). > > The context switching might be possible with some utility methods or a > Python context managers, but it still seems like the wrong way to > affect control -- modifying an object's state so that it's default > behaviour changes, rather than explicitly requesting the behaviour > your want. > > Here's a counter-proposal: > > mycandidate.races is a descriptor. That descriptor implements > __get__() to return a RelatedObjectsManager that does the appropriate > filtering. The related objects manager is a standard manager that > allows calls to all(), filter() etc. Why not also implement __call__, > and have __call__() return a new RelatedObjectsManager, bound to a > different manager (as named in the arguments to call)? > > So, using your example: > > * race.candidates.all() would use _default_manager > > * race.candidates('objects_all').all() would use the objects_all manager > > * race.candidates('objects').all() would also use _default_manager > (but explicitly) > > With some slightly neater manager naming, it becomes even easier to > read. Consider the following example: > > class Person(…): > people = Manager() > men = MaleManager() > women = FemaleManager() > > class Event(…): > attendees = ManyToMany(Person, related_name='events') > objects = Manager() > confirmed = ConfirmedManager() > > then: > > all people: Person.people.all() > all women: Person.women.all() > > all events: Event.objects.all() > all confirmed events: Event.confirmed.all() > > all events being attended by the Person frank: frank.events.all() > all confirmed events being attended by the Person frank: > frank.events('confirmed').all() > > all people attending the brogrammer event: brogrammer.attendees.all() > all men attending the brogrammer event: brogrammer.attendees('men').all() > > For my money, that's an explicit API that makes sense when reading the > single query line, and doesn't require the interpolation of extra > state/context from a router or some other context manager. It's also > backwards compatible, because there won't be any existing code > invoking __call__() on a manager. > > Russ %-)
+1. Just as a bike-shedding thought: Would it be possible to have frank.events.confirmed.all() as the syntax? I see this a tiny bit cleaner. On the other hand it isn't explicit you can only use the .confirmed only directly after the events, and there is the possibility of clashing with queryset methods. The clash issue can be solved by just using frank.events('clashing_name').all() instead of frank.events.clashing_name.all() in the rare cases this is needed. How would this work with prefetch_related? Maybe prefetch_related('events__confirmed')? IMHO this is an important use case, as there isn't currently any possibility to use different filtering, ordering etc than the one given by the default related manager. - Anssi -- You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@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.