#33929: Field Reference in FilteredRelation Does Not Recognize Previously 
Defined
FilteredRelation
-------------------------------------+-------------------------------------
               Reporter:  Matt       |          Owner:  nobody
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  4.1
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 I suspect this may be the same root cause as
 https://code.djangoproject.com/ticket/33766, but the use-case here is
 different enough I thought I'd log a new ticket.

 All this is using Django 4.0 or 4.1, on PostgreSQL.  I confess that I have
 not checked if other DB layers might generate correct SQL.

 It appears that I cannot reference one FilteredRelation from another's
 condition without jumping through some hoops.  Starting with the following
 example models:
 {{{
 from django.db import models

 class A(models.Model):
     ...

 class B(models.Model):
     a = models.ForeignKey("A", on_delete=models.CASCADE)
     complete = models.BooleanField(default=False)

 class C(models.Model):
     a = models.ForeignKey("A", on_delete=models.CASCADE)
     b = models.OneToOneField("B", blank=True, null=True,
 on_delete=models.CASCADE)
     complete = models.BooleanField(default=False)
 }}}

 Now suppose that I want a count of incomplete B, and also incomplete C,
 but only when related to an incomplete B.
 If I were writing SQL myself, I’d write this as:
 {{{
 SELECT COUNT(b.id) as b_count, COUNT(c.id) as c_count
 FROM a
 LEFT JOIN b ON b.a_id = a.id AND NOT b.complete
 LEFT JOIN c ON c.a_id = a.id AND c.b_id = b.id AND NOT c.complete
 }}}

 Now, the below queryset very nearly works:
 {{{
 A.objects.annotate(
     binc=FilteredRelation("b", condition=Q(b__complete=False)),
     cinc=FilteredRelation("c", condition=Q(c__b=F("binc__pk"),
 c__complete=False)),
     b_count=Count("binc"),
     c_count=Count("cinc"),
 )
 }}}

 Unfortunately this uses an incorrect table alias into the `cinc`
 FilteredRelation, where I tried to reference `F("binc__pk")`.  If I try to
 execute it, I get
 {{{
 django.db.utils.ProgrammingError: missing FROM-clause entry for table "t4"
 LINE 1: ...("a"."id" = cinc."a_id" AND ((cinc."b_id" = (T4."id") A…
 }}}

 There is a workaround: I can force the correct identifier using RawSQL,
 and use this, which provides correct results:

 {{{
 A.objects.annotate(
     binc=FilteredRelation("b", condition=Q(b__complete=False)),
     cinc=FilteredRelation("c", condition=Q(c__b=RawSQL("binc.id", ()),
 c__complete=False)),
     b_count=Count("binc"),
     c_count=Count("cinc"),
 )
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33929>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-updates+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/01070182a91335db-7b51b27c-9705-47b7-aa12-0f00dab94898-000000%40eu-central-1.amazonses.com.

Reply via email to