如何在javascrript中使用inlineformset工厂?

问题描述

我想在我的项目中使用 inlineformset factory!我已经编写了自己的 js 来添加更多字段,但它只将最后一个表单保存在子表单中!我不想使用jquery.formset.js 这是我的models.py

class Main(models.Model):
     admin = models.ForeignKey(User,on_delete=models.CASCADE)
     company = models.ForeignKey(Companies,on_delete=models.CASCADE)
     items = models.ManyToManyField(Item,through='Child')
     invoice_number = models.IntegerField()

class Child(models.Model):
     main = models.ForeignKey(Main,on_delete=models.CASCADE)
     item = models.ForeignKey(Item,on_delete=models.CASCADE)
     quantity = models.IntegerField()

这是我的 views.py ,我使用了基于类的视图

class CreateMainInlineFormset(LoginrequiredMixin,SuccessMessageMixin,CreateView):
    model = Main
    form_class = MainForm
    template_name = 'main/create.html'
    def get_context_data(self,*args,**kwargs):
        data = super().get_context_data(*args,**kwargs)
        if self.request.POST:
            data['items'] = ChildInlineFormSet(self.request.POST)
            data['items'].full_clean()
        else:
            data['items'] = ChildInlineFormSet()
        return data

    def form_valid(self,form):
        context = self.get_context_data()
        items = context['items']

        with transaction.atomic():
            self.object = form.save(commit=False)
            form.instance.admin = self.request.user
            if items.is_valid() and form.is_valid() and items.cleaned_data!={}:
                items.instance = self.object
                form.save(commit=True)
                items.save()
            else:
                return render(self.request,self.template_name,context)
    
        return super().form_valid(form)
    def get_success_url(self):
        return reverse_lazy('maininfo:list-item')

这是我的模板html + js脚本,我认为问题出在这里,我不知道如何以正确的方式增加子表单!

   $("#addRow").click(function () {
    var html = $("#relInputs").clone();
    $('#relatiedInput').append(html);
  });

  $(document).on('click','#removeRow',function () {
    if ($("#relatiedInput> #relInputs").length != 1)
      $(this).closest('#relInputs').remove();
  });
<div class="mt-1 text-right mx-auto" style="direction: rtl;">
    <form action="" method="POST">{% csrf_token %}
      {{items.management_form}}

      <div id="allInputs">

        <div class=" grid grid-cols-1 md:grid-cols-3 gap-5">

          <div class="flex flex-wrap border grayBG rounded-tl-lg rounded-bl-lg ">
            <p
              class="w-3/12 bg-red-500 flex scale-100 items-center justify-center whiteCOLOR rounded-tl-lg rounded-bl-lg">
              company:
            </p>
            {{form.company | add_class:'w-7/12 p-2 rounded-tl-lg rounded-bl-lg  focus:outline-none text-right grayBG whiteCOLOR'}}
            <!-- error -->
            {% if form.company.errors %}
              <div class="redCOLOR pb-1 my-0 text-center rounded-lg w-full md:w-6/12 mx-auto">{{form.collection.errors}}</div>
              {% endif %}

          </div>

          <div class="flex flex-wrap border grayBG rounded-tl-lg rounded-bl-lg ">
            <p
              class="w-4/12 bg-red-500 flex scale-100 items-center justify-center whiteCOLOR rounded-tl-lg rounded-bl-lg">
              invoice number:
            </p>
            {{ form.invoice_number | add_class:'w-7/12 p-2 rounded-tl-lg rounded-bl-lg  focus:outline-none text-right grayBG whiteCOLOR' }}

            <!-- error -->
            {% if form.invoice_number.errors %}
            <div class="redCOLOR pb-1 my-0 text-center rounded-lg w-full md:w-6/12 mx-auto">{{form.invoice_number.errors}}</div>
            {% endif %}

          </div>

        </div>

        <div id="relatiedInput" class="w-full grayBG p-2 mt-6 rounded-lg">
          {% for item in items.forms %}

          {{item.id}}    

          <div  id="relInputs"  class="border p-2 rounded-lg mb-4 mt-3 inp">
            <button id="removeRow" type="button" class="bg-red-500 whiteCOLOR px-2 py-1 rounded mb-1"><i class="fas fa-trash"></i></button>
            
            <div class="grid grid-cols-1 md:grid-cols-3 gap-2 mt-3">

              <div class="flex flex-wrap border grayBG rounded-tl-lg rounded-bl-lg ">
                <p
                  class="w-5/12 whiteBG flex scale-100 items-center justify-center grayCOLOR rounded-tl-lg rounded-bl-lg">
                  item:
                </p>
                {{item.item | add_class:'w-7/12 p-2 rounded-tl-lg rounded-bl-lg  focus:outline-none text-right grayBG whiteCOLOR'}}

                 <!-- error -->
                 {% if item.item.errors %}
            <div class="redCOLOR pb-1 my-0 text-center rounded-lg w-full md:w-6/12 mx-auto">{{item.item.errors}}</div>
            {% endif %}
              </div>
              <div class="flex flex-wrap border grayBG rounded-tl-lg rounded-bl-lg ">
                <p
                  class="w-5/12 whiteBG flex scale-100 items-center justify-center grayCOLOR rounded-tl-lg rounded-bl-lg">
                  quantity:
                </p>
                {{item.quantity | add_class:'w-7/12 p-2 rounded-tl-lg rounded-bl-lg  focus:outline-none text-right grayBG whiteCOLOR'}}
                <!-- error -->
                {% if item.quantity.errors %}
                <div class="redCOLOR pb-1 my-0 text-center rounded-lg w-full md:w-6/12 mx-auto">{{item.selling_price.errors}}</div>
               {% endif %}  
              </div>
            </div>
          </div>
          {% endfor %}
        </div>

      </div>

        <div class="mt-10">
          <button class="grayBG px-6 rounded-lg py-2  whiteCOLOR">
            <i class="fas fa-save redCOLOR"></i>
            submit
          </button>
        </div>
      </div>
    </form>
  </div>
