Вот моя модель:
class GroupedModels(models.Model):
other_model_one = models.ForeignKey('app.other_model')
other_model_two = models.ForeignKey('app.other_model')
По сути, я хочу other_model
быть уникальным в этой таблице. Это означает, что если есть запись с other_model_one
идентификатором id 123
, я не должен позволять создавать другую запись с other_model_two
идентификатором as 123
. Я могу переопределить, clean
я думаю, но мне было интересно, есть ли в Django что-то встроенное.
Я использую версию 2.2.5 с PSQL.
Изменить: Это не сложная ситуация вместе. Если я добавлю запись с other_model_one_id=1
и другим other_model_two_id=2
, я не смогу добавить еще одну запись с other_model_one_id=2
иother_model_two_id=1
python
django
django-models
Pittfall
источник
источник
Ответы:
Я объясняю несколько вариантов здесь, может быть, один из них или их комбинация могут быть вам полезны.
Переопределение
save
Ваше ограничение является бизнес-правилом, вы можете переопределить
save
метод, чтобы сохранить согласованность данных:Изменить дизайн
Я положил образец легко понять. Давайте предположим этот сценарий:
Теперь вы хотите, чтобы команда не играла матч с самой собой, а команда А может играть только с командой Б один раз (почти по вашим правилам). Вы можете перепроектировать свои модели как:
ManyToManyField.symmetrical
Это похоже на симметричную проблему, Django может решить ее для вас. Вместо того, чтобы создавать
GroupedModels
модель, просто создайте поле ManyToManyField с самим собой наOtherModel
:Это то, что django имеет как встроенный для этих сценариев.
источник
match_id
в ограничение unike, чтобы позволить командам играть неограниченное количество матчей. Просто удалите это поле, чтобы снова ограничить игру.Это не очень удовлетворительный ответ, но, к сожалению, правда в том, что нет способа сделать то, что вы описываете, с помощью простой встроенной функции.
То, что вы описали,
clean
будет работать, но вы должны быть осторожны, чтобы вызывать его вручную, так как я думаю, что он вызывается только автоматически при использовании ModelForm. Возможно, вы сможете создать сложное ограничение базы данных, но оно будет находиться за пределами Django, и вам придется обрабатывать исключения из базы данных (что может быть сложно в Django, когда выполняется транзакция).Может быть, есть лучший способ структурировать данные?
источник
От Дани Эрреры уже есть отличный ответ , однако я хотел бы уточнить его.
Как объясняется во втором варианте, решение, требуемое OP, состоит в том, чтобы изменить конструкцию и реализовать два уникальных ограничения попарно. Аналогия с баскетбольными матчами очень наглядно иллюстрирует проблему.
Вместо баскетбольного матча я использую пример с футбольными (или футбольными) играми. В футбольную игру (которую я называю это
Event
) играют две команды (в моих моделях это командаCompetitor
). Это отношение «многие ко многим» (m:n
), сn
ограничением до двух в данном конкретном случае принцип подходит для неограниченного числа.Вот как выглядят наши модели:
Событие может быть:
Теперь мы должны решить вопрос из вопроса. Django автоматически создает промежуточную таблицу между моделями с отношением «многие ко многим», но мы можем использовать пользовательскую модель и добавлять дополнительные поля. Я называю эту модель
Participant
:ManyToManyField
Имеет опцию ,through
которая позволяет нам указать промежуточную модель. Давайте изменим это в моделиEvent
:Уникальные ограничения теперь будут автоматически ограничивать число участников на событие до двух (потому что есть только две роли: Дом и Посетитель ).
В конкретном событии (футбольный матч) может быть только одна домашняя команда и только одна команда гостей. Клуб (
Competitor
) может выступать в качестве домашней команды или команды гостей.Как нам теперь управлять всеми этими вещами в админе? Нравится:
Мы добавили
Participant
как встроенный вEventAdmin
. Когда мы создаем новое,Event
мы можем выбрать домашнюю команду и команду посетителей. Опцияmax_num
ограничивает количество записей до 2, поэтому на одно событие можно добавить не более 2 команд.Это может быть реорганизовано для других случаев использования. Допустим, наши соревнования - это соревнования по плаванию, и вместо дома и посетителя у нас есть дорожки с 1 по 8. Мы просто рефакторинг
Participant
:С помощью этой модификации мы можем получить это событие:
титул: FINA 2019, финал на 50 м на спине среди мужчин,
участники:
// и т. д. с 5 по 8 дорожку (источник: Википедия
Пловец может появиться только один раз в жару, а дорожка может быть занята только один раз в жару.
Я поместил код в GitHub: https://github.com/cezar77/competition .
Опять же, все кредиты идут к Дани Эррера. Я надеюсь, что этот ответ обеспечит читателям дополнительную ценность.
источник