【问题标题】:Django form with multiple models and dynamic quantity of models具有多个模型和动态模型数量的 Django 表单
【发布时间】:2015-09-11 06:44:18
【问题描述】:

我正在创建一个创建动态数量模型的表单。 FormSets 似乎是这项工作的工具,但我找不到使用多个模型的示例。

使用this example 中的模型(AuthorBook),我的表单集只需要一个Author 表单,并且至少需要一个Book 表单。用户可以向作者添加任意数量的书籍,所有书籍都在同一个表单(集)内。

在 Django 后端完成此任务的最佳方法是什么?

将 JSON 发布到 REST api 以创建这些模型会更好吗?

【问题讨论】:

    标签: django django-models django-forms django-rest-framework


    【解决方案1】:

    This example 是您正在寻找的。它解释了如何使用内联表单集来填充模型父母和孩子:

    # models.py
    from django.db import models
    
    class Recipe(models.Model):
        title = models.CharField(max_length=255)
        description = models.TextField()
    
    
    class Ingredient(models.Model):
        recipe = models.ForeignKey(Recipe)
        description = models.CharField(max_length=255)
    
    
    class Instruction(models.Model):
        recipe = models.ForeignKey(Recipe)
        number = models.PositiveSmallIntegerField()
        description = models.TextField()
    

    # 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)
    

    # views.py
    from django.http import HttpResponseRedirect
    from django.views.generic import CreateView
    
    from .forms import IngredientFormSet, InstructionFormSet, RecipeForm
    from .models import Recipe
    
    
    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)
    
        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())
    
        def form_invalid(self, form, ingredient_form, instruction_form):
            """
            Called if a form is invalid. Re-renders the context data with the
            data-filled forms and errors.
            """
            return self.render_to_response(
                self.get_context_data(form=form,
                                      ingredient_form=ingredient_form,
                                      instruction_form=instruction_form))
    

    <!-- recipe_add.html -->
    <!DOCTYPE html>
    <html>
    <head>
        <title>Multiformset Demo</title>
        <script src="{{ STATIC_URL }}js/jquery.min.js"></script>
        <script src="{{ STATIC_URL }}js/jquery.formset.js"></script>
        <script type="text/javascript">
            $(function() {
                $(".inline.{{ ingredient_form.prefix }}").formset({
                    prefix: "{{ ingredient_form.prefix }}",
                })
                $(".inline.{{ instruction_form.prefix }}").formset({
                    prefix: "{{ instruction_form.prefix }}",
                })
            })
        </script>
    </head>
    
    <body>
        <div>
            <h1>Add Recipe</h1>
            <form action="." method="post">
                {% csrf_token %}
                <div>
                    {{ form.as_p }}
                </div>
                <fieldset>
                    <legend>Recipe Ingredient</legend>
                    {{ ingredient_form.management_form }}
                    {{ ingredient_form.non_form_errors }}
                    {% for form in ingredient_form %}
                        {{ form.id }}
                        <div class="inline {{ ingredient_form.prefix }}">
                            {{ form.description.errors }}
                            {{ form.description.label_tag }}
                            {{ form.description }}
                        </div>
                    {% endfor %}
                </fieldset>
                <fieldset>
                    <legend>Recipe instruction</legend>
                    {{ instruction_form.management_form }}
                    {{ instruction_form.non_form_errors }}
                    {% for form in instruction_form %}
                        {{ form.id }}
                        <div class="inline {{ instruction_form.prefix }}">
                            {{ form.number.errors }}
                            {{ form.number.label_tag }}
                            {{ form.number }}
                            {{ form.description.errors }}
                            {{ form.description.label_tag }}
                            {{ form.description }}
                        </div>
                    {% endfor %}
                </fieldset>
                <input type="submit" value="Add recipe" class="submit" />
            </form>
        </div>
    </body>
    </html>
    

    通过这种方式(假设您使用基于类的视图),它将允许您在表单集中定义任意数量的表单。

    查看inlineformset_factory signature,了解如何定义每个表单集需要多少个表单。

    要处理创建的表单的动态数量,您可以指定extra、min_num 和 max_num

    那么对于显示来说,我认为使用 javascript 是最方便的选择。 This 是您可以找到答案的地方。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-13
      • 1970-01-01
      • 1970-01-01
      • 2019-03-15
      • 1970-01-01
      • 1970-01-01
      • 2016-11-06
      • 2017-05-31
      相关资源
      最近更新 更多