【问题标题】:Creating a models.UniqueConstraint in abstract model在抽象模型中创建 models.UniqueConstraint
【发布时间】:2019-11-30 14:33:04
【问题描述】:

我正在为我的 django 应用程序创建一个抽象模型,SrdObject。我的模型的一个特点是它有一对字段,它们加在一起必须是唯一的:“名称”和外键“模块”。

这是我的一个例子

class SrdObject(models.Model):
    name = models.CharField(max_length=50)
    slug_name = models.SlugField(max_length=75, unique=True)
    active = models.BooleanField(default=True)
    module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name='%(class)s', blank=False, null=False, default='default')

    class Meta:
        unique_together = ['name', 'module']
        ordering = ['name']
        abstract = True

这似乎工作正常,但 unique_together 属性已被 django 标记为已弃用(参见 here),所以我将其更改为此

class Meta:
    constraints = [
        models.UniqueConstraint(fields=['name', 'module'], name='unique-in-module')
    ]
    ordering = ['name']
    abstract = True

这不起作用,因为 name 字段必须是唯一的,并且由于这是一个抽象类,因此约束会在多个模型上重复。

我也试过

models.UniqueConstraint(fields=['name', 'module'], name='{}-unique-in-module'.format(model_name))

但显然这属于范围界定问题,所以我尝试了一种装饰器方法

def add_unique_in_module_constraint(cls):
    cls._meta.constraints = [
        models.UniqueConstraint(fields=['name', 'module'], name='unique-in-module')
    ]
    return cls

@add_unique_in_module_constraint
class SrdObject(models.Model):
    class Meta:
        ordering = ['name']
        abstract = True

但这似乎没有任何作用。

如果每个约束都需要唯一的名称属性,我该如何在抽象模型中创建 models.UniqueConstraint?

【问题讨论】:

  • 只是为了澄清-名称/模块的唯一性是跨从 SrdObject 继承的所有模型? IE。假设我们有两个模型 - SrdObjectA 和 SrdObjectB - 从 SrdObject 继承,如果我有一个名为“test”且模块 id 为 1 的 SrdObjectA,那么我也不能有一个名为“test”和模块 id 的 SrdObject 1 个?
  • 这不是必需的。每个 SrdObject 模型都有自己的命名空间

标签: python django python-3.x django-models


【解决方案1】:

我采用了这个模型设置:

class Module(models.Model):
    pass


class SrdObject(models.Model):
    name = models.CharField(max_length=50)
    slug_name = models.SlugField(max_length=75, unique=True)
    active = models.BooleanField(default=True)
    module = models.ForeignKey(Module, on_delete=models.CASCADE, related_name='%(class)s', blank=False, null=False, default='default')

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['name', 'module'], name='unique-in-module')
        ]
        ordering = ['name']
        abstract = True


class SrdObjectA(SrdObject):
    pass


class SrdObjectB(SrdObject):
    pass

然后运行这些测试:

class TestSrdObject(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.module = Module.objects.create()
        SrdObjectA.objects.create(name='A', module=cls.module)

    def test_unique_applies_to_same_model(self):
        with self.assertRaises(IntegrityError):
            SrdObjectA.objects.create(name='A', module=self.module)

    def test_unique_does_not_apply_to_different_model(self):
        self.assertTrue(SrdObjectB.objects.create(name='A', module=self.module))

他们通过了。也许我仍然错过了您遇到的问题?

【讨论】:

  • 当我尝试迁移数据库时,我得到django.db.utils.ProgrammingError: relation "unique-in-module" already exists
  • 嗯,很有趣。你用什么数据库?您能否分享一下您的迁移文件是什么样的?
【解决方案2】:

最新更新

从第 3 版开始,您终于可以通过 specifying interpolation 做到这一点:

Changed in Django 3.0:
Interpolation of '%(app_label)s' and '%(class)s' was added.

例子:

UniqueConstraint(fields=['room', 'date'], name='%(app_label)s_unique_booking')

旧版(Django

你不能那样做,对我来说同样的问题,太伤心了......

来源:django docs

抽象基类中的约束

您必须始终为约束指定一个唯一名称。因此,您通常不能在抽象基类上指定约束,因为 Meta.constraints 选项由子类继承,每次属性(包括名称)具有完全相同的值。相反,直接在子类上指定约束选项,为每个约束提供一个唯一的名称。

【讨论】:

  • 这到底是什么意思?插值?
  • @NoName,你可以随意命名,我只是从官方文档中复制过来的
  • @NoName 添加示例
猜你喜欢
  • 1970-01-01
  • 2016-04-03
  • 1970-01-01
  • 2020-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 2018-04-08
相关资源
最近更新 更多