传统方法(基于方法的视图):http://stellarchariot.com/blog/2011/02/dynamically-add-form-to-formset-using-javascript-and-django/
概要:
服务器端,使用了formset , 文档在这里:https://docs.djangoproject.com/en/dev/topics/forms/formsets/
客户端,使用脚本动态添加内容。
class based view ,参考这里:http://kevindias.com/writing/django-class-based-views-multiple-inline-formsets/
总结:
重写了get/post方法。
要点:
1. form里面做关联:
# forms.py
from django.forms import ModelForm
from django.forms.models import inlineformset_factory from .models import Recipe, Ingredient, Instruction class RecipeForm(ModelForm):
class Meta:
model = Recipe IngredientFormSet = inlineformset_factory(Recipe, Ingredient)
InstructionFormSet = inlineformset_factory(Recipe, Instruction)
2. 重写post/get方法,并在里面对子表初始化,注意get里面构造时无参,post里有参。
ingredient_form = IngredientFormSet() vs ingredient_form = IngredientFormSet(self.request.POST)
class RecipeCreateView(CreateView):
template_name = 'recipe_add.html'
model = Recipe
form_class = RecipeForm
success_url = 'success/' def get(self, request, *args, **kwargs):
"""
Handles GET requests and instantiates blank versions of the form
and its inline formsets.
"""
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
ingredient_form = IngredientFormSet()
instruction_form = InstructionFormSet()
return self.render_to_response(
self.get_context_data(form=form,
ingredient_form=ingredient_form,
instruction_form=instruction_form)) def post(self, request, *args, **kwargs):
"""
Handles POST requests, instantiating a form instance and its inline
formsets with the passed POST variables and then checking them for
validity.
"""
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
ingredient_form = IngredientFormSet(self.request.POST)
instruction_form = InstructionFormSet(self.request.POST)
if (form.is_valid() and ingredient_form.is_valid() and
instruction_form.is_valid()):
return self.form_valid(form, ingredient_form, instruction_form)
else:
return self.form_invalid(form, ingredient_form, instruction_form)
3. 保存时做关联:
ingredient_form.instance = self.object
def form_valid(self, form, ingredient_form, instruction_form):
"""
Called if all forms are valid. Creates a Recipe instance along with
associated Ingredients and Instructions and then redirects to a
success page.
"""
self.object = form.save()
ingredient_form.instance = self.object
ingredient_form.save()
instruction_form.instance = self.object
instruction_form.save()
return HttpResponseRedirect(self.get_success_url())
4. 模板注意包含两个隐藏域:
{{ ingredient_form.management_form }}
{{ ingredient_form.non_form_errors }}
3. 自己写了个demo,完整代码看这里: https://github.com/TommyU/dynamic_form/