如何使用ModelForm使用唯一约束更新Django模型数据?

如何使用ModelForm使用唯一约束更新Django模型数据?,django,python-3.x,database,constraints,Django,Python 3.x,Database,Constraints,我有两个模型,其中一个是用约束定义的(参见下面的“实体”模型) 我构建了两个表单,一个用于创建新模型数据,另一个用于更新模型数据。“创建表单”工作正常,但“更新表单”会抛出一个错误,说明已存在项的数量(我的约束基于两个字段的唯一组合)。无论我在更新表单中修改哪个字段,都会抛出相同的错误 例如,在“实体”实例中仅修改“注释”字段会导致以下错误 具有此名称和公司的实体已存在 如何正确地实现我的表单(和/或模型),以便保留约束(具有相同名称的实体在公司中必须是唯一的),并且修改非约束字段不会引发错误

我有两个模型,其中一个是用约束定义的(参见下面的“实体”模型)

我构建了两个表单,一个用于创建新模型数据,另一个用于更新模型数据。“创建表单”工作正常,但“更新表单”会抛出一个错误,说明已存在项的数量(我的约束基于两个字段的唯一组合)。无论我在更新表单中修改哪个字段,都会抛出相同的错误

例如,在“实体”实例中仅修改“注释”字段会导致以下错误

具有此名称和公司的实体已存在

如何正确地实现我的表单(和/或模型),以便保留约束(具有相同名称的实体在公司中必须是唯一的),并且修改非约束字段不会引发错误

型号.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
视图.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试图插入一个副本,而不是更新现有数据。