I’m trying to build a FBV (django version 4.2) that updates, at once, selected records. Here’s the current code:
def edit_selected_accountsplan(request):
selected_items_str = request.GET.get('items', '')
selected_items = [int(item) for item in selected_items_str.split(',') if item.isdigit()]
AccountsPlanFormSet = formset_factory(form=AccountsPlanForm, extra=0)
if request.method == 'POST':
formset = AccountsPlanFormSet(request.POST)
if formset.is_valid():
for form, accountplan in zip(formset, selected_items):
instance = AccountsPlan.objects.get(pk=accountplan)
form.instance = instance
instance.subgroup = form.cleaned_data['subgroup']
instance.name = form.cleaned_data['name']
instance.active = form.cleaned_data['active']
instance.save()
return redirect('confi:list_accountsplan')
else:
initial_data = []
for accountplan in selected_items:
instance = AccountsPlan.objects.get(pk=accountplan)
initial_data.append({
'subgroup': instance.subgroup,
'name': instance.name,
'active': instance.active,
'id': instance.id,
})
formset = AccountsPlanFormSet(initial=initial_data)
return render(request, 'confi/pages/accountsplan/edit_selected_accountsplan.html', context={
'formset': formset,
})
The model code:
class AccountsPlan (models.Model):
subgroup = models.ForeignKey(Subgroups, on_delete=models.PROTECT)
name = models.CharField(
max_length=100,
unique=True,
error_messages={
'unique': "An account with this name already exists. Please, choose another.",
}
)
active = models.BooleanField(default=True)
show_acc = models.BooleanField(default=True)
show_man = models.BooleanField(default=True)
class Meta:
verbose_name_plural = 'AccountPlans'
def __str__(self):
return self.name
And the form code:
class AccountsPlanForm(forms.ModelForm):
subgroup = ModelChoiceField(
queryset=Subgroups.objects.filter(
Q(active=True),
~Q(code=5.5)
).order_by('name__unaccent'),
label='Subgrupo',
empty_label='SELECIONE',
)
name = forms.CharField(
label='Nome',
required=True,
error_messages={'required': ''},
)
active = forms.BooleanField(
label='Ativo',
required=False,
)
show_acc = forms.BooleanField(
label='Aparece Contábil',
required=False,
)
show_man = forms.BooleanField(
label='Aparece Gerencial',
required=False,
)
def clean_name(self):
return self.cleaned_data['name'].upper()
class Meta:
model = AccountsPlan
fields = '__all__'
The code works as expected, the page loads and the formset is filled correctly. The problem is when I try to save the data. Because the ‘name’ field is defined as unique in the database, when I try to change other fields but don’t change the name, it gives me the unique error message defined in the model’s ‘name’ field. If I change the name to anything else that is not already in the database, the data is saved correctly.
Since I don’t have this issue when using the form directly (I have a view that edits a single record and in that view even if I don’t change the name, the data is saved) and I’m getting the instance on the formset, I don’t know why this is happening. Maybe I’m missing something obvious here, but shouldn’t this error message trigger only when creating new data or when editing and changing the unique field? Is there a specific way to make the formset behave exacly like it does when only the form is used? Thanks!