Q objects and the '&' operator in django
Asked Answered
S

2

11

I have a curious problem.

I have 3 objects. All the same

class Articles(models.Model):
    owner = models.ForeignKey(Author)
    tags = models.ManyToManyField('Tag')


class Tag(models.Model):
     name = models.CharField(max_length=255)

and so I have 3 Articles. With all the same tags: 'tag1' and 'tag2'

And I have queries

actionsAll = Articles.objects.filter((Q(tags__name__exact="tag1") | Q(tags__name__exact="tag2"))).distinct()

This gives me all my articles. It will return 6 articles w/o distinct() since it will collect each article 2x since they have both tags.

However with this query:

actionsAll = Articles.objects.filter((Q(tags__name__exact="tag1") & Q(tags__name__exact="tag2"))).distinct()

This gives me no articles. Since the articles contain both the tags, it should return them all shouldnt it?

Stomatology answered 24/12, 2010 at 0:43 Comment(4)
replacing | and & with keywords "or" and "and" it works just fine.Stomatology
or and and do very different things from | and &; don't try to use them as a replacement.Laundromat
well it works the way it should for me. Can you explain what is happening here then and why I shouldnt use it? The only thing that I needed to do to get my desired behavior was to use "and" for the union and "or" for the intersection which is backwards logic. I understand that you should think before replacing one for the other, but in my case my query works just as I want it to.Stomatology
and and or do not provide the "joining" into one query that & and | do; instead they return one of their operands based on their "trueness". It may work for the data you have, but as your data widens you'll find that there are logic errors in it.Laundromat
L
1

If you look at the SQL it generates, you'll see that it checks to see if the same tag has both names. What you need is an IN query or an EXISTS query that traverses the relation.

Laundromat answered 24/12, 2010 at 1:18 Comment(0)
S
1
** import Q from django
from *models import SuperUser, NameUser
import operator

# we do not know the name in the superhero
super_users = SuperUser.objects.all()
q_expressions = [Q(username=user.username) for user in super_users]
# we have bind super_hero with user
name_superheroes_qs = models.NameUser.objects.filter(reduce(operator.or_, q_expressions))
Seine answered 6/5, 2016 at 14:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.