#30379: ProgrammingError from exclude using models.F with long relation
-------------------------------------+-------------------------------------
Reporter: | Owner: nobody
PeterJCLaw |
Type: Bug | Status: new
Component: Database | Version: 2.2
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 |
-------------------------------------+-------------------------------------
The following query emits a `ProgrammingError` due to the query omitting
the definitions of a number of references it uses:
{{{#!python
Alert.objects.exclude(
item__order_items__order__user=models.F('user'),
)
}}}
{{{
django.db.utils.ProgrammingError: missing FROM-clause entry for table "u2"
}}}
The spelling using a specific user does seem to work correctly, hinting
that the issue is somehow related to the handling of the `models.F`
component.
{{{#!python
Alert.objects.exclude(
item__order_items__order__user=the_user,
)
}}}
Models:
{{{#!python
from django.db import models
class Item(models.Model):
name = models.TextField()
class Order(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
class UnsizedOrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE,
related_name='items')
item = models.ForeignKey(Item, on_delete=models.CASCADE,
related_name='order_items')
class Alert(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
item = models.ForeignKey(Item, on_delete=models.CASCADE,
related_name='alerts')
}}}
I originally saw this with another layer of many-to-many between the item
and the order, but that turned out not to be necessary to reproduce the
issue:
{{{#!python
class SizedItem(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE,
related_name='sizes')
size = models.TextField()
class SizedOrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE,
related_name='sized_items')
sized_item = models.ForeignKey(SizedItem, on_delete=models.CASCADE,
related_name='sized_order_items')
Alert.objects.exclude(
item__sizes__sized_order_items__order__user=models.F('user'),
)
}}}
Traceback:
{{{
File ".../lib/python3.5/site-packages/django/db/models/query.py", line
55, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch,
chunk_size=self.chunk_size)
File ".../lib/python3.5/site-packages/django/db/models/sql/compiler.py",
line 1097, in execute_sql
cursor.execute(sql, params)
File ".../lib/python3.5/site-
packages/sentry_sdk/integrations/django/__init__.py", line 298, in execute
return real_execute(self, sql, params)
File "/home/peter-thread/thread/styleme/styleme/graphql/metrics.py",
line 112, in wrapper
return fn(wrapped_self, *args, **kwargs)
File ".../lib/python3.5/site-packages/django/db/backends/utils.py", line
67, in execute
return self._execute_with_wrappers(sql, params, many=False,
executor=self._execute)
File ".../lib/python3.5/site-packages/django/db/backends/utils.py", line
76, in _execute_with_wrappers
return executor(sql, params, many, context)
File ".../lib/python3.5/site-packages/django/db/backends/utils.py", line
84, in _execute
return self.cursor.execute(sql, params)
File ".../lib/python3.5/site-packages/django/db/utils.py", line 89, in
__exit__
raise dj_exc_value.with_traceback(traceback) from exc_value
File ".../lib/python3.5/site-packages/django/db/backends/utils.py", line
84, in _execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: missing FROM-clause entry for table "u2"
LINE 1: ...JOIN "liked_email_alerts_unsizedorderitem" U3 ON (U2."id" = ...
^
}}}
Versions:
* I've seen this under both 2.1.7 and 2.2
* I'm using Python 3.5.2
* I'm using Postgres 9.6 (psycopg2-binary==2.7.7)
For reference here's the SQL generated by printing the `.query` on the
querysets:
{{{#!sql
-- relative
SELECT
"liked_email_alerts_alert"."id",
"liked_email_alerts_alert"."user_id",
"liked_email_alerts_alert"."item_id"
FROM
"liked_email_alerts_alert"
WHERE
NOT ("liked_email_alerts_alert"."item_id" IN (
SELECT
U3. "item_id"
FROM
"liked_email_alerts_alert" U0
INNER JOIN "liked_email_alerts_unsizedorderitem" U3 ON
(U2. "id" = U3. "item_id")
INNER JOIN "liked_email_alerts_order" U4 ON (U3.
"order_id" = U4. "id")
WHERE
U4. "user_id" = (U0. "user_id")));
-- specific
SELECT
"liked_email_alerts_alert"."id",
"liked_email_alerts_alert"."user_id",
"liked_email_alerts_alert"."item_id"
FROM
"liked_email_alerts_alert"
WHERE
NOT ("liked_email_alerts_alert"."item_id" IN (
SELECT
U2. "item_id"
FROM
"liked_email_alerts_unsizedorderitem" U2
INNER JOIN "liked_email_alerts_order" U3 ON (U2.
"order_id" = U3. "id")
WHERE
U3. "user_id" = 13))
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/30379>
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 [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/053.e60650569edc3510fc66b7f458ad0bff%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.