Отношения "один ко многим" в Django ORM
Я создал несколько систем баз данных для управления базами данных деталей на небольших предприятиях по производству электроники. Я повторяю этот процесс, используя Django5 и MySQL. Я новичок в Django, но много раз использовал MySQL в Java и Python.
Рассмотрите таблицы
class Bom(models.Model):
bom = models.AutoField(primary_key=True);
bompart = models.ForeignKey(Part, on_delete=models.CASCADE)
revision = models.CharField(max_length=1)
class BomLine(models.Model):
bom = models.ForeignKey(Bom, on_delete=models.CASCADE)
part = models.ForeignKey(Part, on_delete=models.CASCADE)
designator = models.CharField(max_length=10, primary_key=True)
ordinal = models.IntegerField()
qty = models.DecimalField(max_digits=11, decimal_places=4)
class Meta:
constraints = [
models.UniqueConstraint(fields=['bom', 'designator'], name='bomdesignator')]
class Part(models.Model):
groupid = models.ForeignKey(PartGroup, on_delete=models.CASCADE)
partno = models.AutoField(primary_key=True)
partdescription = models.CharField(max_length=100)
(я опустил таблицу PartGroup, так как она не имеет отношения к моему вопросу). Идея заключается в том, что в таблице Bom определяется спецификация материалов. Система автоматически присваивает ему целочисленный идентификатор, и деталь назначается "родителем" этой спецификации - т.е. спецификация представляет собой список материалов, необходимых для изготовления назначенной детали.
Каждый BOM относится к BomLines. В BOM может быть много строк для каждого компонента. Поскольку в BOM может быть много компонентов одного типа, используется "обозначение", чтобы точно указать, к какому месту в сборке относится деталь. (Поле 'ordinal' используется только для сортировки и может быть проигнорировано).
Обычно я делаю комбинированный ключ для Bom и Designator в моей таблице MySQL. Однако Django ORM возражает против этого. Чтобы попытаться обойти ограничение на использование нескольких полей в качестве ключей, в класс BomLine было добавлено ограничение UniqueConstraint. Когда я добавляю обозначение 'U1' в bom 1, а затем добавляю 'U1' в bom 2, возникает проблема, поскольку 'U1' уже используется в качестве ключа. Если я убираю параметр primary_key=True у designator, Django добавляет AutoField id в таблицу. Я подумал, что это должно сработать, за исключением того, что мне придется назначить значение по умолчанию для ID. Движок MySQL не позволяет использовать значение по умолчанию, и это тоже не сработает.
Мне кажется, что либо мое мышление неверно (у меня есть способ структурировать отношения, который в некотором роде "не нормальный") - что подразумевается тем, как Django заставляет меня делать вещи. Или же бэкэнд MySQL не подходит для такого типа ситуаций и, возможно, мне следует использовать что-то другое?
Комментарии начали отклоняться от проблемы, поэтому я взглянул еще раз. На SO есть несколько постов о проблемах использования моделей Django с более чем одним первичным ключом. Это по-прежнему вызывает у меня недоумение, поскольку это конструкция базы данных, которую я часто видел и использовал. Я не думаю, что есть какая-то теория баз данных, которая препятствует этому, и, конечно, мой опыт работы с MySQL и PostgreSQL позволяет мне создавать такие таблицы. У них есть реальное применение. Django не может их моделировать, может быть, кто-нибудь сможет объяснить, почему так происходит?
Решение, которое я использовал и буду использовать в качестве образца, заключается в создании столбца 'id':
class bomline(models.Model):
bomline_id = models.UUIDField(primary_key=True, null=False, default=uuid.uuid1, editable=False, serialize=True)
bom = models.ForeignKey(Bom, on_delete=models.CASCADE)
part = models.ForeignKey(Part, on_delete=models.CASCADE)
designator = models.CharField(max_length=10)
ordinal = models.IntegerField()
qty = models.DecimalField(max_digits=11, decimal_places=4)
class Meta:
constraints = [
models.UniqueConstraint(fields=['bom', 'designator'], name='bomdesignator')]
Использование uuid гарантирует, что для ключа используется уникальное значение, а два внешних ключа обеспечивают существование записей parts и bom. Затем ограничение UniqueConstraint предотвращает двойную запись.
Это кажется длинным. Поразмыслив, можно сказать, что внешние ключи позволяют справиться с ситуациями, когда строки bom могут оказаться бесхозными в результате удаления частей или таблиц bom. Возможно, это лучший способ.