#29545: Nested OuterRef not looking on the right model for the field.
-------------------------------------+-------------------------------------
     Reporter:  pwfff                |                    Owner:  nobody
         Type:  Bug                  |                   Status:  new
    Component:  Database layer       |                  Version:  2.0
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:  outerref, subquery   |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Description changed by pwfff:

Old description:

> I ran into this and made a test case for it. It seems similar to the test
> case above it. I'm not sure what's different about it and causing it to
> fail.
>
> Let me know if the query is just build wrong.
>
> {{{
> diff --git a/tests/expressions/models.py b/tests/expressions/models.py
> index 42e4a37bb0..164bda3b3d 100644
> --- a/tests/expressions/models.py
> +++ b/tests/expressions/models.py
> @@ -83,6 +83,28 @@ class SimulationRun(models.Model):
>          return "%s (%s to %s)" % (self.midpoint, self.start, self.end)
>

> +class Customer(models.Model):
> +    name = models.TextField()
> +
> +
> +class Item(models.Model):
> +    pass
> +
> +
> +class Invoice(models.Model):
> +    INVOICE = 'invoice'
> +    EXPENSE = 'expense'
> +
> +    KIND_CHOICES = (
> +        (INVOICE, 'Invoice'),
> +        (EXPENSE, 'Expense'),
> +    )
> +
> +    kind = models.CharField(choices=KIND_CHOICES, max_length=255,
> default=None)
> +    owner = models.ForeignKey(Customer, models.CASCADE)
> +    items = models.ManyToManyField(Item, related_name='invoices')
> +
> +
>  class UUIDPK(models.Model):
>      id = models.UUIDField(primary_key=True, default=uuid.uuid4)
>
> diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py
> index d1e622a2d4..2c50744fc8 100644
> --- a/tests/expressions/tests.py
> +++ b/tests/expressions/tests.py
> @@ -24,7 +24,7 @@ from django.test.utils import Approximate
>
>  from .models import (
>      UUID, UUIDPK, Company, Employee, Experiment, Number, Result,
> SimulationRun,
> -    Time,
> +    Time, Customer, Item, Invoice
>  )
>

> @@ -536,6 +536,55 @@ class BasicExpressionsTests(TestCase):
>          # This is a contrived example. It exercises the double OuterRef
> form.
>          self.assertCountEqual(outer, [first, second, third])
>
> +    def test_nested_subquery_outer_ref_3(self):
> +        customer = Customer.objects.create(name='Test Customer')
> +        other_customer = Customer.objects.create(name='Ohter Customer')
> +
> +        unexpensed_invoice =
> Invoice.objects.create(kind=Invoice.INVOICE, owner=customer)
> +        unexpensed_item_1 = Item.objects.create()
> +        unexpensed_invoice.items.add(unexpensed_item_1)
> +
> +        partially_expensed_invoice =
> Invoice.objects.create(kind=Invoice.INVOICE, owner=customer)
> +        expense_1 = Invoice.objects.create(kind=Invoice.EXPENSE,
> owner=customer)
> +        expensed_item_1 = Item.objects.create()
> +        unexpensed_item_2 = Item.objects.create()
> +        partially_expensed_invoice.items.add(expensed_item_1,
> unexpensed_item_2)
> +        expense_1.items.add(expensed_item_1)
> +
> +        expensed_invoice = Invoice.objects.create(kind=Invoice.INVOICE,
> owner=customer)
> +        Invoice.objects.create(kind=Invoice.EXPENSE, owner=customer)
> +        expensed_item_2 = Item.objects.create()
> +        expensed_invoice.items.add(expensed_item_2)
> +        expense_1.items.add(expensed_item_2)
> +
> +        other_invoice = Invoice.objects.create(kind=Invoice.INVOICE,
> owner=other_customer)
> +        other_invoice.items.add(unexpensed_item_1)
> +        other_expense = Invoice.objects.create(kind=Invoice.EXPENSE,
> owner=other_customer)
> +        other_expense.items.add(unexpensed_item_1)
> +
> +        inner = Invoice.objects.filter(
> +            kind=Invoice.EXPENSE,
> +            owner=OuterRef(OuterRef('owner')),
> +            items=OuterRef('id'),
> +        )
> +        middle = Item.objects.filter(
> +            invoices=OuterRef('id'),
> +        ).annotate(
> +            expensed=Exists(inner),
> +        ).filter(
> +            expensed=False,
> +        )
> +        outer = Invoice.objects.filter(
> +            kind=Invoice.INVOICE,
> +            owner=customer,
> +        ).annotate(
> +            unexpensed=Exists(middle),
> +        )
> +
> +        self.assertTrue(outer.get(pk=unexpensed_invoice.pk).unexpensed)
> +
> self.assertTrue(outer.get(pk=partially_expensed_invoice.pk).unexpensed)
> +        self.assertFalse(outer.get(pk=expensed_invoice.pk).unexpensed)
> +
>      def test_nested_subquery_outer_ref_with_autofield(self):
>          first = Time.objects.create(time='09:00')
>          second = Time.objects.create(time='17:00')
> }}}
>
> {{{
> django.core.exceptions.FieldError: Cannot resolve keyword 'owner' into
> field. Choices are: expensed, id, invoices
> }}}

