首页 > 解决方案 > 如何确保模型仅在另一个已经存在时才创建一个实例

问题描述

在模型中,我需要防止使用相同的标识符代码创建孤立术语(首选术语的同义词或相关术语)。现在我有以下内容:

from django.utils.translation import gettext_lazy as _
from django.db import models

class TopographyCodes(models.Model):
    code = models.CharField(
        max_length=5,
        primary_key=True,
        )

class TopographyFourCharactersDescription(models.Model):
    code = models.ForeignKey(
        'TopographyCodes',
        on_delete=models.CASCADE,
        )
    term = models.CharField(max_length=200)

    class TermType(models.IntegerChoices):
        PREFERRED = 1, _('Preferred term')
        SYNONYM = 2, _('Synonym')
        RELATED = 3, _('Related or equivalent')

    term_type = models.IntegerField(
        max_lenght=1,
        choices=TermType.choices,
        default=TermType.PREFERRED,
    )

    def is_preferred(self):
        return self.type in {
            self.TermType.PREFERRED,
        }

    class Meta:
        constraints = [
            # We only support one preferred description per code
            models.UniqueConstraint(
                fields=['code'],
                condition=Q(term_type=1),
                name='unique_preferred_code'),
            ]

现在,如果 is_main 返回 true(或将返回 true),则应该允许创建新术语。我正在使用表单集来编辑此模型,它假定它已创建,但我希望模型保证如果没有具有相同代码但首选的条目,则不存在任何术语。

数据库已经存在这类问题,我想防止它们发生。

标签: django

解决方案


由于您的模型与自身有关系,请创建它。就像是:

preferred_term = models.ForeignKey(
    'self',
    null=True,
    limit_choices_to={'is_preferred': True},
    on_delete=models.CASCADE,
)

现在您可以使用检查约束来验证当 term_type 不等于 1 时,确保 preferred_term 不为 NULL:

class Meta:
    constraints = [
        [...]
        models.CheckConstraint(
            check=(Q(preferred_term__isnull=False) & Q(term_type__gt=1)) | Q(term_type=1),

由于此规则不适用于您首选的术语,因此只需在等于 1 时无条件地通过检查。


推荐阅读