Reputation: 93
I feel like I must be missing something obvious but I am having a problem where my model formsets insist on retaining their data after submission. I am creating a page that allows a user to create a project and then add an arbitrary amount of materials to that project. JavaScript is taking care of dynamically adding new instances of the formset as needed. The code works fine the first time through, after that it "remembers" previous data. It happens for the material formset but not for the regular model form above it.
I'm thinking it must have something to do with the way I am creating my model formset. When the page is requested the view seems to be passing back the formset bound to old data rather than an unbound set. I'm new to Django and am trying to teach myself so there are probably things at work I do not quite grasp yet. Below is the code for the view:
def addproject_page(request):
# Define the formset to use to add the materials
MaterialFormSet = modelformset_factory(Material, exclude = ('project',))
# Check to see if there is some POST data from an attempt to fill out the form
if request.method == 'POST':
# Create a form for the project and for the material and use a prefix to separate the POST data for the two
project_form = ProjectForm(request.POST, prefix='project')
# Instantiate the formset to display multiple materials when creating a project
material_formset = MaterialFormSet(request.POST, prefix='material')
# Check both forms with the validators and if both are good process the data
if project_form.is_valid() and material_formset.is_valid():
# Save the data for the newly created project
created_project = project_form.save()
# Tell each material to be associated with the above created project
instances = material_formset.save(commit=False)
for instance in instances:
instance.project = created_project
instance.save()
# After the new project and its materials are created, go back to the main project page
return HttpResponseRedirect('/members/projects/')
# If there is no post data, create and show the blank forms
else:
project_form = ProjectForm(prefix='project')
material_formset = MaterialFormSet(prefix='material')
return render(request, 'goaltracker/addproject.html', {
'project_form': project_form,
'material_formset': material_formset,
})
Edit to add in my template code too in case it helps:
{% extends "base.html" %}
{% block external %}
<script src="{{ static_path }}js/projects.js" type="text/javascript"></script>
{% endblock %}
{% block title %}: Add Project{% endblock %}
{% block content %}
<h1>Add a Project</h1>
<form id="new_project_form" method="post" action="">
{{ project_form.as_p }}
<!-- The management form must be rendered first when iterating manually -->
<div>{{ material_formset.management_form }}</div>
<!-- Show the initial blank form(s) before offering the option to add more via JavaScript -->
{% for material_form in material_formset.forms %}
<div>{{ material_form.as_p }}</div>
{% endfor %}
<input type="button" value="Add Material" id="add_material">
<input type="button" value="Remove Material" id="remove_material">
<input type="submit" value="add" />
</form>
{% endblock %}
Upvotes: 3
Views: 936
Reputation: 1439
Answer of the question the old data is always persists in modelformset
is here. https://docs.djangoproject.com/en/1.8/topics/forms/modelforms/#changing-the-queryset as it is given in the docs chenge the queryset by overriding the constructor of the basemodelformset
from django.forms.models import BaseModelFormSet
from myapp.models import Author
class CalendarFormset(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(CalendarFormset, self).__init__(*args, **kwargs)
self.queryset = Calendar.objects.none()
A same problem was discussed here
django modelformset_factory sustains the previously submitted data even after successfully created the objects
Upvotes: 0
Reputation: 308849
I think you need to use a custom queryset, so that your formset is instantiated with an empty queryset. You need to specify the queryset in the POST
and GET
branches of your if
statement.
if request.method == "POST":
...
material_formset = MaterialFormSet(request.POST, prefix='material', queryset=Material.objects.none())
...
else:
material_formset = MaterialFormSet(prefix='material', queryset=Material.objects.none())
At the moment, your formset is using the default queryset, which contains all objects in the model.
Upvotes: 3