select_related additions

169 views
Skip to first unread message

David Cramer

unread,
Jul 30, 2007, 3:39:50 PM7/30/07
to Django developers
I have taken a bit of time to rewrite part of the QuerySet code
(including select_related). Please, no lectures about a QuerySet
refactoring.

The changes force .filter() to take advantage of select_related.

Before: .filter(mykey__name='Hello') would give you results, but if
you didn't do .select_related(depth=1) you would not have mykey in
memory.
After: it does :P

The changes also change select_related's args:
MyModel.objects.filter(mykey__name="hello").select_related('mykey__author')
will automatically join on mykey__author and keep it in memory.

The biggest thing this fixes is the SQL query optimization, previously
it would have done two JOINs on mykey's table, even if the SQL engine
optimized it, it's best to optimize it in the code.

This also letse you say
MyModel.objects.all().select_related('mykey__author') which will hold
both mykey, and mykey__author values in memory on the objects.

The depth argument still exists, so
MyModel.objects.all().select_related('mykey', depth=1). The result of
this query.. is nothing, because you implicitly set the fields to
"mykey". If however, you said select_related('mykey__author', depth=1)
it would not select on author, only on mykey, because that was
specified.

If people are willing to discuss, or accept this, I will patch SVN
with it. I will still most likely release the patch as I know a LOT of
people want the "fields" selector in select_related().

David Cramer

unread,
Aug 1, 2007, 12:17:39 PM8/1/07
to Django developers
I've submitted a ticket and attached part of the patch (the fields
selection on select_related): http://code.djangoproject.com/ticket/5020

Michael Radziej

unread,
Aug 1, 2007, 12:26:27 PM8/1/07
to django-d...@googlegroups.com
On Wed, Aug 01, David Cramer wrote:

>
> I've submitted a ticket and attached part of the patch (the fields
> selection on select_related): http://code.djangoproject.com/ticket/5020

Funny, I'm working on something similar.

I don't understand how the new API looks like, and particularily how this
could work:

def select_related(self, *args, **kwargs):
...
return self._clone(_select_related=true_or_false,
_max_related_depth=depth, _recurse_fields=fields)

I don't see how `fields` gets populated. Can you please help with a
pointer?

Michael


--
noris network AG - Deutschherrnstraße 15-19 - D-90429 Nürnberg -
Tel +49-911-9352-0 - Fax +49-911-9352-100
http://www.noris.de - The IT-Outsourcing Company

Vorstand: Ingo Kraupa (Vorsitzender), Joachim Astel, Hansjochen Klenk -
Vorsitzender des Aufsichtsrats: Stefan Schnabel - AG Nürnberg HRB 17689

David Cramer

unread,
Aug 1, 2007, 8:12:40 PM8/1/07
to Django developers
Seems I slipped in the diff. I have to actually apply the patch to at
least 2 different versions of Django with our current setup, can get
tedious :P

*args should be *fields :)

On Aug 1, 9:26 am, Michael Radziej <m...@noris.de> wrote:
> On Wed, Aug 01, David Cramer wrote:
>
> > I've submitted a ticket and attached part of the patch (the fields
> > selection on select_related):http://code.djangoproject.com/ticket/5020
>
> Funny, I'm working on something similar.
>
> I don't understand how the new API looks like, and particularily how this
> could work:
>
> def select_related(self, *args, **kwargs):
> ...
> return self._clone(_select_related=true_or_false,
> _max_related_depth=depth, _recurse_fields=fields)
>
> I don't see how `fields` gets populated. Can you please help with a
> pointer?
>
> Michael
>
> --
> noris network AG - Deutschherrnstraße 15-19 - D-90429 Nürnberg -

> Tel +49-911-9352-0 - Fax +49-911-9352-100http://www.noris.de- The IT-Outsourcing Company

Michael Radziej

unread,
Aug 2, 2007, 5:28:45 AM8/2/07
to django-d...@googlegroups.com
On Thu, Aug 02, David Cramer wrote:

>
> Seems I slipped in the diff. I have to actually apply the patch to at
> least 2 different versions of Django with our current setup, can get
> tedious :P
>
> *args should be *fields :)

;-)

Well, for the deeper levels, is there a way to express "follow
myforeignkey__user recursively" and also "follow myforeignkey__user, but no
deeper" without using the depth parameter (because you might want to follow
to different depths in different foreign keys)?

Michael

--
noris network AG - Deutschherrnstraße 15-19 - D-90429 Nürnberg -
Tel +49-911-9352-0 - Fax +49-911-9352-100

http://www.noris.de - The IT-Outsourcing Company

David Cramer

unread,
Aug 2, 2007, 11:22:20 AM8/2/07
to Django developers
This was my best solution. I honestly wouldnt ever encourage anything
where you dont specify which foreignkeys to follow. JOINs can get very
slow when they expand beyond 2 or 3 tables, especially when table
sizes increase.

On Aug 2, 2:28 am, Michael Radziej <m...@noris.de> wrote:
> On Thu, Aug 02, David Cramer wrote:
>
> > Seems I slipped in the diff. I have to actually apply the patch to at
> > least 2 different versions of Django with our current setup, can get
> > tedious :P
>
> > *args should be *fields :)
>
> ;-)
>
> Well, for the deeper levels, is there a way to express "follow
> myforeignkey__user recursively" and also "follow myforeignkey__user, but no
> deeper" without using the depth parameter (because you might want to follow
> to different depths in different foreign keys)?
>
> Michael
>
> --
> noris network AG - Deutschherrnstraße 15-19 - D-90429 Nürnberg -

> Tel +49-911-9352-0 - Fax +49-911-9352-100http://www.noris.de- The IT-Outsourcing Company

Michael Radziej

unread,
Aug 2, 2007, 11:54:48 AM8/2/07
to django-d...@googlegroups.com
On Thu, Aug 02, David Cramer wrote:

>
> This was my best solution. I honestly wouldnt ever encourage anything
> where you dont specify which foreignkeys to follow. JOINs can get very
> slow when they expand beyond 2 or 3 tables, especially when table
> sizes increase.

Agreed ;-) I even think the max_depth argument should be removed, it doesn't
really make sense.

I have something similar that is able to correctly generate outer joins for
nullable foreign keys. It's currently only for my use since it's probably
mysql only, and it can't correctly nest joins if you need an inner join to
an outer join (hope this makes sense to you). It's also written for a
different API (but I prefer your idea).

I've attached it for a quick look, are you interested in joining our
efforts?

Michael

--
noris network AG - Deutschherrnstraße 15-19 - D-90429 Nürnberg -
Tel +49-911-9352-0 - Fax +49-911-9352-100

http://www.noris.de - The IT-Outsourcing Company

select_related.diff
Reply all
Reply to author
Forward
0 new messages