Django Formset Delete Field Not Showing

Viewed 1175

I need to manually render my formset in my template and I cannot get the delete checkbox field into the template when I render manually. However, it does show when I render {{form.as_table}}.

views.py

QuoteManifestForm= modelformset_factory(QuoteManifest, QManifestForm, can_delete = True)

template - this does not display the {{form.DELETE}} but every other field shows fine, including id which I can see in the DOM.

{{ manifest.management_form }} <--!I passed QuoteManifestForm to template as 'manifest'-->

          {% for form in manifest.forms %}
            <div id="form_set">
                <table id = 'manifest-table25' class="manifest-table2" width=100%>
                  {% csrf_token %}
                  <tbody width=100%>
                    <tr class="manifest-row">
                      <td width = 17.5% class="productCode" onchange="populateProduct(this)">{{form.ProductCode}}</td>
                      <td width = 32.5% class="description">{{form.DescriptionOfGoods}}</td>
                      <td width = 12.5% class="quantity" oninput="calculateUnit(this)">{{form.UnitQty}}</td>
                      <td width = 12.5% class="unitType">{{form.Type}}</td>
                      <td width = 12.5% class="price" oninput="calculate(this)">{{form.Price}}</td>
                      <td width = 12.5% class="amount2">{{form.Amount}}</td>
                      <td>{{form.DELETE}}</td>
                      {{form.id}}
                    </tr>
                  </tbody>
                </table>
            </div>
            {% endfor %}

Any idea why that is not working?

UPDATE:

I found in the django docs that if you are rendering manually, you should include something like the below in your form. I tried this, but still no Delete field appears in my template:

{% if form2.can_delete %}
  <td> {{form.DELETE}}</td>
{% endif %}

CODE TO REPRODUCE

views.py

def QuoteView(request):
    QuoteManifestForm= modelformset_factory(QuoteManifest, fields =('ProductCode', 'DescriptionOfGoods', 'UnitQty', 'Type','Amount', 'Price'), can_delete = True)
    if request.method == "POST":
       form2 = QuoteManifestForm(request.POST)
       form2.save()

       return redirect('HomeView')

    else:
       form2 = QuoteManifestForm()
        context = {

            'form2': form2,

        }
        return render(request, 'quote.html', context)

quote.html

{{ form2.management_form }}
            <div id="form_set">
              {% for form2 in form2.forms %}
                <table id = 'manifest-table25' class="manifest-table2" width=100%>
                  {% csrf_token %}
                  <tbody width=100%>
                    <tr class="manifest-row">
                      <td width = 17.5% class="productCode" onchange="populateProduct(this)">{{form2.ProductCode}}</td>
                      <td width = 32.5% class="description">{{form2.DescriptionOfGoods}}</td>
                      <td width = 12.5% class="quantity" oninput="calculateUnit(this)">{{form2.UnitQty}}</td>
                      <td width = 12.5% class="unitType">{{form2.Type}}</td>
                      <td width = 10.5% class="price" oninput="calculate(this)">{{form2.Price}}</td>
                      <td width = 12.5% class="amount2">{{form2.Amount}}</td>
                      <td>{{form2.DELETE}}</td>
                      {{form2.id}}
                    </tr>
                  </tbody>
                </table>
              {% endfor %}
            </div>

models.py

class QuoteManifest(models.Model):
    ProductCode = models.ForeignKey(Product, null=True, blank=True)
    DescriptionOfGoods = models.CharField(max_length=500, blank=True)
    UnitQty = models.CharField(max_length=10, blank=True)
    Type = models.CharField(max_length=50, blank=True)
    Amount = models.CharField(max_length=100, blank=True)
    Price = models.CharField(max_length=100, blank=True)

{{form2.DELETE}} is supposed to render a checkbox. This is what I cannot get working. It does work when I render the form as {{form2.as_p}} but that will not work for me in my case.

2 Answers

