On Fri, 2008-11-14 at 08:10 -0800, David Elias wrote:
> I'm using with Django 0.96 a custom Q object to make joins between
> models, here's an example:
> 
> class Product(models.Model):
>     group = models.IntegerField() # primary key
>     code = models.CharField() # primary key
>     name = models.CharField()
>     ...
> 
> class CartItem(models.Model):
>     product_group = models.IntegerField() # product foreign key
>     product_code = models.CharField() # product foreign key
>     quantity = models.IntegerField()
>     ...
> 
> 
> items = CartItem.objects.filter(
>     QJoin(Product, 'p', Q(group='product_group',
> code='product_code'))).extra(
>         select={
>             'p.name': 'product__name'
>         })
> 
> for this to work i've translated this:
>     "Q(group='product_group', code='product_code')"
> 
> into this:
>     "ON (cartitem.product_group=p.group AND
> cartitem.product_code=p.code)"
> 
> taking advantage of django.db.models.quey.Query._get_sql_clause
> method:
>     if joins:
>             sql.append(" ".join(["%s %s %s ON %s" % (join_type, table,
> alias, condition)
>                             for (alias, (table, join_type, condition))
> in joins.items()]))
> 
> Now on the new django.db.models.sql.query.BaseQuery i can add new
> joins with the "join" method, but on "get_from_clause" the joins
> construction does not allow me to construct a join on multiple
> columns, here's the code from this method:
>     if join_type and not first:
>         result.append('%s %s%s ON (%s.%s = %s.%s)'
>                         % (join_type, qn(name), alias_str, qn(lhs),
>                            qn2(lhs_col), qn(alias), qn2(col)))
> 
> The solution i can think of is to subclass de BaseQuery and overwrite
> the "get_from_clause" method.

It rapidly becomes almost unmanageable to put all join conditions into
the FROM clause, particularly once you start doing combinations with
both conjunctions and disjunctions. Fortunately, there is always a
logically equivalent query that doesn't use "ON", but uses "WHERE"
constraints. In fact, the database optimiser will convert the "ON"
constraints to equivalent WHERE constraints in most situations, since it
allows for more possibilities in join reordering. Django does similar
things internally and uses WHERE constraints predominantly.

At some point in the future, multi-valued ON constraints might make an
appearance (for example, multi-column primary key queries are possibly
easier to write), but they might not, too. The slight preference for
doing so at some point is that there are a couple of cases on some
databases where join constraints are handled more efficiently than where
constraints. That's really sub-optimal behaviour in the database
optimisers and it's sufficiently an edge case that we haven't done
anything about it yet, but it might happen one day in the future.

The easiest solution to your problem is to rewrite your query
construction to put the second constraint into the WHERE clause (via
add_filter(), for example). You might also need to add a comparison to
NULL if there's an outer join involved. See [1] -- a couple of
paragraphs into the section headed "The Where tree" -- for why that's
necessary.

[1] http://www.pointy-stick.com/blog/2008/03/11/queryset-implementation/

Regards,
Malcolm



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To post to this group, send email to django-users@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/django-users?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to