8

我有一个 Django 模型,其中每个实例都需要一个从三个字段派生的唯一标识符:

class Example(Model):
    type = CharField(blank=False, null=False)           # either 'A' or 'B'
    timestamp = DateTimeField(default=timezone.now)
    number = models.IntegerField(null=True)             # a sequential number

这会产生一个形式为 的标签[type][timestamp YEAR][number],它必须是唯一的,除非number为空。

我想我也许可以使用几个注释:

uid_expr = Case(
    When(
        number=None,
        then=Value(None),
    ),
    default=Concat(
        'type', ExtractYear('timestamp'), 'number',
        output_field=models.CharField()
    ),
    output_field=models.CharField()
)

uid_count_expr = Count('uid', distinct=True)

我覆盖了模型的管理器get_queryset以默认应用注释,然后尝试使用CheckConstraint

class Example(Model):
    ...

    class Meta:
        constraints = [
            models.CheckConstraint(check=Q(uid_cnt=1), name='unique_uid')
        ]

这失败了,因为它无法在名为 的实例上找到一个字段uid_cnt,但是我认为对象可以访问注释Q。它看起来像是CheckConstraint直接对模型进行查询,而不是使用管理器返回的查询集:

class CheckConstraint(BaseConstraint):
    ...

    def _get_check_sql(self, model, schema_editor):
        query = Query(model=model)
    ...

有没有办法将约束应用于注释?还是有更好的方法?

我真的很想在 db 层执行此操作。

谢谢。

4

1 回答 1

0

这是伪代码,但请尝试:

class Example(Model):
    ...

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['type', 'timestamp__year', 'number'], 
                condition=Q(number__isnull=False),
                name='unique_uid'
            )
        ]
于 2021-04-10T20:27:35.387 回答