#36481: UpdateQuery.add_update_values always computes "direct" variable as True
-------------------------------------+-------------------------------------
Reporter: Ryan P Kilby | Type: Bug
Status: new | Component: Database
| layer (models, ORM)
Version: 5.2 | Severity: Normal
Keywords: | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
For context, I've been messing around with `ForeignObject` in an attempt
to use correlated subqueries as a join condition. e.g., defining a
`latest_post` relation field that enables queries like
`Author.objects.select_related("latest_post")`. Given that the relation is
based on a subquery, the field is not concrete, and in testing how the
queryset API works with this field, I ran into a confusing condition in
`QuerySet.update` via the `UpdateQuery.add_update_values` method. In
short,
[[
https://github.com/django/django/blob/5.2.3/django/db/models/sql/subqueries.py#L90|line
90]] computes a `direct` variable that always resolves to true. You can
verify how the boolean logic resolves with:
{{{#!python
class UpdateTests(unittest.TestCase):
def test_direct(self):
testcases = [
(True, True),
(True, False),
(False, True),
(False, False),
]
for auto_created, concrete in testcases:
with self.subTest(auto_created=auto_created,
concrete=concrete):
self.assertTrue(not (auto_created and not concrete) or not
concrete)
}}}
This condition should simplify to `not auto_created or concrete or not
concrete` to `concrete or not concrete` to `True`. Digging through the
blame, direct was previously provided by the model meta's
`.get_field_by_name()`, which
[[
https://github.com/django/django/blob/749d23251bbd6564341405e6f8c1da129b8307e7/django/db/models/options.py#L410-L411|states]]
"direct is True if the field exists on this model". Without fully
understanding the field internals, I assume `direct` should have been
replaced with just `field.concrete`. I'm not sure what the intent was for
auto-created fields, but whether it's concrete seems to be the actual
relevant bit, not whether it's auto-created.
--
Ticket URL: <
https://code.djangoproject.com/ticket/36481>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.