#36530: System check for ManyToManyField & Composite Primary Key checks only one
direction
-------------------------------------+-------------------------------------
Reporter: Jacob Walls | Type: Bug
Status: new | Component: Database
| layer (models, ORM)
Version: 5.2 | Severity: Release
| blocker
Keywords: compositeprimarykey | Triage Stage:
| Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 1 | UI/UX: 0
-------------------------------------+-------------------------------------
#36034 added the system check E347 for `ManyToManyField` when the
"to_model" has a composite pk, but the situation is just as unsupported
when the composite primary key model is the "from_model", i.e. the one
with *both* the `ManyToManyField` and the `CompositePrimaryKey`.
We should be able to just adjust
[
https://github.com/django/django/blob/45ba7683a6e399815731a13cceb3acb518a2f1f2/django/db/models/fields/related.py#L1544
this system check condition] to check the "from" table also.
----
e.g. this (purely for demo, not suggesting we edit this test model):
{{{#!diff
diff --git a/tests/composite_pk/models/tenant.py
b/tests/composite_pk/models/tenant.py
index 65eb0feae8..ef777edff9 100644
--- a/tests/composite_pk/models/tenant.py
+++ b/tests/composite_pk/models/tenant.py
@@ -60,3 +60,4 @@ class TimeStamped(models.Model):
id = models.SmallIntegerField(unique=True)
created = models.DateTimeField(auto_now_add=True)
text = models.TextField(default="", blank=True)
+ tenants = models.ManyToManyField(Tenant)
}}}
gives:
{{{#!py
ERROR: test_serialize_datetime
(composite_pk.tests.CompositePKFixturesTests.test_serialize_datetime)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/jwalls/django/tests/composite_pk/tests.py", line 368, in
test_serialize_datetime
result = serializers.serialize("json", TimeStamped.objects.all())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jwalls/django/django/core/serializers/__init__.py", line
134, in serialize
s.serialize(queryset, **options)
File "/Users/jwalls/django/django/core/serializers/base.py", line 144,
in serialize
self.handle_m2m_field(obj, field)
File "/Users/jwalls/django/django/core/serializers/python.py", line 95,
in handle_m2m_field
queryset_iterator(obj, field),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jwalls/django/django/core/serializers/python.py", line 89,
in queryset_iterator
query_set = getattr(obj,
field.name).select_related(None).only("pk")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jwalls/django/django/db/models/manager.py", line 87, in
manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jwalls/django/django/db/models/query.py", line 1632, in
select_related
self._not_support_combined_queries("select_related")
File "/Users/jwalls/django/django/db/models/query.py", line 2052, in
_not_support_combined_queries
if self.query.combinator:
^^^^^^^^^^
File "/Users/jwalls/django/django/db/models/query.py", line 302, in
query
self._filter_or_exclude_inplace(negate, args, kwargs)
File "/Users/jwalls/django/django/db/models/query.py", line 1549, in
_filter_or_exclude_inplace
self._query.add_q(Q(*args, **kwargs))
File "/Users/jwalls/django/django/db/models/sql/query.py", line 1667, in
add_q
clause, _ = self._add_q(q_object, can_reuse)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jwalls/django/django/db/models/sql/query.py", line 1699, in
_add_q
child_clause, needed_inner = self.build_filter(
^^^^^^^^^^^^^^^^^^
File "/Users/jwalls/django/django/db/models/sql/query.py", line 1609, in
build_filter
condition = self.build_lookup(lookups, col, value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jwalls/django/django/db/models/sql/query.py", line 1436, in
build_lookup
lookup = lookup_class(lhs, rhs)
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jwalls/django/django/db/models/lookups.py", line 35, in
__init__
self.rhs = self.get_prep_lookup()
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/jwalls/django/django/db/models/fields/tuple_lookups.py",
line 55, in get_prep_lookup
self.check_rhs_length_equals_lhs_length()
File "/Users/jwalls/django/django/db/models/fields/tuple_lookups.py",
line 69, in check_rhs_length_equals_lhs_length
len_lhs = len(self.lhs)
^^^^^^^^^^^^^
TypeError: object of type 'Col' has no len()
----------------------------------------------------------------------
Ran 170 tests in 0.183s
FAILED (errors=1)
}}}
--
Ticket URL: <
https://code.djangoproject.com/ticket/36530>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.