搜索了很多,但没有得到任何解决方案! 我将感谢您的帮助

解决方法

我就是这样做的

JS:

let container = document.querySelector("#form-container")
let birdForm = document.querySelectorAll(".ingredient-form")
let addButton = document.querySelector("#add-form")
let totalForms = document.querySelector("#id_recipeingredients_set-TOTAL_FORMS")    
let formNum = birdForm.length-1 
 
function addForm(e){
        let newForm = birdForm[0].cloneNode(true)
        let formRegex = RegExp(`recipeingredients_set-(\\d){1}-`,'g')
        formNum++
        newForm.innerHTML = newForm.innerHTML.replace(formRegex,`recipeingredients_set-${formNum}-`)
        let deleteButton = document.createElement('input')
        deleteButton.type = "button"
        deleteButton.value = "Delete"
        deleteButton.className = "delete-btn"
        newForm.appendChild(deleteButton)
        deleteButton.addEventListener('click',deleteForm)
        container.insertBefore(newForm,addButton)
        totalForms.setAttribute('value',`${formNum+1}`)
    }
 
    function deleteForm(e){
        formNum--
        e.target.parentNode.remove()
        totalForms.setAttribute('value',`${formNum+1}`)
    }

蟒蛇:

class RecipeCreateView(LoginRequiredMixin,CreateView):
 
    template_name = 'recipes/create.html'
    form_class = RecipeModelForm
    queryset = Recipe.objects.all()
    success_url = reverse_lazy('recipes:main-recipe-view')
 
    def get(self,request,*args,**kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        ingredient_form = IngredientFormSet()
 
        for n in ingredient_form:
            n.fields['unit'].queryset = FoodWeight.objects.none()
        return self.render_to_response(self.get_context_data(form=form,ingredient_form=ingredient_form))
 
    def post(self,**kwargs):
        self.object = None
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        ingredient_form = IngredientFormSet(self.request.POST)
        if form.is_valid() and ingredient_form.is_valid():
            return self.form_valid(form,ingredient_form)
        else:
            return self.form_invalid(form,ingredient_form)
 
    def form_valid(self,form,ingredient_form):
        self.object = form.save(commit=False)
        self.object.author = self.request.user.profile
 
        self.object.save()
        form.save_m2m()
        if self.object.published:
            create_action(self.request.user,'Added new recipe.',self.object)
        ingredient_form.instance = self.object
        ingredient_form.save()
        return HttpResponseRedirect(self.get_success_url())

模板:

<form id="form-container" data-unit-url={% url 'recipes:load_weights' %} method='POST' enctype="multipart/form-data">
    {% csrf_token %}
    {{ ingredient_form.management_form }}
    {{ form.as_p }}
 
    {% for form in ingredient_form %}
    <div class="ingredient-form">
        {{form}}
    </div>
    {% endfor %}
    <button id="add-form" type="button">Add another ingredient</button>
    <input type="submit" value="Post recipe">
</form>