xssChauhan
xssChauhan

Reputation: 2858

Equality of Django's Q objects

I am trying to compare django's Q objects which are composed in the exact same way.

But despite all children and relations between them being same, they aren't deemed equal.

from django.db.models import Q

$ q1 = Q(a=1) & Q(b=1) & Q(c=1)

$ q2 = Q(a=1) & Q(b=1) & Q(c=1)

$ q1 == q2

$ False

This is posing problems in my unit tests where I build up filters for my querysets using Q objects.

Why are the two Q objects not equal?

I am using Django 1.11.

Upvotes: 4

Views: 994

Answers (2)

t354
t354

Reputation: 617

I built on xssChauhan's answer to handle the case where you have nested Q objects:

def compare_Qs(Q1, Q2):
    if hasattr(Q1, 'children') and hasattr(Q2, 'children'):
        if (Q1.__class__ == Q2.__class__) and ((Q1.connector, Q1.negated)
            == (Q2.connector, Q2.negated)) and (len(Q1.children) ==
            len(Q2.children)):
            result = [compare_Qs(Q1.children[i], Q2.children[i]) for i in
                range(len(Q1.children))]
            return all(result)
    return (Q1 == Q2)

Upvotes: 2

xssChauhan
xssChauhan

Reputation: 2858

Django <= 1.11.x does not implement __eq__ method for Q objects. As can be seen here.

Django >= 2.0 implements __eq__ method for Q objects. Code.

So it is not possible to directly check the equality of two Q objects before Django 2.0.

But it is possible to write a simple function that checks the equality of Q objects. We can directly use the code from the repo.

def compare_q(q1 , q2):
        return (
            q1.__class__ == q2.__class__ and
            (q1.connector, q1.negated) == (q2.connector, q2.negated) and
            q1.children == q2.children
        )

So, for older versions of Django we can do:

$ compare_q(q1 , q2)

$ True

Upvotes: 6

Related Questions