Opened 21 months ago

Closed 21 months ago

Last modified 21 months 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, 21 months 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, 21 months ago

Thanks for explaining and the solution.

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