Django如何将unique_together错误关联至指定字段?
问题描述
我在开发多租户应用,所有数据均关联至Tenant模型。创建模型时需要确保name字段的唯一性,但该唯一性仅需在租户内生效,而非全局生效,因此使用了unique_together(后续会迁移至UniqueConstraint)。
然而当唯一性约束被违反时,系统会添加non_field_error,我希望将该错误关联至name字段——因为tenant字段是隐式的,对用户不可见(始终为当前登录用户所属租户,不可选择)。
请问如何实现这一需求?优先考虑在模型层实现,其次可在表单层实现。我曾考虑先验证模型,再将错误从non_field_errors转移至name字段,但这种方式感觉不太合理。
初始代码:
class Company(models.Model): tenant = models.ForeignKey(Tenant, on_delete=models.PROTECT) name = models.CharField(max_length=255) class Meta: unique_together = ('tenant', 'name')
解决方案
方法一:模型层自定义验证(优先推荐)
直接在模型的clean方法中手动校验租户内的名称唯一性,错误会直接绑定到name字段:
from django.core.exceptions import ValidationError class Company(models.Model): tenant = models.ForeignKey(Tenant, on_delete=models.PROTECT) name = models.CharField(max_length=255) class Meta: # 后续可替换为UniqueConstraint,逻辑一致 unique_together = ('tenant', 'name') def clean(self): super().clean() # 校验当前租户下是否已存在同名记录,编辑时排除自身 exists = Company.objects.filter( tenant=self.tenant, name=self.name ).exclude(pk=self.pk).exists() if exists: raise ValidationError({ 'name': '当前租户下已存在该名称' })
注意:调用model.save()时不会自动触发clean方法,需手动调用model.full_clean(),或者通过Django的ModelForm操作(表单会自动触发模型的clean)。
方法二:表单层转移错误
如果不想修改模型,可在ModelForm中捕获全局错误并转移到name字段:
from django import forms from .models import Company class CompanyForm(forms.ModelForm): class Meta: model = Company fields = ['name'] # 不暴露tenant字段 def clean(self): cleaned_data = super().clean() # 识别唯一性相关的全局错误 if self.non_field_errors(): for error in self.non_field_errors(): if "unique" in error.lower() or "已存在" in error: self.add_error('name', error) # 移除原全局错误 self._errors.pop('__all__', None) return cleaned_data
内容的提问来源于stack exchange,提问作者Timitry
相关产品推荐
相关产品推荐

