Как обрабатываются отношения «многие ко многим» в Django?

У меня есть рубашка, которая может содержать несколько цветов, и несколько цветов, которые могут иметь несколько рубашек. Обычно я бы выразил это следующим образом: введите здесь описание изображения

В django у меня есть многие ко многим (https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many/) Пример:

publications = models.ManyToManyField(Publication)

-- Могу ли я создать таблицу Item_colors, состоящую из 2 столбцов (первичный ключ без идентификатора), и спроектировать модели в соответствии с моей диаграммой, используя составной ключ:

class Item_colors(models.Model):
    class Meta:
        unique_together = (('cloth_item_id', 'color_id'),)

    cloth_item_id = models.ForeignKey(Cloth_item, on_delete=models.CASCADE)
    color_id = models.ForeignKey(Color, on_delete=models.CASCADE)

Как обрабатывается отношение «многие ко многим» в контексте БД и дает ли оно лучшую производительность?

РЕДАКТИРОВАТЬ: https://code.djangoproject.com/wiki/MultipleColumnPrimaryKeys не избегать первичных ключей в в пользу составных ключей, сохраняющих столбцы :( по крайней мере, на данный момент..


person LeOverflow    schedule 14.10.2020    source источник
comment
ManyToManyField создает промежуточную таблицу, но с первичным ключом. В Django каждая модель имеет первичный ключ.   -  person Willem Van Onsem    schedule 14.10.2020
comment
Спасибо, Виллем, я предполагаю, что промежуточная таблица похожа на мою таблицу Item_colors?   -  person LeOverflow    schedule 14.10.2020


Ответы (1)


Как обрабатывается отношение «многие ко многим» в контексте БД и дает ли оно лучшую производительность?

С соединительной таблицей посередине, то есть с таблицей item_colors. Но таблица содержит первичный ключ, как и любая модель в Django.

Если вы не укажете < strong>through=… параметр [Django-doc], чтобы самостоятельно определить модель для соединительной таблицы, Django автоматически создаст такую ​​модель. Затем эта модель имеет два ForeignKey для двух моделей, которые она соединяет, как описано в представление базы данных документации:

За кулисами Django создает промежуточную таблицу соединений для представления отношения "многие ко многим". По умолчанию это имя таблицы создается с использованием имени поля «многие ко многим» и имени таблицы для модели, которая его содержит. Поскольку некоторые базы данных не поддерживают имена таблиц выше определенной длины, эти имена таблиц будут автоматически усечены, и будет использоваться хэш уникальности, например. author_books_9cdf. Вы можете вручную указать имя таблицы соединений, используя параметр db_table.

Но у таблицы таким образом есть первичный ключ. Это может быть полезно, если один и тот же объект встречается в отношении второй раз.

Вы можете получить доступ к сквозной модели в примере Article-Publication, например, с помощью:

Article.publications.through

Таким образом, вы можете самостоятельно определить сквозную модель, например, с помощью:

class Color(models.Model):
    color = models.CharField(max_length=128)

class ClothItem(models.Model):
    item_name = models.CharField(max_length=128)
    colors = models.ManyToManyField(
        Color,
        related_name='cloth_items'
        through='ClothItemColors'
    )

class ClothItemColors(models.Model):
    cloth_item = models.ForeignKey(ClothItem, on_delete=models.CASCADE)
    color = models.ForeignKey(Color, on_delete=models.CASCADE)

    class Meta:
        db_table = 'item_colors'
        constraints = [
            models.UniqueConstraint(
                fields=('cloth_item', 'color'),
                name='unique_cloth_color'
            )
        ]

часто для хранения дополнительной информации используется явная сквозная модель, например quantity:

class ClothItemColors(models.Model):
    cloth_item = models.ForeignKey(ClothItem, on_delete=models.CASCADE)
    color = models.ForeignKey(Color, on_delete=models.CASCADE)
    quantity = models.IntegerField(default=0)

    # …
person Willem Van Onsem    schedule 14.10.2020
comment
Спасибо, Виллем, снова отличная помощь - и хороший пример использования сквозного. Я изучил ваше использование UniqueConstraint, а не моего unique_together — документация согласуется: docs.djangoproject.com/en/3.1/ref/models/options/.. Я просто пропускаю что-то или нет, я могу избежать первичного ключа таблицы, сохраняя столбец, у меня есть много подобных таблицы :) или, как вы говорите, все таблицы имеют первичный ключ (без исключений) - person LeOverflow; 14.10.2020
comment
Я обновил исходный вопрос, когда нашел ваш другой ответ: stackoverflow.com/questions/61320317/ и это в вики: code.djangoproject.com/wiki/MultipleColumnPrimaryKeys не избегая первичных ключей в пользу составных ключей, сохраняющих столбцы :( по крайней мере, на данный момент.. - person LeOverflow; 14.10.2020
comment
@LeOverflow: грустно то, что первичные ключи Django довольно жестко встроены в остальную часть кода. Например, DetailView использует параметр URL-адреса <int:pk> для автоматической фильтрации. Скорее всего, можно достаточно эффективно реализовать изменения в самом Django, но тогда все еще существует экосистема пакетов Django, зависящих от одного первичного ключа. Так что я думаю воздержаться от его исправления, так как это, вероятно, потребует много работы от других сопровождающих пакетов. Особенно для пакетов, которые не поддерживаются в течение некоторого времени. - person Willem Van Onsem; 14.10.2020