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