Opened 2 years ago

Closed 2 years ago

Last modified 2 years ago

#33963 closed Bug (invalid)

Combining Q objects with empty querysets crashes.

Reported by: Bogumil Schube Owned by: nobody
Component: Database layer (models, ORM) Version: 4.1
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Working example with django 4.0

from django.db import models
from django.db.models import Q

class Test(models.Model):
   pass

out = Test.objects.none()
for a, b in [(1,1),(2,2),(3,3)]:
   out |= Q(a=a, b=b)

> out
> Out[23]: <Q: (OR: (AND: ('a', 1), ('b', 1)), (AND: ('a', 2), ('b', 2)), (AND: ('a', 3), ('b', 3)))>

In django 4.1 it's resulting in an AttributeError

site-packages/django/db/models/query.py:1951, in QuerySet._check_operator_queryset(self, other, operator_)
   1950 def _check_operator_queryset(self, other, operator_):
-> 1951     if self.query.combinator or other.query.combinator:
   1952         raise TypeError(f"Cannot use {operator_} operator with combined queryset.")

AttributeError: 'Q' object has no attribute 'query'

This error (or feature?) seems to come from #33127

Change History (2)

comment:1 by Mariusz Felisiak, 2 years ago

Resolution: invalid
Status: newclosed
Summary: Combining Q objectsCombining Q objects with empty querysets crashes.

Thanks for the report. As far as I'm aware combining querysets (empty or not) with Q() objects have never been officially supported, documented, or tests. This worked for empty querysets in Django 4.0, but accidentally and only due to the order of EmptyQuerySet guards. You should use Q() as the starting point for building dynamically Q objects, e.g.:

out = Q()
for a, b in [(1,1),(2,2),(3,3)]:
   out |= Q(a=a, b=b)

comment:2 by Bogumil Schube, 2 years ago

Thanks for explaining and the solution.

Note: See TracTickets for help on using tickets.
Back to Top