DJANGO:ManyToManyField 自对称唯一在一起如何管理它?

问题描述 投票:0回答:0

我在尝试通过 Django Application 获取一些 manytomany 相关数据时遇到了一些问题

这是我的模型:

SoftwareVersion(models.Model):
    id = models.AutoField(
        primary_key=True,
        db_index=True
    )

    ... Some other fields ...

    incompatibilities= models.ManyToManyField(
        "self",
        symmetrical=True,
        blank=True,
        default=None,
        through="Incompatibilities"
    )

Incompatibilities(models.Model):
    id = models.AutoField(
        primary_key=True,
        db_index=True
    )

    softwareversion_a = models.ForeignKey(
        "SoftwareVersion",
        models.CASCADE,
        db_index=True,
        db_column='softwareversion_a ',
        related_name='softwareversion_a',
        verbose_name="software version a",
    )

    softwareversion_b = models.ForeignKey(
        "SoftwareVersion",
        models.CASCADE,
        db_index=True,
        db_column='softwareversion_b',
        related_name='softwareversion_b',
        verbose_name="softwareversion_b",
    )

    status = models.BooleanField(
        verbose_name='Status',
        default=False
    )

    class Meta:
        unique_together = (('softwareversion_a', 'softwareversion_b'),)

为此,我在 SoftwareVersion 的保存方法中添加了一个逻辑,用于为每个新软件版本创建相关的不兼容性。我已经尝试了几种方法来做到这一点(使用循环或使用 bulk_create)这是我使用的批量创建功能:

# Inside SoftwareVersion Model class
def save(self, force_insert=False, force_update=False, using=None, update_fields=None) -> None:
    save = super().save(force_insert, force_update, using, update_fields)
    
    Incompatibilities.objects.bulk_create(
       (Incompatibilities(
       softwareversion_a=self,
       softwareversion_b=software_version,
       status=False
            ) for software_version in SoftwareVersion.objects.exclude(self)),
            ignore_conflicts=True,
            batch_size=1000
        )

    return save

我遇到的第一个问题是此方法忽略了 unique_together 约束,它会创建重复项。 在我使用每个 SoftwareVersion 上的循环来创建一个对象之前,它太长了,所以我想使用 bulk_create,但它似乎无法按我的预期工作。是否有另一种优化方法来执行此操作或要传递的参数,以便遵守唯一的共同约束。

其次,查询“给出该软件版本的所有不兼容”的最优化方式是什么。目前我正在这样做:

Incompatibilities.objects.filter(softwareversion_a=?)

但我实际上错过了在“softwareversion_b”字段中引用软件版本的不兼容性。 我尝试使用逻辑:

VersionLogiciel.objects.get(pk=?).incompatibilities.all()

但是 django 输出相同的 SQL 请求,所以,相同的结果。

Incompatibilities.objects.filter(softwareversion_a=?)

是否有一个参数可以放在某个地方,以便两个字段(这里是'softwareversion_a','softwareversion_b')可以互换。或者我可能必须以特定方式查询才能访问不兼容对象。我试过查询:

Incompatibilities.objects.filter(Q(softwareversion_a=?) or Q(softwareversion_b=?))

但是因为我必须在 softwareversion_a 相关字段和 softwareversion_b 相关字段上订购结果,所以我无法让它按我想要的方式工作。

PS:抱歉我的英语不好,请注意我将模型翻译成英文,所以我可能犯了一些错误,但在我这边,模型编译和迁移正在按预期工作。

在此先感谢您的帮助。

django many-to-many unique-constraint self-join
© www.soinside.com 2019 - 2024. All rights reserved.