Got interested in this after a referral from the tricket tracker. Couldn't 
this specific case be solved with a simple change to __getattr__ on 
QuerySet?

 def __getattr__(self, attr):
     try:
         qmethod = getattr(self.manager, attr).im_func
         is_querymethod = qmethod.is_querymethod
     except AttributeError, exc:
         raise AttributeError(attr)

     if is_querymethod:
-        return curry(qmethod, self)
+        return curry(qmethod, self.manager)
     raise AttributeError(attr)

The only issue I see here is that it assumes self.manager is always defined 
so this would break if a QuerySet was instantiated outside of 
Manager.get_query_set(). But really, it doesn't make sense to add the 
@querymethod decorator on QuerySet functions anyway.

- Michael

Le jeudi 12 janvier 2012 09:05:57 UTC-5, Anssi Kääriäinen a écrit :
>
> On Jan 12, 2:24 pm, Zachary Voase <[email protected]> wrote: 
> > I strongly feel that switching around managers like that would be an 
> > example of overengineering. 
>
> I tend to over-engineer things. It is easy to add the manager 
> switching later on if needed. And it is easy to switch managers by 
> just changing qs.manager if really needed. So, I agree on leaving that 
> feature out. 
>
> > Here's the change I propose:
> https://github.com/zacharyvoase/django/compare/master...feature-query... 
> > 
> > It's very light for now, I'm not sure if there are other corner cases 
> > where it breaks, but it's the simplest thing that could possibly work, 
> > and it's conceptually very easy to understand. 
>
> And in the implementation I disagree. The implementation magically 
> changes what self references in querymethods. This will break any code 
> that wants to reference self in manager. For example: 
>
> def get_id_list_by_raw_sql(self, some_params): 
>     return cursor.execute("select if from sometable where someparam = 
> %s", (some_param,)) 
>
> @querymethod 
> def list_interesting_subjects(self, some_params): 
>     self.filter(id__in=self.get_id_list_by_raw_sql(some_params)) 
>
> Now, the above will work just fine if called through manager, but it 
> will not work if called through queryset, because self suddenly refers 
> to the qs, not to the manager. Depending how it is called. So, I would 
> suggest an approach like in my version, where self is always the 
> manager, and you get the queryset by self.get_query_set() (or maybe 
> with self.base_qs, which is a property returning either 
> self.get_query_set() or the queryset called from). 
>
> The main reason why I think it is a bad idea to "transfer" the method 
> to the qs is that if you do that, you will confuse people (what does 
> self refer to?), forbid some usecases, and gain exactly nothing by 
> doing that. And that can not be changed later on. Why not just let the 
> method be always bound to the manager instance? That is much cleaner. 
> This all assuming I actually understand what the patch does. Can't 
> test it currently... 
>
> Am I missing something that is gained by currying the method to 
> queryset instead of letting it be bound to the manager? 
>
> Still another idea is to somehow patch the parameters to the method in 
> querymethod, so that the queryset to chain to would be passed as a 
> parameter to the querymethod. It would either be self.get_query_set() 
> or the queryset called through. 
>
>  - Anssi


Le jeudi 12 janvier 2012 09:05:57 UTC-5, Anssi Kääriäinen a écrit :
>
> On Jan 12, 2:24 pm, Zachary Voase <[email protected]> wrote: 
> > I strongly feel that switching around managers like that would be an 
> > example of overengineering. 
>
> I tend to over-engineer things. It is easy to add the manager 
> switching later on if needed. And it is easy to switch managers by 
> just changing qs.manager if really needed. So, I agree on leaving that 
> feature out. 
>
> > Here's the change I propose:
> https://github.com/zacharyvoase/django/compare/master...feature-query... 
> > 
> > It's very light for now, I'm not sure if there are other corner cases 
> > where it breaks, but it's the simplest thing that could possibly work, 
> > and it's conceptually very easy to understand. 
>
> And in the implementation I disagree. The implementation magically 
> changes what self references in querymethods. This will break any code 
> that wants to reference self in manager. For example: 
>
> def get_id_list_by_raw_sql(self, some_params): 
>     return cursor.execute("select if from sometable where someparam = 
> %s", (some_param,)) 
>
> @querymethod 
> def list_interesting_subjects(self, some_params): 
>     self.filter(id__in=self.get_id_list_by_raw_sql(some_params)) 
>
> Now, the above will work just fine if called through manager, but it 
> will not work if called through queryset, because self suddenly refers 
> to the qs, not to the manager. Depending how it is called. So, I would 
> suggest an approach like in my version, where self is always the 
> manager, and you get the queryset by self.get_query_set() (or maybe 
> with self.base_qs, which is a property returning either 
> self.get_query_set() or the queryset called from). 
>
> The main reason why I think it is a bad idea to "transfer" the method 
> to the qs is that if you do that, you will confuse people (what does 
> self refer to?), forbid some usecases, and gain exactly nothing by 
> doing that. And that can not be changed later on. Why not just let the 
> method be always bound to the manager instance? That is much cleaner. 
> This all assuming I actually understand what the patch does. Can't 
> test it currently... 
>
> Am I missing something that is gained by currying the method to 
> queryset instead of letting it be bound to the manager? 
>
> Still another idea is to somehow patch the parameters to the method in 
> querymethod, so that the queryset to chain to would be passed as a 
> parameter to the querymethod. It would either be self.get_query_set() 
> or the queryset called through. 
>
>  - Anssi


Le jeudi 12 janvier 2012 09:05:57 UTC-5, Anssi Kääriäinen a écrit :
>
> On Jan 12, 2:24 pm, Zachary Voase <[email protected]> wrote: 
> > I strongly feel that switching around managers like that would be an 
> > example of overengineering. 
>
> I tend to over-engineer things. It is easy to add the manager 
> switching later on if needed. And it is easy to switch managers by 
> just changing qs.manager if really needed. So, I agree on leaving that 
> feature out. 
>
> > Here's the change I propose:
> https://github.com/zacharyvoase/django/compare/master...feature-query... 
> > 
> > It's very light for now, I'm not sure if there are other corner cases 
> > where it breaks, but it's the simplest thing that could possibly work, 
> > and it's conceptually very easy to understand. 
>
> And in the implementation I disagree. The implementation magically 
> changes what self references in querymethods. This will break any code 
> that wants to reference self in manager. For example: 
>
> def get_id_list_by_raw_sql(self, some_params): 
>     return cursor.execute("select if from sometable where someparam = 
> %s", (some_param,)) 
>
> @querymethod 
> def list_interesting_subjects(self, some_params): 
>     self.filter(id__in=self.get_id_list_by_raw_sql(some_params)) 
>
> Now, the above will work just fine if called through manager, but it 
> will not work if called through queryset, because self suddenly refers 
> to the qs, not to the manager. Depending how it is called. So, I would 
> suggest an approach like in my version, where self is always the 
> manager, and you get the queryset by self.get_query_set() (or maybe 
> with self.base_qs, which is a property returning either 
> self.get_query_set() or the queryset called from). 
>
> The main reason why I think it is a bad idea to "transfer" the method 
> to the qs is that if you do that, you will confuse people (what does 
> self refer to?), forbid some usecases, and gain exactly nothing by 
> doing that. And that can not be changed later on. Why not just let the 
> method be always bound to the manager instance? That is much cleaner. 
> This all assuming I actually understand what the patch does. Can't 
> test it currently... 
>
> Am I missing something that is gained by currying the method to 
> queryset instead of letting it be bound to the manager? 
>
> Still another idea is to somehow patch the parameters to the method in 
> querymethod, so that the queryset to chain to would be passed as a 
> parameter to the querymethod. It would either be self.get_query_set() 
> or the queryset called through. 
>
>  - Anssi

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/django-developers/-/3fyLDAVyDrIJ.
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.

Reply via email to