Django使用中间表创建多键M2M关系

86 阅读2分钟

开发者使用了一个外部MySQL数据库,并使用Django ORM对其进行映射。数据库中存在三个表:SchemaCategoryEquipmentOptionList

huake_00152_.jpg SchemaCategory表包含三个字段:schema_idlanguage_idcategory,其中schema_idlanguage_id是主键。

Equipment表包含六个字段:vehicle_idschema_idoption_idrecord_idlocationdata_value,其中vehicle_idschema_idoption_idrecord_id是主键。

OptionList表包含四个字段:vehicle_idoption_idoption_typemanuf_name,其中vehicle_idoption_id是主键。

开发者想要从OptionList表中加载所有给定vehicle_id的条目,并为每个选项关联相应的SchemaCategory条目。OptionListSchemaCategory通过Equipment表相关联(vehicle_idoption_id生成schema_id,可用于获取所有类别)。

2. 解决方案

可以使用Django ORM的ManyToManyField字段来实现这个多键M2M关系。在OptionList模型中,添加一个名为schema_categoriesManyToManyField字段,如下所示:

class OptionList(models.Model):

    vehicle_id = models.BigIntegerField(primary_key=True)
    option_id = models.IntegerField(primary_key=True)

    option_type = models.CharField(max_length=10L)
    option_code = models.CharField(max_length=255L, blank=True)
    manuf_name = models.CharField(max_length=255L)

    schema_categories = models.ManyToManyField(
        'SchemaCategory',
        through='Equipment',
        on_delete=models.CASCADE,
    )

    unique_together = (('vehicle_id', 'option_id'),)

    class Meta:
        db_table = 'option_list'

Equipment模型中,添加一个名为option_listForeignKey字段,如下所示:

class Equipment(models.Model):

    vehicle_id = models.BigIntegerField(primary_key=True)
    schema_id = models.IntegerField(primary_key=True)
    option_id = models.IntegerField(primary_key=True)
    record_id = models.IntegerField(primary_key=True)
    location = models.CharField(max_length=50L, blank=True)
    data_value = models.CharField(max_length=255L, primary_key=True)
    condition = models.TextField(blank=True)

    option_list = models.ForeignKey(
        'OptionList',
        on_delete=models.CASCADE,
    )

    unique_together = (('vehicle_id', 'schema_id', 'option_id', 'data_value', 'record_id'))

    class Meta:
        db_table = 'equipment'

SchemaCategory模型中,添加一个名为equipmentForeignKey字段,如下所示:

class SchemaCategory(models.Model):

    schema_id = models.IntegerField(primary_key=True)
    language_id = models.IntegerField(primary_key=True)
    category = models.CharField(max_length=255L, blank=True)

    equipment = models.ForeignKey(
        'Equipment',
        on_delete=models.CASCADE,
    )

    unique_together = (('schema_id', 'language_id'),)

然后,可以使用Django ORM的prefetch_related()方法来预加载SchemaCategory条目,如下所示:

option_lists = OptionList.objects.filter(vehicle_id=vehicle_id).prefetch_related('schema_categories')

这将加载所有给定vehicle_idOptionList条目,并预加载每个条目的SchemaCategory条目。