Using your example code, I was able to create a sample that seems to render the checkbox using the {{ form.DELETE }} syntax.

It appears that my sample code is very similar to what you already have. I did add an on_delete parameter to the ProductCode variable in the QuoteManifest model. And I'm not sure what your Product model looks like so I just created a dummy model. I also removed your CSS classes and JavaScript calls. Is it possible that something in your JavaScript was overriding the checkboxes?

As you'll see in my sample, I do get the checkbox. My code is below, and here is a link to the working demo on repl.it.

models.py

from django.db import models

class Product(models.Model):
    ProductName = models.CharField(max_length=100, unique=True)


class QuoteManifest(models.Model):
    ProductCode = models.ForeignKey(Product, null=True, blank=True, on_delete=models.CASCADE)
    DescriptionOfGoods = models.CharField(max_length=500, blank=True)
    UnitQty = models.CharField(max_length=10, blank=True)
    Type = models.CharField(max_length=50, blank=True)
    Amount = models.CharField(max_length=100, blank=True)
    Price = models.CharField(max_length=100, blank=True)

views.py

from django.shortcuts import render, redirect
from django.forms.models import modelformset_factory
from .models import QuoteManifest

def QuoteView(request):
  QuoteManifestForm= modelformset_factory(QuoteManifest, fields =('ProductCode', 'DescriptionOfGoods', 'UnitQty', 'Type','Amount', 'Price'), can_delete=True)

  form2 = QuoteManifestForm()
  context = {
  'form2': form2,
  }
  return render(request, 'quote.html', context)

templates/quote.html

<div id="form_set">
{% for form2 in form2.forms %}
  <table id="manifest-table25" width=100%>
    {% csrf_token %}
    <tbody width=100%>
      <tr>
        <td>{{form2.ProductCode}}</td>
        <td>{{form2.DescriptionOfGoods}}</td>
        <td>{{form2.UnitQty}}</td>
        <td>{{form2.Type}}</td>
        <td>{{form2.Price}}</td>
        <td>{{form2.Amount}}</td>
        <td>{{form2.DELETE}}</td>
      </tr>
    </tbody>
  </table>
{% endfor %}
</div>

Based on the examples here: https://docs.djangoproject.com/en/3.0/topics/forms/formsets/#manually-rendered-can-delete-and-can-order

It looks like your view would be:

def QuoteView(request):
    QuoteManifestFormset= modelformset_factory(QuoteManifest, fields =('ProductCode', 'DescriptionOfGoods', 'UnitQty', 'Type','Amount', 'Price'), can_delete = True)   # Renamed as formset for clarity
    if request.method == "POST":
       formset = QuoteManifestFormset(request.POST) # also renamed
       formset.save()
       return redirect('HomeView')
    else:
       formset = QuoteManifestFormset()
        context = {'formset': formset}
        return render(request, 'quote.html', context)

And your quote.html I think {% for form2 in form2.forms %} needs to be {% for form in formset %}

<form method="post">
    {{ formset.management_form }}
    {% for form in formset %}  
      <table id = 'manifest-table25' class="manifest-table2" width=100%>
        {% csrf_token %}
        <tbody width=100%>
          <tr class="manifest-row">
            <td width = 17.5% class="productCode" onchange="populateProduct(this)">{{form.ProductCode}}</td>
            <td width = 32.5% class="description">{{form.DescriptionOfGoods}}</td>
            <td width = 12.5% class="quantity" oninput="calculateUnit(this)">{{form.UnitQty}}</td>
            <td width = 12.5% class="unitType">{{form.Type}}</td>
            <td width = 10.5% class="price" oninput="calculate(this)">{{form.Price}}</td>
            <td width = 12.5% class="amount2">{{form.Amount}}</td>
            <td>{{form.DELETE}}</td>
            {{form.id}}
          </tr>
        </tbody>
      </table>
    {% endfor %}
</form>
Related