傳統方法(基於方法的視圖):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/
