On May 23, 11:43 am, akaariai <
akaar...@gmail.com> wrote:
> I would guess you would get duplicate objects returned.
We programmers are usually very bad at guessing. So when in doubt,
check, don't guess ;)
> I think the
> query works as follows:
> - Fetch all Blook's categories
> - For those categories you fetch all the classifications (not only
> those which are related to Blook) and order by the position in there.
Not quite - cf the generated SQL below.
> So, you could get the same category multiple times ordered by
> positions not related to the blook <-> category connection.
That's not the case. Demonstration:
First, check that we do have categories shared by multiples blooks
(else it wouldn't mean much):
>>> for blook in blooks:
... print blook, blook.categories.order_by("id").values_list("id",
flat=True)
...
#139 [533L, 534L, 535L, 536L, 537L, 538L, 539L, 540L, 541L, 542L,
543L, 544L, 545L, 546L, 547L]
#129 [534L, 535L, 537L, 539L, 540L, 542L, 543L, 544L, 545L, 546L,
547L]
#128 [534L]
#126 [533L, 534L, 535L, 536L, 537L, 538L, 539L, 540L, 541L, 542L,
543L, 544L, 545L, 546L, 547L]
#127 [533L, 534L, 535L, 536L, 537L, 538L, 539L, 540L, 541L, 542L,
543L, 544L, 545L, 546L, 547L]
#118 [534L]
Now check that for each blook, we have the same categories whether
sorted or unsorted:
>>> for blook in blooks:
... cats = blook.categories.all()
... scats = blook.sorted_categories
... assert set(cats) == set(scats), "OOPS ??? %s" % blook
...
Well... No AssertionError raised, so it's correct.
> Maybe the above code does work correctly.
It does.
Custom ordering is possibly one of the most common use case for
"through" m2ms, so you can bet it works - else there would have been
quite some criticism about it ;)
> The interaction between
> multiple references to same reverse foreign key relation in single
> queryset is somewhat hard to remember. Could you post the generated
> SQL?
here you go - reformated for readability:
SELECT
`blookcore_category`.`id`,
`blookcore_category`.`label`
FROM
`blookcore_category`
LEFT OUTER JOIN `blookcore_classification`
ON (`blookcore_category`.`id` =
`blookcore_classification`.`category_id`)
WHERE
`blookcore_classification`.`blook_id` = 118
ORDER BY
`blookcore_classification`.`position` ASC
I don't quite get why it uses a left outer join instead of the inner
join used when not adding the order by clause, but writing a working,
usable ORM is not exactly a piece of cake so I won't complain about
this ;). Anyway: the where clause still makes sure we only get the
relevant categories.
HTH