The assertions are just saying what the current behavior of the ORM is. Under the hood, it's because Q(m2ms__int_value=10) & Q(m2ms__char_value='bar') is equivalent to Q(m2ms__int_value=10, m2ms__char_value='bar') and a single join to the m2ms table (not including the through table) is created:
SELECT "testapp_testobj"."id"
FROM "testapp_testobj"
INNER JOIN "testapp_testobj_m2ms"
ON ("testapp_testobj"."id" = "testapp_testobj_m2ms"."testobj_id")
INNER JOIN "testapp_m2mmodel"
ON ("testapp_testobj_m2ms"."m2mmodel_id" = "testapp_m2mmodel"."id")
WHERE ("testapp_m2mmodel"."int_value" = 10
AND "testapp_m2mmodel"."char_value" = bar)
The conditions in the WHERE clause must apply to the same row in the join, so it only matches when the same row in the m2m table matches both conditions simultaneously.
I think that's a reasonable way to make the ORM behave, espeically since it's been pretty long standing behavior. You certainly could give Q(foo=1, bar=2) a different meaning than Q(foo=1) & Q(bar=2), though at this point that would be a big break with pre-existing behavior. Given that behavior, it seems counterintuitive to not obey logical invariants like De Morgan's law.
I've definitely seen that in trying to build a library to mimmick its behavior! Thanks for the links. I'll read through those pull requests and file a trac ticket if they don't clarify my question. If the determination from Anssi is that altering the current behavior is desirable/feasibl, I'll start working on a patch. Thanks very much, Tim!
- Lucas