#python #django
#python #django
Вопрос:
От документация Django для ManyToManyField
:
Если вы не хотите, чтобы между одними и теми же экземплярами было несколько ассоциаций, добавьте UniqueConstraint, включая поля from и to . Автоматически сгенерированные таблицы «многие ко многим» в Django включают такое ограничение.
Как мне отключить это ограничение? Это единственный способ предоставить явную through
таблицу? Или есть способ сообщить Django, чтобы он не добавлял UniqueConstraint
в сгенерированную таблицу «многие ко многим»?
Комментарии:
1. В значительной степени. Вы можете обезьянничать с исправлением
django.db.models.fields.related.create_many_to_many_intermediary_model
, но это больше работы, чем установка сквозной модели. Я не вижу поддерживаемого способа сброса ограничения.2. @Melvyn Я был бы признателен, если бы это было опубликовано в качестве ответа, пожалуйста.
Ответ №1:
таблицы m2m связаны промежуточной таблицей, которая управляет отношениями и имеет unique_together
ограничение. Эта таблица создается автоматически, но вы можете использовать свою собственную таблицу, как указано в документе с through
аргументом. Вы можете прочитать об этом в документации. В вашем случае вам нужно отключить unique_together
ограничение, определив свою собственную промежуточную таблицу.
Другие варианты:
- Расширьте значение по умолчанию
ManyToManyField
и переопределитеcontribute_to_class
метод. - Отредактируйте значение по умолчанию
ManyToManyField
напрямую, как упоминал @Melvyn.
Комментарии:
1. Это не то уникальное, что имеет значение. 🙂
unique_together
Метакласс in модели, которую создает Django, является соответствующей частью. уникальность на уровне поля по умолчанию равна False. Подробнее см. Метод, о котором я упоминал выше. Эта функция вызывается изManyToManyField.contribute_to_class()
.2. Из моего вопроса: «Это единственный способ предоставить явную сквозную таблицу?» Похоже, ваш ответ «да, это единственный способ отключить UniqueConstraint по умолчанию». Это правильно?
3. Вы также можете расширить значение по умолчанию
ManyToManyField
и переопределитьcontribute_to_class
методы. Другой способ — комментарий @Melvyn к вашему основному сообщению.4. @Jonatan Спасибо за информацию. Мне кажется, что создать класс для
through
kwarg намного проще, чем любой из других предложенных до сих пор вариантов.
Ответ №2:
Вы можете обезьянить patch django.db.models.fields.related.create_many_to_many_intermediary_model
, который создает промежуточную модель, и это самое близкое, что вы можете получить от него. Он вызывается из contribute_to_class
метода в ManyToManyField. Конечно, это больше работы, чем указание сквозной модели, но если у вас есть вариант использования, когда все (или большинство) ваших посредников не требуют ограничений, тогда это стоит изучить.
Я не вижу поддерживаемого способа переопределить только это ограничение.
И да, вы можете создать подкласс ManyToManyField и установить там сквозную модель с помощью служебной функции, идентичной вышеупомянутой, исключая ограничение, а затем вызвать super() . Это позволит избежать ограничения, поскольку contribute_to_class не вызывает указанный выше метод, когда сквозная модель уже установлена:
if not cls._meta.abstract:
if self.remote_field.through:
def resolve_through_model(_, model, field):
field.remote_field.through = model
lazy_related_operation(resolve_through_model, cls, self.remote_field.through, field=self)
elif not cls._meta.swapped:
self.remote_field.through = create_many_to_many_intermediary_model(self, cls)
Оба метода имеют одинаковое предостережение: вам необходимо вручную синхронизировать вашу альтернативную утилиту с Django при обновлении Django, и все это с целью удаления одной строки :
'unique_together': (from_, to),
.
Комментарии:
1. Переопределение contribute_to_class требует меньше работы, чем редактирование библиотеки Django.
2. Исправление обезьяны отличается от «физического исправления библиотеки Django». Вы перенаправляете функцию / метод в классе, который не принадлежит вам, на что-то другое.
unittest.mock
Библиотека делает это широко, используяpatch
свои функциональные возможности.3. Плохая практика .
4. То же самое можно сказать и о том, что Django не придерживается мантры «делай одно». Утилита могла бы делегировать
get_intermediairy_meta_klass
, которая будет иметь элементы по умолчанию и будет принимать kwargs . Эти «золотые правила» и BCP существуют для общего случая. К счастью, мир пока не черно-белый, и все еще есть люди, которые игнорируют их, когда это уместно 🙂5. Как вы говорите в своем первоначальном комментарии к моему вопросу, это намного больше работы, чем просто создание класса и указание
through
kwarg toManyToManyField
.