I have inline formset:
JustificationFormset = inlineformset_factory(
ClpPcn, Justification, form = JustificationForm,
extra=0,
validate_min=True,
can_delete = True, can_delete_extra = True,
)
I am trying to delete forms marked as deleted in my view:
def formset_valid(self, formset):
justifications = formset.save(commit=False)
for obj in formset.deleted_objects:
obj.delete()
for justification in justifications:
justification.dossier = self.object
justification.save()
The formset is created this way in my view:
def get_formset(self):
if self.request.method == "GET":
return JustificationFormset(prefix='justification')
else:
return JustificationFormset(self.request.POST or None, prefix='justification')
However forms marked as DELETE are not deleted, they are still present in the formset. What am I doing wrong?
This is correct - this is how formsets work. The purpose of the delete flag in the formset is to allow the backend to delete the underlying data in the model associated with that form. The actual form is not to be deleted.
This is referenced and documented at:
From the documentation:
If you call formset.save(commit=False)
, objects will not be deleted automatically. You’ll need to call delete()
on each of the formset.deleted_objects
to actually delete them:
I thought that’s what I am doing in my view:
def formset_valid(self, formset):
justifications = formset.save(commit=False)
for obj in formset.deleted_objects:
obj.delete()
for justification in justifications:
justification.dossier = self.object
justification.save()
Yes, that deletes the objects referenced by the form, but it does not delete the form itself.
I don’t understand. How can I delete the form then?
You don’t.
I’m not sure I’m understanding what your underlying objective is here, or why you think this is either necessary or desirable,
Everytime you’re creating the instance of the formset, you’re creating a new set of forms. It’s not like these forms persist across multiple view invocations.
How can I delete data saved in DELETED form? They are still in my database.
It should delete data from database?
Yes.
I think we may need to see the entire view at this point.
class ClpPcnEditParentView():
model = ClpPcn
form_class = ClpPcnForm
template_name = 'clp_pcn_form.html'
def form_valid(self, form):
self.object = form.save(commit=False)
# validate formset
formset = self.get_formset()
if not formset.is_valid():
return self.render_to_response(self.get_context_data(form=form, justification=formset))
# save object to db
self.object.save()
form.save_m2m()
# save formset
self.formset_valid(formset)
return redirect(self.get_success_url())
def formset_valid(self, formset):
justifications = formset.save(commit=False)
for obj in formset.deleted_objects:
obj.delete()
for justification in justifications:
justification.dossier = self.object
justification.save()
def form_invalid(self, form):
return self.render_to_response(self.get_context_data(form=form))
class ClpPcnCreateView(ClpPcnEditParentView, CreateView):
def get_context_data(self, **kwargs):
data = super(ClpPcnCreateView, self).get_context_data(**kwargs)
if 'justification' not in data.keys():
data['justification'] = self.get_formset()
data['is_update'] = 0
return data
def get_formset(self):
if self.request.method == "GET":
return JustificationFormset(prefix='justification')
else:
return JustificationFormset(self.request.POST or None, prefix='justification')
def get_success_url(self):
return 'pcn:create-mixture'
Just making a guess here, but I’d be interested in determining whether the deletes are being issued and then the data is being resaved in the for justification in justifications
loop, because you’re not checking to see if an instance of justification
is to be deleted.
You’ve got a couple ways to test / verify this:
- Add some print statements in
formset_valid
to show what’s being saved or deleted
- Swap the order of the two
for
loops
- Restructure your test such that you’re only looping over the forms once - if it’s in the
formset.deleted_objects
then delete it, otherwise, update and save it.
I have found out that the issue is in my UpdateView:
class ClpPcnUpdateView(ClpPcnEditParentView, UpdateView):
def get_context_data(self, **kwargs):
data = super(ClpPcnUpdateView, self).get_context_data(**kwargs)
data['pcn_number'] = self.kwargs['pk']
data['justification'] = self.get_formset()
data['is_update'] = 1
return data
def get_formset(self):
return JustificationFormset(self.request.POST or None, instance=self.object, prefix='justification')
def get_success_url(self):
return self.request.path_info
It seems that the problem is in get_formset(). When I try to save the formset it is invalid.
The problem was in my template. I use crispy forms and the hidden_fields were missing:
{% for jform in justification.forms %}
{{ jform.management_form }}
<tr class="formset_row">
<td id="td_id_0">
{% crispy jform %}
So I added the hidden_fields and now it is working:
{% for jform in justification.forms %}
{{ jform.management_form }}
<tr class="formset_row">
<td id="td_id_0">
{% for hidden in jform.hidden_fields %}
{{ hidden }}
{% endfor %}
{% crispy jform %}
Thank you for your time and navigating me!