Django Form Basics

Django Form Basics

Despite using Django for a number of years, I haven’t really worked with Django’s Forms until this week. I needed to create a form to handle a file upload, which has an associated category. The form also had to allow users to create new categories from within the file. When creating a new category, we have some extra data we want associated with the new category. I learned a few things trying to set this up.

First, forms.ModelForm: The fields on this form don't have to map 1-1 to the model. The upload model has a category field, but we need some extra fields on the form when we create new categories that don't exist on the upload model. No problem! I thought I might have to fall back to a standard form since I needed extra fields, but I was able to add them to the form and assign them to the category in the view.

Also, to break up and style different fields in a form, you can individually identify the fields in the template file and style them. So instead of

<formid="id_upload_form" action="{% url 'app_name:upload_file' %}" method="post" enctype="multipart/form-data">
  {% csrf_token %}
  {{ form|crispy }}
  <input type="submit" id="idupload_form_submit" class="btn btn-primary mt-4 disabled" value="Upload">
 </form>

We have:

<formid="id_upload_form" action="{% url 'app_name:upload_file' %}" method="post" enctype="multipart/form-data">
  {% csrf_token %}

  {{ form.file|as_crispy_field }}
  {{ form.category|as_crispy_field }}
  {{ form.new_category_sources|as_crispy_field }}
  {{ form.new_category_display_name|as_crispy_field }}

  <input type="submit" id="idupload_form_submit" class="btn btn-primary mt-4 disabled" value="Upload">
 </form>

This allowed me to wrap the bottom two fields in a Boostrap accordion in order to hide them from users who are updating a category instead of creating one.

<div class="accordion" id="accordionExample">
  <div class="accordion-item">
    <h2 class="accordion-header" id="headingOne">
      <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
        Create New Category
      </button>
    </h2>
    <div id="collapseOne" class="accordion-collapse collapse" aria-labelledby="headingOne" data-bs-parent="#accordionExample">
      <div class="accordion-body">
        {{ form.new_category_sources|as_crispy_field }}
        {{ form.new_category_display_name|as_crispy_field }}
    </div>
  </div>
</div>

We already have bootstrap as a dependency, so I like this solution better than adding JavaScript, which I also saw as a way to solve this problem.