New description:

 I ran into this and made a test case for it. It seems similar to the test
 case above it. I'm not sure what's different about it and causing it to
 fail.

 Let me know if the query is just built wrong.

 {{{
 diff --git a/tests/expressions/models.py b/tests/expressions/models.py
 index 42e4a37bb0..164bda3b3d 100644
 --- a/tests/expressions/models.py
 +++ b/tests/expressions/models.py
 @@ -83,6 +83,28 @@ class SimulationRun(models.Model):
          return "%s (%s to %s)" % (self.midpoint, self.start, self.end)


 +class Customer(models.Model):
 +    name = models.TextField()
 +
 +
 +class Item(models.Model):
 +    pass
 +
 +
 +class Invoice(models.Model):
 +    INVOICE = 'invoice'
 +    EXPENSE = 'expense'
 +
 +    KIND_CHOICES = (
 +        (INVOICE, 'Invoice'),
 +        (EXPENSE, 'Expense'),
 +    )
 +
 +    kind = models.CharField(choices=KIND_CHOICES, max_length=255,
 default=None)
 +    owner = models.ForeignKey(Customer, models.CASCADE)
 +    items = models.ManyToManyField(Item, related_name='invoices')
 +
 +
  class UUIDPK(models.Model):
      id = models.UUIDField(primary_key=True, default=uuid.uuid4)

 diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py
 index d1e622a2d4..2c50744fc8 100644
 --- a/tests/expressions/tests.py
 +++ b/tests/expressions/tests.py
 @@ -24,7 +24,7 @@ from django.test.utils import Approximate

  from .models import (
      UUID, UUIDPK, Company, Employee, Experiment, Number, Result,
 SimulationRun,
 -    Time,
 +    Time, Customer, Item, Invoice
  )


 @@ -536,6 +536,55 @@ class BasicExpressionsTests(TestCase):
          # This is a contrived example. It exercises the double OuterRef
 form.
          self.assertCountEqual(outer, [first, second, third])

 +    def test_nested_subquery_outer_ref_3(self):
 +        customer = Customer.objects.create(name='Test Customer')
 +        other_customer = Customer.objects.create(name='Ohter Customer')
 +
 +        unexpensed_invoice = Invoice.objects.create(kind=Invoice.INVOICE,
 owner=customer)
 +        unexpensed_item_1 = Item.objects.create()
 +        unexpensed_invoice.items.add(unexpensed_item_1)
 +
 +        partially_expensed_invoice =
 Invoice.objects.create(kind=Invoice.INVOICE, owner=customer)
 +        expense_1 = Invoice.objects.create(kind=Invoice.EXPENSE,
 owner=customer)
 +        expensed_item_1 = Item.objects.create()
 +        unexpensed_item_2 = Item.objects.create()
 +        partially_expensed_invoice.items.add(expensed_item_1,
 unexpensed_item_2)
 +        expense_1.items.add(expensed_item_1)
 +
 +        expensed_invoice = Invoice.objects.create(kind=Invoice.INVOICE,
 owner=customer)
 +        Invoice.objects.create(kind=Invoice.EXPENSE, owner=customer)
 +        expensed_item_2 = Item.objects.create()
 +        expensed_invoice.items.add(expensed_item_2)
 +        expense_1.items.add(expensed_item_2)
 +
 +        other_invoice = Invoice.objects.create(kind=Invoice.INVOICE,
 owner=other_customer)
 +        other_invoice.items.add(unexpensed_item_1)
 +        other_expense = Invoice.objects.create(kind=Invoice.EXPENSE,
 owner=other_customer)
 +        other_expense.items.add(unexpensed_item_1)
 +
 +        inner = Invoice.objects.filter(
 +            kind=Invoice.EXPENSE,
 +            owner=OuterRef(OuterRef('owner')),
 +            items=OuterRef('id'),
 +        )
 +        middle = Item.objects.filter(
 +            invoices=OuterRef('id'),
 +        ).annotate(
 +            expensed=Exists(inner),
 +        ).filter(
 +            expensed=False,
 +        )
 +        outer = Invoice.objects.filter(
 +            kind=Invoice.INVOICE,
 +            owner=customer,
 +        ).annotate(
 +            unexpensed=Exists(middle),
 +        )
 +
 +        self.assertTrue(outer.get(pk=unexpensed_invoice.pk).unexpensed)
 +
 self.assertTrue(outer.get(pk=partially_expensed_invoice.pk).unexpensed)
 +        self.assertFalse(outer.get(pk=expensed_invoice.pk).unexpensed)
 +
      def test_nested_subquery_outer_ref_with_autofield(self):
          first = Time.objects.create(time='09:00')
          second = Time.objects.create(time='17:00')
 }}}

 {{{
 django.core.exceptions.FieldError: Cannot resolve keyword 'owner' into
 field. Choices are: expensed, id, invoices
 }}}

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/29545#comment:1>
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 post to this group, send email to django-updates@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/063.9df82859e80f812088be137890064130%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to