Обратный поиск не работает в django 5.x

Мы переносим наше приложение django с django==3.2.25 на django==5.1.6. OneToOneField, ManyToManyField при обратном поиске появляются ошибки.

У меня есть модели, как показано ниже.

from django.db import models

class Switch(models.Model):
    fqdn = models.CharField(max_length=45, unique=True)
    class Meta:
        managed = False
        db_table = 'Switch'
        app_label = 'myapp_models'

class ConfigState(models.Model):
    switch = models.OneToOneField(Switch, models.CASCADE, db_column='switch', primary_key=True,
                                  related_name='config_state')
    class Meta:
        managed = False
        db_table = 'ConfigState'
        app_label = 'myapp_models'

class EdgeSwitch(models.Model):
    switch = models.OneToOneField(Switch, models.CASCADE, db_column='switch', primary_key=True,
                                      related_name='edge_switch')
    class Meta:
        managed = False
        db_table = 'EdgeSwitch'
        app_label = 'myapp_models'

Когда я пытаюсь получить запрос обратного поиска в DJango==3.X, это срабатывает.

>>> print(EdgeSwitch.objects.filter(switch__config_state=1).query)
SELECT `EdgeSwitch`.`switch`, `EdgeSwitch`.`cluster`, `EdgeSwitch`.`sequence`, `EdgeSwitch`.`position`, `EdgeSwitch`.`role`, `EdgeSwitch`.`span`, `EdgeSwitch`.`loopback_v4`, `EdgeSwitch`.`loopback_v6` FROM `EdgeSwitch` INNER JOIN `Switch` ON (`EdgeSwitch`.`switch` = `Switch`.`id`) INNER JOIN `ConfigState` ON (`Switch`.`id` = `ConfigState`.`switch`) WHERE `ConfigState`.`switch` = 1

Тот же код выдает ошибку в DJango==5.X

>>> print(EdgeSwitch.objects.filter(switch__config_state=1).query)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/user/virtualenvs/app_corp_1.0.X/lib/python3.12/site-packages/django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/virtualenvs/app_corp_1.0.X/lib/python3.12/site-packages/django/db/models/query.py", line 1476, in filter
    return self._filter_or_exclude(False, args, kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/virtualenvs/app_corp_1.0.X/lib/python3.12/site-packages/django/db/models/query.py", line 1494, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)
  File "/home/user/virtualenvs/app_corp_1.0.X/lib/python3.12/site-packages/django/db/models/query.py", line 1501, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))
  File "/home/user/virtualenvs/app_corp_1.0.X/lib/python3.12/site-packages/django/db/models/sql/query.py", line 1609, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/virtualenvs/app_corp_1.0.X/lib/python3.12/site-packages/django/db/models/sql/query.py", line 1641, in _add_q
    child_clause, needed_inner = self.build_filter(
                                 ^^^^^^^^^^^^^^^^^^
  File "/home/user/virtualenvs/app_corp_1.0.X/lib/python3.12/site-packages/django/db/models/sql/query.py", line 1555, in build_filter
    condition = self.build_lookup(lookups, col, value)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/virtualenvs/app_corp_1.0.X/lib/python3.12/site-packages/django/db/models/sql/query.py", line 1379, in build_lookup
    lhs = self.try_transform(lhs, lookup_name)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/virtualenvs/app_corp_1.0.X/lib/python3.12/site-packages/django/db/models/sql/query.py", line 1423, in try_transform
    raise FieldError(
django.core.exceptions.FieldError: Unsupported lookup 'config_state' for OneToOneField or join on the field not permitted.

Как заставить его работать так, как он работал раньше?

Вероятно, причиной является app_label: вы зарегистрировали модели с помощью app_label, которого нет в INSTALLED_APPS, и в результате они не зарегистрированы.

Если я изменю app_label на единицу в INSTALLED_APPS, это сработает. Но вам не нужно упоминать app_label: если вы оставите его, он автоматически установится в приложении, в котором находится models.py.

Вернуться на верх