In Django, Stuff.objects.filter(a=1).filter(b=1) is almost always the same as Stuff.objects.filter(a=1, b=1) .

Everyone knows and expects this, and it's very well documented.

However, Stuff.objects.filter(rel__a=1).filter(rel__b=1) might not be the same as Stuff.objects.filter(rel__a=1, rel__b=1) .

This is also very well documented, but in my option this behavior is not always intuitive.

Lets take an example:

class Tag ( models . Model ): name = models . CharField ( max_length = 100 ) class Entry ( models . Model ): tags = models . ManyToManyField ( Tag )

Now if we run Entry.objects.filter(tags__name='stuff') we'd get roughly something like:

SELECT `app_entry` . `id` FROM `app_entry` INNER JOIN `app_entry_tags` ON ( `app_entry` . `id` = `app_entry_tags` . `entry_id` ) INNER JOIN `app_tag` ON ( `app_entry_tags` . `tag_id` = `app_tag` . `id` ) WHERE `app_tag` . `name` = 'stuff'

If we run Entry.objects.filter(tags__name='stuff').filter(tags__name='other') we'd get roughly something like:

SELECT `app_entry` . `id` FROM `app_entry` INNER JOIN `app_entry_tags` ON ( `app_entry` . `id` = `app_entry_tags` . `entry_id` ) INNER JOIN `app_tag` ON ( `app_entry_tags` . `tag_id` = `app_tag` . `id` ) INNER JOIN `app_entry_tags` T4 ON ( `app_entry` . `id` = T4 . `entry_id` ) INNER JOIN `app_tag` T5 ON ( T4 . `tag_id` = T5 . `id` ) WHERE ( `app_tag` . `name` = 'stuff' AND T5 . `name` = 'other' )

Two JOIN is exactly what we wanted - a WHERE with a single JOIN wouldn't make sense anyway.