Причина сбоя фильтрации обратного отношения, когда поле m2m использует строковый класс?
Я столкнулся со странной проблемой, используя Django 2.2 и пытаясь отфильтровать обратное отношение, которое было определено с помощью строковой ссылки на класс. Проблема исчезает, если я передаю сам класс, т.е.
ЭТО ПРОВАЛ:
class Whatever(models.Model):
providers = models.ManyToManyField('Relation', related_name='dependants')
ЭТО РАБОТАЕТ:
from models import Relation
class Whatever(models.Model):
providers = models.ManyToManyField(Relation, related_name='dependants')
Обратите внимание, что разница только в том, объявлено ли поле m2m с помощью строки или класса модели.
Когда у меня есть внешняя модель в виде строки и я вызываю:
Relation.objects.filter(dependants=1)
Ошибка, которую я получаю:
FieldError: Cannot resolve keyword 'dependants' into field. Choices are: ...
Ни один из перечисленных вариантов не является dependants
, в основном он недоступен.
Хотя это работает:
r = Relation.objects.first()
r.dependants
Использование импортированного класса модели решает мою конкретную проблему, но преимущество использования строкового класса для разрешения циклических зависимостей теряется. На случай, если это произойдет снова, может ли кто-нибудь пролить свет на то, почему это может произойти? Это известная ошибка, решенная в более поздних версиях Django или известное ограничение использования строк для указания классов?
Примечание, я попытался решить эту проблему следующим образом:
- Упрощение обеих моделей, чтобы не было специальных менеджеров или других хаков кверисетов .
- Полная квалификация строки имени модели, например
'appname.Relation'
- переименование как поля, так и связанного_имени в случае некоторого внутреннего конфликта
- перестройка и запуск миграций
- изменение запроса на
Relation.objects.filter(dependants__id=1)
Я думаю, что вы получаете эту ошибку, потому что ваши два класса моделей не находятся в одном и том же приложении django. Но вы можете использовать строковую ссылку, но вы должны использовать строковую точечную нотацию, например 'app_label.model_class_name'