On Nov 6, 5:18 pm, Malcolm Tredinnick <[EMAIL PROTECTED]>
wrote:
> On the queryset-refactor branch, I've changed the way Q() objects are
> handled so that it will be easier to write your own variants on these.
> Basically, the Q-like object (by which I mean, any object you can pass
> to a filter() method) will have full access to the query that is being
> built and can add things to the where attribute and the columns and the
> tables and so on.
[...]
> I'm not quite sure how to do it yet, but one idea I'd like to implement
> is a way to more or less pass in a full Query object inside an object as
> part of a filter. It's not too hard -- it's already done for
> multi-column distinct counts, which need sub-queries on everything
> except MySQL. It's mostly a matter of working out the API. That might be
> post-merge work, though, since it's an addition and can be trialled
> without core modifications.

Since you're thinking about subqueries, I figured I'd share some
observations from my effort this evening to create a prototype
implementation of Q class that encapsulates an IN subquery expression
built from a QuerySet. I called this prototype class 'QIn'.

For example, a query expression such as

someuser = User.objects.get(uid=23423423)
qs =
User.objects.filter(friendship2_users__user1=mrf).exclude(QIn('uid',UserFilter.objects.filter(user=someuser,status='b'),'friend'))

results in the Django-generated query

SELECT ... FROM `fb_user` INNER JOIN `fb_friendship` AS
`fb_user__friendship2_users` ON `fb_user`.`uid` =
`fb_user__friendship2_users`.`user2_id` WHERE
(`fb_user__friendship2_users`.`user1_id` = 725912850 AND (NOT
(`fb_user`.`uid` IN (SELECT `discuss_userfilter`.`friend_id` FROM
`discuss_userfilter` WHERE (`discuss_userfilter`.`status` = b AND
`discuss_userfilter`.`user_id` = 725912850)))))

I haven't tested it exhaustively, but it seems to work on 0.96 with
MySQL 5.1.19-beta. The QIn can be applied in filter() and exclude(),
combined with AND, even nested. Should work with OR, too, but I
haven't tried that yet.

There are some significant limitations I wasn't able to eliminate in
this prototype, and it's probably useful to consider them in your
refactoring effort.

1. The field named as the first argument to QIn.__init__() must be
unabiguous within the scope of the primary model the outer query
('uid' refers to User.uid in the example). I only do a simple lookup
in the opts passed to get_sql().

2. The field named by the select keyword arg in QIn.__init() must be
unambiguous within the scope of the subquery ('friend' refers to the
foreign key UserFilter.friend in the example). I only do a simple
lookup using the model._meta attribute of the subquery.

3. The 'related_name__attr' syntax is not supported.

4. The subquery is not, strictly speaking, a correlated subquery since
it does not include any criteria that compare values in the subquery
table to those in the outer query.

I played around with a QExists() prototype, too, but it isn't really
useful without the ability to specify correlated criteria.

I took a hard look at the parse_lookup() and lookup_inner() functions
while trying to figure out how to eliminate these limitations, but
neither was really well suited to what I needed.

What is really needed is a contextual name resolver. For example, I
want to be able to call something like
context.resolve('related_name__attr') and get back a qualified column
expression. For subquery support, this context would be an argument
passed to get_sql() that resolves names relative to the enclosing
query. Similarly, QuerySet objects should have a resolver that I could
call to resolve names relative to a subquery.

If the contexts could be nested or chained, that would be even better!
For example, the subquery resolver would look first in the columns of
the subquery tables, then search the columns of the containing query.
I'm not sure what keyword-like syntax would appropriate for
disambiguating overlapping names, but that must be considered too
since tables in the subquery could have columns that overlap names in
the outer contex.


--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to