如何使用ModelForm使用唯一约束更新Django模型数据?
我有两个模型,其中一个是用约束定义的(参见下面的“实体”模型) 我构建了两个表单,一个用于创建新模型数据,另一个用于更新模型数据。“创建表单”工作正常,但“更新表单”会抛出一个错误,说明已存在项的数量(我的约束基于两个字段的唯一组合)。无论我在更新表单中修改哪个字段,都会抛出相同的错误 例如,在“实体”实例中仅修改“注释”字段会导致以下错误 具有此名称和公司的实体已存在 如何正确地实现我的表单(和/或模型),以便保留约束(具有相同名称的实体在公司中必须是唯一的),并且修改非约束字段不会引发错误 型号.py如何使用ModelForm使用唯一约束更新Django模型数据?,django,python-3.x,database,constraints,Django,Python 3.x,Database,Constraints,我有两个模型,其中一个是用约束定义的(参见下面的“实体”模型) 我构建了两个表单,一个用于创建新模型数据,另一个用于更新模型数据。“创建表单”工作正常,但“更新表单”会抛出一个错误,说明已存在项的数量(我的约束基于两个字段的唯一组合)。无论我在更新表单中修改哪个字段,都会抛出相同的错误 例如,在“实体”实例中仅修改“注释”字段会导致以下错误 具有此名称和公司的实体已存在 如何正确地实现我的表单(和/或模型),以便保留约束(具有相同名称的实体在公司中必须是唯一的),并且修改非约束字段不会引发错误
class Entities(models.Model):
company = models.ForeignKey(Companies, on_delete=models.CASCADE)
name = models.CharField(max_length=50, blank=False, null=False)
notes = models.TextField(blank=True, null=True)
class Meta:
# Constraint here (entity name + company combination name must be unique)
constraints = [models.UniqueConstraint(fields=['name', 'company'], name='unique_company_entity')]
managed = True
db_table = 'entities'
def __str__(self):
object_name = self.name + " " + self.company.name
return object_name
class Companies(models.Model):
name = models.CharField(max_length=50, blank=False, null=False)
notes = models.CharField(max_length=50, blank=True, null=True)
class Meta:
managed = True
db_table = 'companies'
def __str__(self):
object_name = self.name
return object_name
def entity_edit(request,entity_id):
companies = Companies.objects.all().order_by('name')
entity_id = int(entity_id)
entity = Entities.objects.get(id = entity_id)
if request.method == 'POST':
form = EntityEditForm(request.POST,instance=entity)
if form.is_valid():
post_result = form.save(commit=True)
redirect_url_valid = "/contacts/companies/entities/" + str(entity.id) + "/view/"
return redirect(redirect_url_valid)
else:
form = EntityEditForm(instance=entity)
return render(request,'entity_edit_form.html',{
'companies': companies,
'entity': entity,
'form': form
})
class EntityEditForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.label_suffix = ''
self.fields['name'] = forms.CharField(label='Name',widget=forms.TextInput(attrs={ 'class': 'form-control' }))
self.fields['company'] = forms.ModelChoiceField(queryset=Companies.objects.all(),label='Company',required=True,widget=forms.Select(attrs={ 'class': 'form-control' }))
self.fields['notes'] = forms.CharField(label='Notes',required=False,widget=forms.Textarea(attrs={ 'class': 'form-control' }))
class Meta(object):
model = Entities
fields = ('name','company','notes')
# Méthodes de nettoyage des champs du formulaire
def clean_name(self):
name = self.cleaned_data['name']
return name
def clean_company(self):
company = self.cleaned_data['company']
return company
def clean_notes(self):
notes = self.cleaned_data['notes']
return notes
视图.py
class Entities(models.Model):
company = models.ForeignKey(Companies, on_delete=models.CASCADE)
name = models.CharField(max_length=50, blank=False, null=False)
notes = models.TextField(blank=True, null=True)
class Meta:
# Constraint here (entity name + company combination name must be unique)
constraints = [models.UniqueConstraint(fields=['name', 'company'], name='unique_company_entity')]
managed = True
db_table = 'entities'
def __str__(self):
object_name = self.name + " " + self.company.name
return object_name
class Companies(models.Model):
name = models.CharField(max_length=50, blank=False, null=False)
notes = models.CharField(max_length=50, blank=True, null=True)
class Meta:
managed = True
db_table = 'companies'
def __str__(self):
object_name = self.name
return object_name
def entity_edit(request,entity_id):
companies = Companies.objects.all().order_by('name')
entity_id = int(entity_id)
entity = Entities.objects.get(id = entity_id)
if request.method == 'POST':
form = EntityEditForm(request.POST,instance=entity)
if form.is_valid():
post_result = form.save(commit=True)
redirect_url_valid = "/contacts/companies/entities/" + str(entity.id) + "/view/"
return redirect(redirect_url_valid)
else:
form = EntityEditForm(instance=entity)
return render(request,'entity_edit_form.html',{
'companies': companies,
'entity': entity,
'form': form
})
class EntityEditForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.label_suffix = ''
self.fields['name'] = forms.CharField(label='Name',widget=forms.TextInput(attrs={ 'class': 'form-control' }))
self.fields['company'] = forms.ModelChoiceField(queryset=Companies.objects.all(),label='Company',required=True,widget=forms.Select(attrs={ 'class': 'form-control' }))
self.fields['notes'] = forms.CharField(label='Notes',required=False,widget=forms.Textarea(attrs={ 'class': 'form-control' }))
class Meta(object):
model = Entities
fields = ('name','company','notes')
# Méthodes de nettoyage des champs du formulaire
def clean_name(self):
name = self.cleaned_data['name']
return name
def clean_company(self):
company = self.cleaned_data['company']
return company
def clean_notes(self):
notes = self.cleaned_data['notes']
return notes
forms.py
class Entities(models.Model):
company = models.ForeignKey(Companies, on_delete=models.CASCADE)
name = models.CharField(max_length=50, blank=False, null=False)
notes = models.TextField(blank=True, null=True)
class Meta:
# Constraint here (entity name + company combination name must be unique)
constraints = [models.UniqueConstraint(fields=['name', 'company'], name='unique_company_entity')]
managed = True
db_table = 'entities'
def __str__(self):
object_name = self.name + " " + self.company.name
return object_name
class Companies(models.Model):
name = models.CharField(max_length=50, blank=False, null=False)
notes = models.CharField(max_length=50, blank=True, null=True)
class Meta:
managed = True
db_table = 'companies'
def __str__(self):
object_name = self.name
return object_name
def entity_edit(request,entity_id):
companies = Companies.objects.all().order_by('name')
entity_id = int(entity_id)
entity = Entities.objects.get(id = entity_id)
if request.method == 'POST':
form = EntityEditForm(request.POST,instance=entity)
if form.is_valid():
post_result = form.save(commit=True)
redirect_url_valid = "/contacts/companies/entities/" + str(entity.id) + "/view/"
return redirect(redirect_url_valid)
else:
form = EntityEditForm(instance=entity)
return render(request,'entity_edit_form.html',{
'companies': companies,
'entity': entity,
'form': form
})
class EntityEditForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.label_suffix = ''
self.fields['name'] = forms.CharField(label='Name',widget=forms.TextInput(attrs={ 'class': 'form-control' }))
self.fields['company'] = forms.ModelChoiceField(queryset=Companies.objects.all(),label='Company',required=True,widget=forms.Select(attrs={ 'class': 'form-control' }))
self.fields['notes'] = forms.CharField(label='Notes',required=False,widget=forms.Textarea(attrs={ 'class': 'form-control' }))
class Meta(object):
model = Entities
fields = ('name','company','notes')
# Méthodes de nettoyage des champs du formulaire
def clean_name(self):
name = self.cleaned_data['name']
return name
def clean_company(self):
company = self.cleaned_data['company']
return company
def clean_notes(self):
notes = self.cleaned_data['notes']
return notes
您确定初始化表单时使用的
实例
是正确的实例吗?在执行唯一性验证时,模型
仅查找数据库中包含相同值的其他行,实例本身除外。所以我对你为什么会犯这个错误感到困惑。@dirkgroten:你把我的错误放在了正确的轨道上。它现在似乎起作用了,因为我错误地忘记了提交视图中的修改,views.py代码实际上是:form=EntityEditForm(request.POST),而不是form=EntityEditForm(request.POST,instance=entity)。因此Django试图插入一个副本,而不是更新现有数据。