Использование Django CheckConstraint с аннотациями - PullRequest
3 голосов
/ 19 февраля 2020

У меня есть модель 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)
    ...

Есть ли способ применить ограничение к аннотации? Или есть лучший подход?

Я бы очень хотел применить это на уровне базы данных.

Спасибо.

...