Opened 3 months ago

Closed 3 months ago

#31397 closed New feature (duplicate)

Support qs.filter(related=Q(...)).

Reported by: Roman Odaisky Owned by: nobody
Component: Database layer (models, ORM) Version: 3.0
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

It would be very helpful to be able to use Q objects with related models, especially if some other code generates the Q objects. Use case:

def bestsellers(q):
    qs = Author.objects.filter(q).annotate(total_sold=Sum("book__n_sold"))
    ...

Suppose that later the calculations become so complex that they can’t be expressed in terms of aggregate functions, thus Python code has to be written instead, and the queryset changes models:

def bestsellers(q):  # q still contains fields from the Author model
    qs = Book.objects.filter(???)
    for book in qs:
        ...

It would be natural to try to write Book.objects.filter(author=q), but this syntax isn’t supported.

I suggest that Q(model=Q(a=b, c=d)) be allowed with the same effect as Q(model__a=b, model__c=d) (recursively if the inner Q is nested).

The implementation does not seem to be particularly complex. This function does most of the work:

def prefix_q(prefix, q):
    """ Q(prefix=q) === prefix_q(prefix, q) """
    if isinstance(q, tuple):
        return (prefix + "__" + q[0], q[1])

    return Q(*[prefix_q(prefix, c) for c in q.children],
        _connector=q.connector, _negated=q.negated)

Change History (1)

comment:1 Changed 3 months ago by felixxm

Resolution: duplicate
Status: newclosed
Summary: Support qs.filter(related=Q(...))Support qs.filter(related=Q(...)).

Duplicate of #16979.

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