For some reason my implementation of django-dynamic-formset is acting a little funny.
It is creating two add/remove links for each dynamic formset in my template.
I have been fiddling around trying to figure this out for a bit and its gotten the best of me.
here is a screen shot of the error i am talking about
i can also provide a login if you would like to trigger the error on your own here is my template:
<head>
<script type="text/javascript" src="{{ STATIC_URL }}jquery.formset.js"></script>
<script type="text/javascript">
$(function() {
$('#ingredients tbody tr').formset({
prefix: '{{ ingredients_formset.prefix }}',
formCssClass: 'dynamic-ingredients'
});
$('#steps tbody tr').formset({
prefix: '{{ steps_formset.prefix }}',
formCssClass: 'dynamic-steps'
});
})
</script>
</head>
<body>
<form action="{% url cookbook.views.createrecipe %}" method="POST" id="ingredients">
{% csrf_token %}
<table>
<tbody>
<tr>
<label>
Ingredients:
</label>
</tr>
<tr>
<td>
<input type="text" cols="40" rows="10" />
</td>
</tr>
</tbody>
</table>
</form>
<form action="{% url cookbook.views.createrecipe %}" method="POST" id="steps">
{% csrf_token %}
<table>
<tbody>
<label>
Steps:
</label>
<tr>
<td>
<input type="text" cols="40" rows="10" />
</td>
</tr>
</tbody>
</table>
</form>
</body>
here is the forms.py
class RecipeForm(forms.ModelForm):
reset_recipe = forms.CharField(widget=forms.HiddenInput(), required = False)
class Meta:
model = Recipe
widgets = {'original_cookbook':forms.HiddenInput(),
'pub_date':forms.HiddenInput(),
'author':forms.HiddenInput()}
fields =("name", "picture","ingredients","steps","prep_time","type",'reset_recipe')
class CookbookForm(forms.ModelForm):
class Meta:
model = Cookbook
class StepsForm(forms.Form):
Step = forms.CharField()
StepsFormSet = formset_factory(RecipeForm, StepsForm, can_order=True, can_delete=True, extra = 0)
class IngredientsForm(forms.Form):
Ingredient = forms.CharField()
IngredientsFormSet = formset_factory(RecipeForm, IngredientsForm, can_order=True, can_delete=True, extra = 0)
and the view:
def createrecipe(request):
RecipeForm = RecipeForm(request.POST)
IngredientsFormSet = formset_factory(IngredientsForm)
StepsFormSet = formset_factory(StepsForm)
if request.method == 'POST':
form = RecipeForm(request.POST)
ingredients_formset = IngredientsFormSet(request.POST, request.FILES, prefix='ifs')
steps_formset = StepsFormSet(request.POST, request.FILES, prefix='sfs')
if form.is_valid() and ingredients_formset.is_valid() and steps_formset.is_valid():
print "form is valid"
new_recipe = form.save(commit=False)
new_recipe.original_cookbook = request.user.cookbooks.all()[0]
new_recipe.author = request.user.cookbooks.all()[0].name
new_recipe.steps = steps_formset
new_recipe.ingredients = ingredients_formset
new_recipe.save()
cookbooks = request.user.cookbooks.all()
cookbook = cookbooks[0]
cookbook.recipes.add(new_recipe)
form.save_m2m()
t = loader.get_template('cookbook/create_form.html')
c = RequestContext(request, {
'form': new_recipe,
})
data = {
'replace': True,
'form': t.render(c),
'success': True,
}
json = simplejson.dumps(data)
return HttpResponse(json, mimetype='text/plain')
else:
print "form is invalid"
form = RecipeForm(request.POST)
ingredients_formset = IngredientsFormSet(request.POST, request.FILES, prefix='ifs')
steps_formset = StepsFormSet(request.POST, request.FILES, prefix='sfs')
t = loader.get_template('cookbook/create_form.html')
c = RequestContext(request, {
'form':form,
})
data ={
'form': t.render(c),
'success': False,
}
json = simplejson.dumps(data)
return HttpResponse(json, mimetype='text/plain')
You can use the amazing django-dynamic-formset jQuery plugin by ELO80KA
I'm using it on a project right now, let me show you how I'm doing it right now, lets take a look of the markup:
Then, in the javascript you need to do the correct selector (where the fields of your formset lives), this is where the plugin will grab the code to clone it with the proper ids and names, don't forget to pase it the "prefix" of the formset:
The plugin will automatically create remove and add button.