Django模型UniqueConstraint仅在Admin生效,新增重复数据问题求助
问题
在Django模型中使用UniqueConstraint类时遇到异常:模型已配置联合唯一约束,但通过自定义表单的create()方法、手动MySQL插入都能添加重复数据,仅Django Admin后台添加时约束生效。相关代码如下:
模型代码
class ModeleEquipement(models.Model): id = models.AutoField(primary_key=True) fabricant = models.ForeignKey(FabricantEquipement, on_delete=models.SET_DEFAULT, default='') type = models.ForeignKey(TypeEquipement, on_delete=models.SET_DEFAULT, default='') reference = models.CharField(max_length=50, default='') designation = models.CharField(max_length=50, default='') def __str__(self): return str(self.id) class Meta: constraints = [ models.UniqueConstraint(fields=['fabricant', 'type', 'reference', 'designation'], name='unique_model_constraint') ]
后端数据创建代码
form = ModeleEquipementForm(request.POST) if form.is_valid(): fabricant = FabricantEquipement.objects.get(id=form.cleaned_data["fabricant"]) type = TypeEquipement.objects.get(id=form.cleaned_data["type"]) ModeleEquipement.objects.create( designation=form.cleaned_data["designation"], reference=form.cleaned_data["reference"], fabricant=fabricant, type=type )
表单代码
class ModeleEquipementForm(forms.Form): fabricant = forms.ChoiceField(widget=forms.Select()) type = forms.ChoiceField(widget=forms.Select()) reference = forms.CharField(label="Référence", max_length=20) designation = forms.CharField(label="Désignation", max_length=50) action = forms.CharField(widget=forms.HiddenInput(attrs={'value': 'add_modele'}))
解决方案
1. 同步数据库约束
Django的UniqueConstraint需要通过迁移操作同步到MySQL数据库才会生效。Admin后台生效是因为它在ORM层面做了前置校验,但直接create()或手动数据库插入时,只有数据库层面的约束能拦截重复数据。
执行以下命令完成约束同步:
python manage.py makemigrations python manage.py migrate
之后可以登录MySQL,检查modeleequipement表是否存在unique_model_constraint这个联合唯一索引。
2. 改用ModelForm实现表单校验
当前使用的forms.Form是普通表单,不会自动继承模型的唯一性校验逻辑,form.is_valid()仅检查字段格式合规性。而Django Admin使用的是ModelForm,会自动关联模型的约束规则。
将表单修改为ModelForm:
class ModeleEquipementForm(forms.ModelForm): action = forms.CharField(widget=forms.HiddenInput(attrs={'value': 'add_modele'})) class Meta: model = ModeleEquipement fields = ['fabricant', 'type', 'reference', 'designation']
后端代码也可以简化为直接调用save():
form = ModeleEquipementForm(request.POST) if form.is_valid(): form.save()
3. 捕获数据库完整性异常
即使数据库约束生效,直接调用create()遇到重复数据时会抛出IntegrityError,需要在代码中捕获并处理,避免静默插入失败:
from django.db import IntegrityError form = ModeleEquipementForm(request.POST) if form.is_valid(): try: fabricant = FabricantEquipement.objects.get(id=form.cleaned_data["fabricant"]) type = TypeEquipement.objects.get(id=form.cleaned_data["type"]) ModeleEquipement.objects.create( designation=form.cleaned_data["designation"], reference=form.cleaned_data["reference"], fabricant=fabricant, type=type ) except IntegrityError: form.add_error(None, "该组合已存在,请检查输入")
内容的提问来源于stack exchange,提问作者bbrenger
相关产品推荐
相关产品推荐

