Django: Почему некоторые поля моделей сталкиваются друг с другом?

Я хочу создать объект, содержащий 2 ссылки на пользователя. Например:

class GameClaim(models.Model):
    target = models.ForeignKey(User)
    claimer = models.ForeignKey(User)
    isAccepted = models.BooleanField()

но при запуске сервера возникают следующие ошибки:

  • Аксессор для полевых "целевых" столкновений со связанным полем "User.gameclaim_set". Добавьте аргумент related_name в определение для "target".

  • Аксессуар для полевых "претендентов" сталкивается со связанным полем "User.gameclaim_set". Добавьте аргумент related_name в определение для "заявителя".

Не могли бы вы объяснить, почему я получаю ошибки и как их исправлять?

Ответ 1

У пользователя есть два внешних ключа. Django автоматически создает обратное отношение от пользователя к GameClaim, обычно gameclaim_set. Однако, поскольку у вас есть два FK, у вас есть два атрибута gameclaim_set, что, очевидно, невозможно. Поэтому вам нужно указать Django, какое имя использовать для обратного отношения.

Используйте атрибут related_name в определении FK. например.

class GameClaim(models.Model):
    target = models.ForeignKey(User, related_name='gameclaim_targets')
    claimer = models.ForeignKey(User, related_name='gameclaim_users')
    isAccepted = models.BooleanField()

Ответ 2

Модель User пытается создать два поля с тем же именем: одно для GameClaims, у которого User есть target, а другое для GameClaims, у которого есть User как claimer. Здесь docs на related_name, который является способом Django, позволяющим вам устанавливать имена атрибутов, чтобы автогенерированные не конфликтуют.

Ответ 3

OP не использует абстрактный базовый класс... но если вы, то обнаружите, что жесткое кодирование связанного_имя в FK (например..., related_name = "myname" ) приведет к ряду эти ошибки конфликтов - по одному для каждого унаследованного класса из базового класса. В приведенной ниже ссылке содержится обходной путь, который прост, но определенно не очевиден.

Из django docs...

Если вы используете связанное имя атрибут на ForeignKey или ManyToManyField, вы всегда должны указать уникальное обратное имя для поле. Это, как правило, проблема в абстрактных базовых классах, поскольку поля этого класса включенных в каждого ребенка классы с точно такими же значениями для атрибутов (в том числе related_name) каждый раз.

Подробнее здесь.

Ответ 4

Кажется, я иногда сталкиваюсь с этим, когда добавляю подмодуль в качестве приложения к проекту django, например, учитывая следующую структуру:

myapp/
myapp/module/
myapp/module/models.py

Если я добавлю следующее в INSTALLED_APPS:

'myapp',
'myapp.module',

Кажется, что Django обрабатывает файл myapp.mymodule models.py дважды и выдает указанную выше ошибку. Это можно решить, не включая основной модуль в списке INSTALLED_APPS:

'myapp.module',

Включение myapp вместо myapp.module приводит к созданию всех таблиц базы данных с неправильными именами, поэтому это, кажется, правильный способ сделать это.

Я столкнулся с этим сообщением, ища решение этой проблемы, поэтому решил, что поставлю это здесь:)

Ответ 5

Просто добавив ответ Джордану (спасибо за отзыв Jordan), это также может произойти, если вы импортируете уровень над приложениями и затем импортируете приложения, например.

myproject/ apps/ foo_app/ bar_app/

Итак, если вы импортируете приложения, foo_app и bar_app, тогда вы можете получить эту проблему. У меня были приложения, foo_app и bar_app все перечисленные в settings.INSTALLED_APPS

И вы хотите избежать импорта приложений в любом случае, потому что тогда у вас есть одно и то же приложение, установленное в 2 разных пространствах имен

apps.foo_app а также foo_app

Ответ 6

Иногда вам нужно использовать дополнительное форматирование в related_name - фактически, в любое время, когда используется наследование.

class Value(models.Model):
    value = models.DecimalField(decimal_places=2, max_digits=5)
    animal = models.ForeignKey(
        Animal, related_name="%(app_label)s_%(class)s_related")

    class Meta:
        abstract = True

class Height(Value):
    pass

class Weigth(Value):
    pass

class Length(Value):
    pass

Здесь нет столкновений, но связанное имя определено один раз, и Django позаботится о создании уникальных имен отношений.

то у детей класса Value вы получите доступ к:

herdboard_height_related
herdboard_lenght_related
herdboard_weight_related

Ответ 7

У меня была та же проблема. Использование run python manage.py makemigrations "appname" исправил его для меня. Я случайно удалил некоторые файлы миграции. Нет необходимости повторно удалять файлы.