模型 unique_together 约束 + 无 = 失败?

Posted

技术标签:

【中文标题】模型 unique_together 约束 + 无 = 失败?【英文标题】:Models unique_together constraint + None = fail? 【发布时间】:2010-11-03 15:29:15 【问题描述】:

2 个问题:

当 parent=None 且名称相同时,如何阻止创建重复项? 我可以从表单中调用模型方法吗?

请参阅下面的完整详细信息:

models.py

class MyTest(models.Model):
    parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
    name = models.CharField(max_length=50)
    slug = models.SlugField(max_length=255, blank=True, unique=True)
    owner = models.ForeignKey(User, null=True)

    class Meta:
        unique_together = ("parent", "name")

    def save(self, *args, **kwargs):
        self.slug = self.make_slug() 
        super(MyTest, self).save(*args, **kwargs)

    def make_slug(self):
        # some stuff here 
        return generated_slug

注意:slug = 也是独一无二的!

forms.py

class MyTestForm(forms.ModelForm):
    class Meta:
        model = MyTest
        exclude = ('slug',)

    def clean_name(self):
        name = self.cleaned_data.get("name")
        parent = self.cleaned_data.get("parent")

        if parent is None:
            # this doesn't work when MODIFYING existing elements!
            if len(MyTest.objects.filter(name = name, parent = None)) > 0:
                raise forms.ValidationError("name not unique")
        return name

详情

unique_together 约束与parent != None 时的形式完美配合。但是,当 parent == None (null) 时,它允许创建重复项。

为了避免这种情况,我尝试使用表单并定义 clean_name 来尝试检查重复项。这在创建新对象时有效,但在修改现有对象时无效。

有人提到我应该在 ModelForm 的 .save 上使用 commit=False,但我不知道如何做/实现这个。我还考虑过使用 ModelForm 的 has_changed 来检测模型的更改并允许它们,但是 has_changed 在新创建的带有表单的对象上也返回 true。帮忙!

另外,(有点完全不同的问题)我可以从表单访问 make_slug() 模型方法吗?我相信目前我的exclude = ('slug',) 行也忽略了 slug 字段上的“唯一”约束,而在模型保存字段中,我正在生成 slug。我想知道是否可以改为在 forms.py 中执行此操作?

【问题讨论】:

请参阅***.com/questions/3488264/… 了解处理此问题的最新方法。需要 Django 1.2。 使用 Django2.2,您可以使用带有条件参数的 UniqueConstraints 来创建部分索引:docs.djangoproject.com/en/2.2/ref/models/constraints/#condition 【参考方案1】:

无论是创建还是更新,您都可以有不同的表单。

在实例化表单时使用 instance kwarg。

if slug:
    instance = MyTest.object.get( slug=slug )
    form = MyUpdateTestForm( instance=instance )
else:
    form = MyTestForm()

对于第二部分,我认为您可以在其中引入 commit=False,例如:

if form.is_valid():
    inst = form.save( commit=False )
    inst.slug = inst.make_slug()
    inst.save() 

【讨论】:

【参考方案2】:

我不确定这是否能解决您的问题,但我建议在最新的 Django 主干代码上测试您的代码。得到它:

svn co http://code.djangoproject.com/svn/django/trunk/

自 1.02 版本以来,已经对 unique_together 进行了多项修复,例如参见 ticket 9493。

【讨论】:

【参考方案3】:

唯一的一起应该是元组的元组

unique_together = (("parent", "name"),)

【讨论】:

以上是关于模型 unique_together 约束 + 无 = 失败?的主要内容,如果未能解决你的问题,请参考以下文章

约束 unique_together 可能与 django 类中的唯一字段冲突

为啥我的 Django ModelForm 不会引发 unique_together 约束的验证错误?

为啥 Django 不将我的 unique_together 约束强制为 form.ValidationError 而不是抛出异常?

如何在 MySQL 中有一个涉及 ForeignKey 字段的 unique_together 约束?

django rest 框架:内容类型 unique_together 和序列化

模型管理器可以访问其模型的元属性(`Meta.unique_together`)吗?