Inline Formset Factory - Dynamically Adding Forms - Invalid UUID

I have a inlineformset_factory that I am trying to dynamically add forms to.

I found some code from stack overflow here to help with this.

However, when I try to save the formset, I get an error that says:

[{'transaction_line_account_1': ['“6b5e3acb-18f9-0-97b2-61e76fd101c2” is not a valid UUID.'], 'transaction_line_account_2': ['“8463b972-65ad-0-804a-d916d0b162d5” is not a valid UUID.'], 'transaction_line_tag': ['“a34b8f5b-619d-0-ba3e-0c00392dc6b1” is not a valid UUID.']}]

These are all valid UUID’s in my database.
This error only occurs with forms that are added using the javascript. If the form is included as an “extra” in the inlineformset_factory, it saves just fine. I am lost as to what might be happening.

My form(s):

class TransactionLineForm(ModelForm):
    class Meta:
        model = TransactionLine
        fields = [
            'transaction_line_account_1',
            'transaction_line_account_2',
            'transaction_line_merchant',
            'transaction_line_amount',
            'transaction_line_description',
            'transaction_line_tag',
        ]
        labels = {
            'transaction_line_account_1': 'Account',
            'transaction_line_account_2': 'Category (or Account)',
            'transaction_line_merchant': 'Merchant',
            'transaction_line_amount': 'Amount',
            'transaction_line_description': 'Description',
            'transaction_line_tag': 'Tag(s)',
        }
        widgets = {
            'transaction_line_account_1': forms.Select(attrs={'class': 'bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50', 'required': True}),
            'transaction_line_account_2': forms.Select(attrs={'class': 'bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50', 'required': True}),
            'transaction_line_merchant': forms.Select(attrs={'class': 'bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50'}),
            'transaction_line_amount': forms.NumberInput(attrs={'class': 'mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50', 'required': True}),
            'transaction_line_description': forms.TextInput(attrs={'class': 'mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50', 'required': True}),
            'transaction_line_tag': forms.SelectMultiple(attrs={'class': 'mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50'}),
        }

    def __init__(self, *args, **kwargs):
        self.current_user = kwargs.pop('current_user', None)
        super().__init__(*args, **kwargs)
        self.fields['transaction_line_account_1'] = GroupedModelChoiceField(queryset=Account.objects.filter(Q(account_class__account_class='Asset') | Q(account_class__account_class='Liability'), household=self.current_user.household).order_by('account_class__account_subtype', 'account_name'), choices_groupby='account_class', widget=forms.Select(attrs={'class': 'bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50', 'required': True}), label='Account')
        self.fields['transaction_line_account_2'] = GroupedModelChoiceField(queryset=Account.objects.filter(household=self.current_user.household).exclude(Q(account_class__account_class='Income') | Q(account_class__account_class='Expense'), account_parent__isnull=True).exclude(account_name='Opening Balance').annotate(custom_order=Case(When(account_class__account_class='Income', then=Value(2)),When(account_class__account_class='Expense', then=Value(1)),output_field=IntegerField())).order_by('-custom_order','account_parent__account_name', 'account_name'), choices_groupby='account_parent', widget=forms.Select(attrs={'class': 'bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50', 'required': True}), label='Category (or Account)')
        self.fields['transaction_line_merchant'].queryset = Merchant.objects.filter(household=self.current_user.household).exclude(merchant_name='Opening Balance Merchant').order_by('merchant_name')
        self.fields['transaction_line_tag'].queryset = Tag.objects.filter(household=self.current_user.household).exclude(tag_type='Parent').order_by('tag_name')
TransactionLineFormset = inlineformset_factory(Transaction, TransactionLine, form=TransactionLineForm, extra=2, can_delete=True)

My view:

@login_required
def CashflowTransactionCreate(request):
    transaction_form = TransactionForm(request.POST or None)
    transaction_line_formset = TransactionLineFormset(form_kwargs={'current_user': request.user}) # form_kwargs are used to pass the request.user to the inner form of the formset
    context = {'transaction_form': transaction_form, 'transaction_line_formset': transaction_line_formset}
    
    if request.method == 'POST':
        # Check and create Transaction header
        if transaction_form.is_valid():
            transaction_form_instance = transaction_form.save(commit=False)
            transaction_form_instance.household = request.user.household
            transaction_form_instance.created_by = request.user
            transaction_line_formset = TransactionLineFormset(request.POST, instance=transaction_form_instance, form_kwargs={'current_user': request.user})
            if transaction_line_formset.is_valid():
                # DO LOGIC CHECKS
                transaction_line_formset_instance = transaction_line_formset.save(commit=False)
                for form in transaction_line_formset_instance:
                    # If the transaction line accounts are the same, throw error.
                    if form.transaction_line_account_1 == form.transaction_line_account_2:
                        messages.error(request, 'Transaction line accounts cannot be the same. You must use different accounts for transfers.')
                        return render(request, 'cashflow/transaction-create.html', context)
                    # Set transaction line status
                    form.transaction_line_status = 'Reviewed'
                transaction_form_instance.save()
                transaction_line_formset.save()
                return redirect('transaction-list')
            else:
                print(transaction_line_formset.errors)
        else:
            print(transaction_form.errors)

    return render(request, 'cashflow/transaction-create.html', context)

Template:

{% extends 'base.html' %}
{% load static %}

{% block content %}

<section class="pt-10">
    <div class="mb-10">
      <h1 class="text-4xl text-center">Create a New Transaction</h1>
    </div>
    <div class="flex justify-center">
      <template id="id_formset_empty_form">{{ transaction_line_formset.empty_form }}</template>
        <form method="POST" id="id_html_form" autocomplete="off">
          {% csrf_token %}
          {{ transaction_line_formset.management_form }}
          {{ transaction_form.as_p }}
          <hr class="pb-2 border-black h-5px">
            <table id="id_formset_container">
            {{ transaction_line_formset }}
            </table>
          <div id="id_formset_add_button" class="px-6 py-3 mb-2 font-medium text-white bg-blue-500 hover:bg-blue-600 rounded transition duration-200">Add lines</div>
          <br>
          <button id="id_formset_submit_button" class="px-6 py-3 font-medium text-white bg-blue-500 hover:bg-blue-600 rounded transition duration-200" type="submit">Create Transaction</button>
        </form>
      </div>
</section>

<script type="text/javascript" src="{% static 'js/cashflow.js' %}" onload="currentDate()"></script>

{% endblock content %}

Javascript:

// DYNAMICALLY ADD FORMS TO TRANSACTION LINE FORMSET
window.addEventListener('load', (event) => {
    // get form template and total number of forms from management form
    const templateForm = document.getElementById('id_formset_empty_form');
    const inputTotalForms = document.querySelector('input[id$="-TOTAL_FORMS"]');
    const inputInitialForms = document.querySelector('input[id$="-INITIAL_FORMS"]');

    // get our container (e.g. <table>, <ul>, or <div>) and "Add" button
    const containerFormSet = document.getElementById('id_formset_container');
    const buttonAdd = document.getElementById('id_formset_add_button');
    const buttonSubmit = document.getElementById('id_formset_submit_button');

    // event handlers
    buttonAdd.onclick = addForm;
    buttonSubmit.onclick = updateNameAttributes;

    // form counters (note: proper form index bookkeeping is necessary
    // because django's formset will create empty forms for any missing
    // indices, and will discard forms with indices >= TOTAL_FORMS, which can
    // lead to funny behavior in some edge cases)
    const initialForms = Number(inputInitialForms.value);
    let extraFormIndices = [];
    let nextFormIndex = initialForms;

    function addForm () {
        // create DocumentFragment from template
        const formFragment = templateForm.content.cloneNode(true);
        // a django form is rendered as_table (default), as_ul, or as_p, so
        // the fragment will contain one or more <tr>, <li>, or <p> elements,
        // respectively.
        for (let element of formFragment.children) {
            // replace the __prefix__ placeholders from the empty form by the
            // actual form index
            element.innerHTML = element.innerHTML.replace(
                /(?<=\w+-)(__prefix__|\d+)(?=-\w+)/g,
                nextFormIndex.toString());
            // add a custom attribute to simplify bookkeeping
            element.dataset.formIndex = nextFormIndex.toString();
            // add a delete click handler (if formset can_delete)
            setDeleteHandler(element);
        }
        // move the fragment's children onto the DOM
        // (the fragment is empty afterwards)
        containerFormSet.appendChild(formFragment);
        // keep track of form indices
        extraFormIndices.push(nextFormIndex++);
    }

    function removeForm (event) {
        // remove all elements with form-index matching that of the delete-input
        const formIndex = event.target.dataset.formIndex;
        for (let element of getFormElements(formIndex)) {
            element.remove();
        }
        // remove form index from array
        let indexIndex = extraFormIndices.indexOf(Number(formIndex));
        if (indexIndex > -1) {
            extraFormIndices.splice(indexIndex, 1);
        }
    }

    function setDeleteHandler (containerElement) {
        // modify DELETE checkbox in containerElement, if the checkbox exists
        // (these checboxes are added by formset if can_delete)
        const inputDelete = containerElement.querySelector('input[id$="-DELETE"]');
        if (inputDelete) {
            // duplicate the form index instead of relying on parentElement (more robust)
            inputDelete.dataset.formIndex = containerElement.dataset.formIndex;
            inputDelete.onclick = removeForm;
        }
    }

    function getFormElements(index) {
        // the data-form-index attribute is available as dataset.formIndex
        // https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes#javascript_access
        return containerFormSet.querySelectorAll('[data-form-index="' + index + '"]');
    }

    function updateNameAttributes (event) {
        // make sure the name indices are consecutive and smaller than
        // TOTAL_FORMS (the name attributes end up as dict keys on the server)
        // note we do not need to update the indices in the id attributes etc.
        for (let [consecutiveIndex, formIndex] of extraFormIndices.entries()) {
            for (let formElement of getFormElements(formIndex)){
                for (let element of formElement.querySelectorAll('input, select')) {
                    if ('name' in element) {
                        element.name = element.name.replace(
                            /(?<=\w+-)(__prefix__|\d+)(?=-\w+)/g,
                            (initialForms + consecutiveIndex).toString());
                    }
                }
            }
        }
        updateTotalFormCount();
    }

    function updateTotalFormCount (event) {
        // note we could simply do initialForms + extraFormIndices.length
        // to get the total form count, but that does not work if we have
        // validation errors on forms that were added dynamically
        const firstElement = templateForm.content.querySelector('input, select');
        // select the first input or select element, then count how many ids
        // with the same suffix occur in the formset container
        if (firstElement) {
            let suffix = firstElement.id.split('__prefix__')[1];
            let selector = firstElement.tagName.toLowerCase() + '[id$="' + suffix + '"]';
            let allElementsForId = containerFormSet.querySelectorAll(selector);
            // update total form count
            inputTotalForms.value = allElementsForId.length;
        }
    }
}, false);

Model(s):

class Transaction(models.Model): # Stores the transaction header
    id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, primary_key=True)
    household = models.ForeignKey(Household, on_delete=models.PROTECT, null=False, blank=False)
    transaction_date = models.DateField(null=False, blank=False)
    transaction_description = models.CharField(null=False, blank=False, max_length=250)
    created_by = models.ForeignKey(User, on_delete=models.PROTECT)
    created_time = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return str(self.transaction_description)

class TransactionLine(models.Model): # Stores all the line details of the transactions
    TRANSACTION_LINE_STATUS_CHOICES = (
        ('Pending', 'Pending'),
        ('Reviewed', 'Reviewed'),
        ('Reconciled', 'Reconciled'),
    )
    id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False, primary_key=True)
    transaction = models.ForeignKey(Transaction, on_delete=models.PROTECT, null=False, blank=False)
    transaction_line_account_1 = models.ForeignKey(Account, on_delete=models.PROTECT, null=False, blank=False, related_name='transaction_line_account_1')
    transaction_line_account_2 = models.ForeignKey(Account, on_delete=models.PROTECT, null=False, blank=False, related_name='transaction_line_account_2')
    transaction_line_merchant = models.ForeignKey(Merchant, on_delete=models.PROTECT, null=False, blank=False)
    transaction_line_tag = models.ManyToManyField(Tag, blank=True)
    transaction_line_amount = models.DecimalField(max_digits=12, decimal_places=2, null=False, blank=False)
    transaction_line_description = models.CharField(null=False, blank=False, max_length=255)
    transaction_line_status = models.CharField(choices=TRANSACTION_LINE_STATUS_CHOICES, max_length=15, null=False, blank=False)

    def __str__(self):
        return str(self.transaction_line_description)

This is not a valid UUID string. A valid UUID formatted as a hyphenated string consists of the pattern of 8-4-4-4-12 hex digits. The string you are supplying here does not match that pattern.

@KenWhitesell - Thanks for pointing that out. I was just looking at the beginning and end of the UUID, not the middle.

I looked at the HTML, and below is what I have when the page is rendered and I add one of the dynamic forms. I always get the correct UUID. It seems to be an issue on the django side when it is being processed.

<option value="6b5e3acb-18f9-4871-97b2-61e76fd101c2">Account 1</option>

Any thoughts on what might be happening/causing it?

Thanks

It would be helpful to see the html that has been built in the browser, along with seeing what is submitted as the post body.

@KenWhitesell -

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.tailwindcss.com"></script>
    <title>Dashboard</title>
</head>
<body class="bg-amber-50">
    <nav class="lg:hidden py-6 px-6 border-b bg-white">
    <div class="flex items-center justify-between">
      <span class="text-2xl font-semibold">
        <h1>Dashboard</h1>
      </span>
      <button class="navbar-burger flex items-center rounded focus:outline-none">
        <svg class="text-white bg-indigo-500 hover:bg-indigo-600 block h-8 w-8 p-2 rounded" viewbox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill="currentColor">
          <title>Mobile menu</title>
          <path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"></path>
        </svg>
      </button>
    </div>
  </nav>
  <div class="hidden lg:block navbar-menu relative z-50">
    <div class="navbar-backdrop fixed lg:hidden inset-0 bg-gray-800 opacity-10"></div>
    <nav class="fixed top-0 left-0 bottom-0 flex flex-col w-1/3 lg:w-50 sm:max-w-xs pt-6 pb-8 bg-white border-r overflow-y-auto">
      <div class="flex w-full items-center px-6 pb-6 mb-6 lg:border-b border-blue-50">
        <span class="text-xl font-semibold">
          <h1>Dashboard</h1>
        </span>
      </div>
      <div class="px-4 pb-6">
        <ul class="mb-8 text-sm font-medium">
          <li>
            <a class="flex items-center pl-3 py-3 pr-4 text-gray-500 hover:bg-indigo-50 rounded" href="/">
              <span class="inline-block mr-3">
              </span>
              <span>Dashboard</span>
              <span class="inline-block ml-auto">
              </span>
            </a>
          </li>
          <li>
            <a class="flex items-center pl-3 py-3 pr-4 text-gray-500 hover:bg-indigo-50 rounded" href="/transactions/">
              <span class="inline-block mr-3">
              </span>
              <span>Transactions</span>
            </a>
          </li>
          <li>
            <a class="flex items-center pl-3 py-3 pr-4 text-gray-500 hover:bg-indigo-50 rounded" href="/categories/">
              <span class="inline-block mr-3">
              </span>
              <span>Categories</span>
            </a>
          </li>
          <li>
            <a class="flex items-center pl-3 py-3 pr-4 text-gray-500 hover:bg-indigo-50 rounded" href="/tags/">
              <span class="inline-block mr-3">
              </span>
              <span>Tags</span>
            </a>
          </li>
          <li>
            <a class="flex items-center pl-3 py-3 pr-4 text-gray-500 hover:bg-indigo-50 rounded" href="/merchants/">
              <span class="inline-block mr-3">
              </span>
              <span>Merchants</span>
            </a>
          </li>
          <li>
            <a class="flex items-center pl-3 py-3 pr-4 text-gray-500 hover:bg-indigo-50 rounded" href="/accounts/">
              <span class="inline-block mr-3">
              </span>
              <span>Accounts</span>
            </a>
          </li>
        </ul>
        <div class="pt-8">
          <a class="flex items-center pl-3 py-3 pr-2 text-gray-500 hover:bg-indigo-50 rounded" href="/user/logout/">
            <span class="inline-block mr-4">
            </span>
            <span>Log Out</span>
          </a>
        </div>
      </div>
    </nav>
  </div>
    <div class="flex justify-center">
        
    </div>
    <div class="mx-auto lg:ml-80">
        

<section class="pt-10">
    <div class="mb-10">
      <h1 class="text-4xl text-center">Create a New Transaction</h1>
    </div>
    <div class="flex justify-center">
      <template id="id_formset_empty_form"><tr>
    <th><label for="id_transactionline_set-__prefix__-transaction_line_account_1">Account:</label></th>
    <td>
      
      <select name="transactionline_set-__prefix__-transaction_line_account_1" class="bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" required id="id_transactionline_set-__prefix__-transaction_line_account_1">
  <option value="" selected>---------</option>

  <optgroup label="Label 1">
  <option value="3bf06a26-5041-4297-8e7f-cc95f8c311b8">Account 1</option>

  </optgroup>
  <optgroup label="Label 2">
  <option value="aa1b0b67-6a7a-47bb-8fb8-9cde103bcdd1">Account 2</option>

  </optgroup>
  <optgroup label="Label 3">
  <option value="3c55715d-1401-4265-a631-8dabd9a0623e">Account 3</option>

  </optgroup>
  <optgroup label="Label 4">
  <option value="6b5e3acb-18f9-4871-97b2-61e76fd101c2">Account 4</option>

  </optgroup>
  <optgroup label="Label 5">
  <option value="7c7a64e5-7b43-4a6d-845a-b0b4a85c9329">Account 5</option>

  <option value="615925f0-8e13-4384-9f26-e3ccc512e557">Account 6</option>

  </optgroup>
  <optgroup label="Label 6">
  <option value="11bb3008-79b7-418a-addc-91b1b2f2378d">Account 7</option>

  </optgroup>
  <optgroup label="Label 7">
  <option value="4decb951-63b7-49e8-a719-e9e3c05194ed">Account 8</option>

  </optgroup>
  <optgroup label="Label 8">
  <option value="80f142d7-5541-4a55-a00b-1eb824e62352">Account 9</option>

  </optgroup>
  <optgroup label="Label 9">
  <option value="df074f56-862c-4250-9de0-62e4f22ed439">Account 10</option>

  </optgroup>
  <optgroup label="Label 10">
  <option value="0946072b-2291-499e-99ab-7d29ebc93492">Account 11</option>

  </optgroup>
</select>
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-__prefix__-transaction_line_account_2">Category (or Account):</label></th>
    <td>
      
      <select name="transactionline_set-__prefix__-transaction_line_account_2" class="bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" required id="id_transactionline_set-__prefix__-transaction_line_account_2">
  <option value="" selected>---------</option>

  <optgroup label="Label 1">
  <option value="60f9b642-630b-4a8e-b05d-85cb9e13b856">Account 12</option>

  </optgroup>
  <optgroup label="Label 2">
  <option value="8463b972-65ad-4330-804a-d916d0b162d5">Account 13</option>

  <option value="96b0a0dd-af90-442a-baff-dd33cadb6c3a">Account 14</option>

  </optgroup>
  <optgroup label="Label 3">
  <option value="a669b193-1e78-4bc9-984d-b1f5c36160c7">Account 15</option>

  </optgroup>
  <option value="3c55715d-1401-4265-a631-8dabd9a0623e">Account 3</option>

  <option value="80f142d7-5541-4a55-a00b-1eb824e62352">Account 9</option>

  <option value="4decb951-63b7-49e8-a719-e9e3c05194ed">Account 8</option>

  <option value="f6fcda60-2274-476b-9faf-c05e278016a7">Account 16</option>

  <option value="7c7a64e5-7b43-4a6d-845a-b0b4a85c9329">Account 5</option>

  <option value="6b5e3acb-18f9-4871-97b2-61e76fd101c2">Account 4</option>

  <option value="615925f0-8e13-4384-9f26-e3ccc512e557">Account 6</option>

  <option value="df074f56-862c-4250-9de0-62e4f22ed439">Account 10</option>

  <option value="0946072b-2291-499e-99ab-7d29ebc93492">Account 11</option>

  <option value="11bb3008-79b7-418a-addc-91b1b2f2378d">Account 7</option>

  <option value="aa1b0b67-6a7a-47bb-8fb8-9cde103bcdd1">Account 2</option>

  <option value="3bf06a26-5041-4297-8e7f-cc95f8c311b8">Account 1</option>

</select>
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-__prefix__-transaction_line_merchant">Merchant:</label></th>
    <td>
      
      <select name="transactionline_set-__prefix__-transaction_line_merchant" class="bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" id="id_transactionline_set-__prefix__-transaction_line_merchant">
  <option value="" selected>---------</option>

  <option value="5728a38f-5ba5-4b19-941c-f5f62d071a86">Merchant 1</option>

  <option value="e6bf1287-2522-4581-89a2-6e81f71a5f6f">Merchant 2</option>

  <option value="200875a9-93e1-4e1b-9b94-466291f5251a">Merchant 3</option>

  <option value="f1e25148-3dbd-4165-a271-e9d14f6f96af">Merchant 4</option>

  <option value="bc77e65c-7d98-472d-b361-8af7dc5791d0">Merchant 5</option>

</select>
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-__prefix__-transaction_line_amount">Amount:</label></th>
    <td>
      
      <input type="number" name="transactionline_set-__prefix__-transaction_line_amount" class="mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" required step="0.01" id="id_transactionline_set-__prefix__-transaction_line_amount">
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-__prefix__-transaction_line_description">Description:</label></th>
    <td>
      
      <input type="text" name="transactionline_set-__prefix__-transaction_line_description" class="mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" required maxlength="255" id="id_transactionline_set-__prefix__-transaction_line_description">
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-__prefix__-transaction_line_tag">Tag(s):</label></th>
    <td>
      
      <select name="transactionline_set-__prefix__-transaction_line_tag" class="mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" id="id_transactionline_set-__prefix__-transaction_line_tag" multiple>
  <option value="97ef3869-7db0-4adb-a1c2-232d95431fe7">Tag 1</option>

  <option value="08a52446-48c5-4c55-8007-d783bf479d05">Tag 2</option>

  <option value="2d35f34a-674b-4444-a109-2687be887f67">Tag 3</option>

  <option value="a34b8f5b-619d-4301-ba3e-0c00392dc6b1">Tag 4</option>

  <option value="e75d77b3-1b35-4c91-a0a8-83a0efd06fa9">Tag 5</option>

</select>
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-__prefix__-DELETE">Delete:</label></th>
    <td>
      
      <input type="checkbox" name="transactionline_set-__prefix__-DELETE" id="id_transactionline_set-__prefix__-DELETE">
      
      
        <input type="hidden" name="transactionline_set-__prefix__-id" id="id_transactionline_set-__prefix__-id"><input type="hidden" name="transactionline_set-__prefix__-transaction" id="id_transactionline_set-__prefix__-transaction">
      
    </td>
  </tr></template>
        <form method="POST" id="id_html_form" autocomplete="off">
          <input type="hidden" name="csrfmiddlewaretoken" value="3Sv9OBxzwIqlXgQBuVxarz2klWNhkxZQW3djmxGKwR6midxMwRuGuSmaYgCDQoMx">
          <input type="hidden" name="transactionline_set-TOTAL_FORMS" value="1" id="id_transactionline_set-TOTAL_FORMS"><input type="hidden" name="transactionline_set-INITIAL_FORMS" value="0" id="id_transactionline_set-INITIAL_FORMS"><input type="hidden" name="transactionline_set-MIN_NUM_FORMS" value="0" id="id_transactionline_set-MIN_NUM_FORMS"><input type="hidden" name="transactionline_set-MAX_NUM_FORMS" value="1000" id="id_transactionline_set-MAX_NUM_FORMS">
          <p>
    <label for="id_transaction_date">Transaction Date:</label>
    <input type="date" name="transaction_date" class="mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" required id="id_transaction_date">
    
    
  </p>

  
  <p>
    <label for="id_transaction_description">Transaction Description:</label>
    <input type="text" name="transaction_description" class="mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" maxlength="250" required id="id_transaction_description">
    
    
      
    
  </p>
          <hr class="pb-2 border-black h-5px">
            <table id="id_formset_container">
            <input type="hidden" name="transactionline_set-TOTAL_FORMS" value="1" id="id_transactionline_set-TOTAL_FORMS"><input type="hidden" name="transactionline_set-INITIAL_FORMS" value="0" id="id_transactionline_set-INITIAL_FORMS"><input type="hidden" name="transactionline_set-MIN_NUM_FORMS" value="0" id="id_transactionline_set-MIN_NUM_FORMS"><input type="hidden" name="transactionline_set-MAX_NUM_FORMS" value="1000" id="id_transactionline_set-MAX_NUM_FORMS"><tr>
    <th><label for="id_transactionline_set-0-transaction_line_account_1">Account:</label></th>
    <td>
      
      <select name="transactionline_set-0-transaction_line_account_1" class="bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" required id="id_transactionline_set-0-transaction_line_account_1">
  <option value="" selected>---------</option>

  <optgroup label="Label 1">
    <option value="3bf06a26-5041-4297-8e7f-cc95f8c311b8">Account 1</option>
  
    </optgroup>
    <optgroup label="Label 2">
    <option value="aa1b0b67-6a7a-47bb-8fb8-9cde103bcdd1">Account 2</option>
  
    </optgroup>
    <optgroup label="Label 3">
    <option value="3c55715d-1401-4265-a631-8dabd9a0623e">Account 3</option>
  
    </optgroup>
    <optgroup label="Label 4">
    <option value="6b5e3acb-18f9-4871-97b2-61e76fd101c2">Account 4</option>
  
    </optgroup>
    <optgroup label="Label 5">
    <option value="7c7a64e5-7b43-4a6d-845a-b0b4a85c9329">Account 5</option>
  
    <option value="615925f0-8e13-4384-9f26-e3ccc512e557">Account 6</option>
  
    </optgroup>
    <optgroup label="Label 6">
    <option value="11bb3008-79b7-418a-addc-91b1b2f2378d">Account 7</option>
  
    </optgroup>
    <optgroup label="Label 7">
    <option value="4decb951-63b7-49e8-a719-e9e3c05194ed">Account 8</option>
  
    </optgroup>
    <optgroup label="Label 8">
    <option value="80f142d7-5541-4a55-a00b-1eb824e62352">Account 9</option>
  
    </optgroup>
    <optgroup label="Label 9">
    <option value="df074f56-862c-4250-9de0-62e4f22ed439">Account 10</option>
  
    </optgroup>
    <optgroup label="Label 10">
    <option value="0946072b-2291-499e-99ab-7d29ebc93492">Account 11</option>

  </optgroup>
</select>
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-0-transaction_line_account_2">Category (or Account):</label></th>
    <td>
      
      <select name="transactionline_set-0-transaction_line_account_2" class="bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" required id="id_transactionline_set-0-transaction_line_account_2">
  <option value="" selected>---------</option>

  <optgroup label="Label 1">
    <option value="60f9b642-630b-4a8e-b05d-85cb9e13b856">Account 12</option>
  
    </optgroup>
    <optgroup label="Label 2">
    <option value="8463b972-65ad-4330-804a-d916d0b162d5">Account 13</option>
  
    <option value="96b0a0dd-af90-442a-baff-dd33cadb6c3a">Account 14</option>
  
    </optgroup>
    <optgroup label="Label 3">
    <option value="a669b193-1e78-4bc9-984d-b1f5c36160c7">Account 15</option>
  
    </optgroup>
    <option value="3c55715d-1401-4265-a631-8dabd9a0623e">Account 3</option>
  
    <option value="80f142d7-5541-4a55-a00b-1eb824e62352">Account 9</option>
  
    <option value="4decb951-63b7-49e8-a719-e9e3c05194ed">Account 8</option>
  
    <option value="f6fcda60-2274-476b-9faf-c05e278016a7">Account 16</option>
  
    <option value="7c7a64e5-7b43-4a6d-845a-b0b4a85c9329">Account 5</option>
  
    <option value="6b5e3acb-18f9-4871-97b2-61e76fd101c2">Account 4</option>
  
    <option value="615925f0-8e13-4384-9f26-e3ccc512e557">Account 6</option>
  
    <option value="df074f56-862c-4250-9de0-62e4f22ed439">Account 10</option>
  
    <option value="0946072b-2291-499e-99ab-7d29ebc93492">Account 11</option>
  
    <option value="11bb3008-79b7-418a-addc-91b1b2f2378d">Account 7</option>
  
    <option value="aa1b0b67-6a7a-47bb-8fb8-9cde103bcdd1">Account 2</option>
  
    <option value="3bf06a26-5041-4297-8e7f-cc95f8c311b8">Account 1</option>

</select>
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-0-transaction_line_merchant">Merchant:</label></th>
    <td>
      
      <select name="transactionline_set-0-transaction_line_merchant" class="bg-white mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" id="id_transactionline_set-0-transaction_line_merchant">
  <option value="" selected>---------</option>

  <option value="5728a38f-5ba5-4b19-941c-f5f62d071a86">Merchant 1</option>

  <option value="e6bf1287-2522-4581-89a2-6e81f71a5f6f">Merchant 2</option>

  <option value="200875a9-93e1-4e1b-9b94-466291f5251a">Merchant 3</option>

  <option value="f1e25148-3dbd-4165-a271-e9d14f6f96af">Merchant 4</option>

  <option value="bc77e65c-7d98-472d-b361-8af7dc5791d0">Merchant 5</option>

</select>
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-0-transaction_line_amount">Amount:</label></th>
    <td>
      
      <input type="number" name="transactionline_set-0-transaction_line_amount" class="mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" required step="0.01" id="id_transactionline_set-0-transaction_line_amount">
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-0-transaction_line_description">Description:</label></th>
    <td>
      
      <input type="text" name="transactionline_set-0-transaction_line_description" class="mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" required maxlength="255" id="id_transactionline_set-0-transaction_line_description">
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-0-transaction_line_tag">Tag(s):</label></th>
    <td>
      
      <select name="transactionline_set-0-transaction_line_tag" class="mb-5 w-full px-3 py-3 border-2 border-blue-500 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" id="id_transactionline_set-0-transaction_line_tag" multiple>
  <option value="97ef3869-7db0-4adb-a1c2-232d95431fe7">Tag 1</option>

  <option value="08a52446-48c5-4c55-8007-d783bf479d05">Tag 2</option>

  <option value="2d35f34a-674b-4444-a109-2687be887f67">Tag 3</option>

  <option value="a34b8f5b-619d-4301-ba3e-0c00392dc6b1">Tag 4</option>

  <option value="e75d77b3-1b35-4c91-a0a8-83a0efd06fa9">Tag 5</option>

</select>
      
      
    </td>
  </tr>

  <tr>
    <th><label for="id_transactionline_set-0-DELETE">Delete:</label></th>
    <td>
      
      <input type="checkbox" name="transactionline_set-0-DELETE" id="id_transactionline_set-0-DELETE">
      
      
        <input type="hidden" name="transactionline_set-0-id" id="id_transactionline_set-0-id"><input type="hidden" name="transactionline_set-0-transaction" id="id_transactionline_set-0-transaction">
      
    </td>
  </tr>
            </table>
          <div id="id_formset_add_button" class="px-6 py-3 mb-2 font-medium text-white bg-blue-500 hover:bg-blue-600 rounded transition duration-200">Add lines</div>
          <br>
          <button id="id_formset_submit_button" class="px-6 py-3 font-medium text-white bg-blue-500 hover:bg-blue-600 rounded transition duration-200" type="submit">Create Transaction</button>
        </form>
      </div>
</section>

<script type="text/javascript" src="/static/js/cashflow.js" onload="currentDate()"></script>


    </div>
    <script type="text/javascript" src="/static/js/burger.js"></script>
</body>
</html>
<QueryDict: {'csrfmiddlewaretoken': ['jQnp6atAzanvYldEM7vh04L3dfFJq7oHc15zE6CLzj3wjiUPO3sN3n5TQzu5WYbo'], 'transactionline_set-TOTAL_FORMS': ['2', '1'], 'transactionline_set-INITIAL_FORMS': ['0', '0'], 'transactionline_set-MIN_NUM_FORMS': ['0', '0'], 'transactionline_set-MAX_NUM_FORMS': ['1000', '1000'], 'transaction_date': ['2025-04-14'], 'transaction_description': ['Test'], 'transactionline_set-0-transaction_line_account_1': ['6b5e3acb-18f9-4871-97b2-61e76fd101c2', '6b5e3acb-18f9-0-97b2-61e76fd101c2'], 'transactionline_set-0-transaction_line_account_2': ['8463b972-65ad-4330-804a-d916d0b162d5', '8463b972-65ad-0-804a-d916d0b162d5'], 'transactionline_set-0-transaction_line_merchant': ['200875a9-93e1-4e1b-9b94-466291f5251a', '200875a9-93e1-4e1b-9b94-466291f5251a'], 'transactionline_set-0-transaction_line_amount': ['1', '2'], 'transactionline_set-0-transaction_line_description': ['Test 1', 'Test 2'], 'transactionline_set-0-transaction_line_tag': ['97ef3869-7db0-4adb-a1c2-232d95431fe7', '08a52446-48c5-4c55-0-d783bf479d05'], 'transactionline_set-0-id': ['', ''], 'transactionline_set-0-transaction': ['', '']}>

It would be more helpful to see the actual post data as sent by the browser - you can get this from the network tab in the browser’s developer tools. That will help determine whether the issue is in the browser or on the server.

But superficially, it looks like you have two copies of the management form being submitted.

If you’re working with more than one formset in the view, you’ll want to use the prefix on the formsets to keep the data isolated.

Your HTML table also appears to possibly be malformed in that you have your <input element directly under the <table element - not within a <tr or <td element.

@KenWhitesell

Thanks for pointing that out. I accidentally had {{ transaction_line_formset.management_form }} in my HTML template twice. I have fixed that. I do not have 2 formsets.

Even after fixing that the issue persist.

Here is the POST data from the browser:

csrfmiddlewaretoken=VOsN74NW4WMq4nwyrqERC2NV760jxivyOZaXF0W745srpkdJtmBnFl7LKqPF39if&transaction_date=2025-04-14&transaction_description=TEST&transactionline_set-TOTAL_FORMS=2&transactionline_set-INITIAL_FORMS=0&transactionline_set-MIN_NUM_FORMS=0&transactionline_set-MAX_NUM_FORMS=1000&transactionline_set-0-transaction_line_account_1=6b5e3acb-18f9-4871-97b2-61e76fd101c2&transactionline_set-0-transaction_line_account_2=8463b972-65ad-4330-804a-d916d0b162d5&transactionline_set-0-transaction_line_merchant=200875a9-93e1-4e1b-9b94-466291f5251a&transactionline_set-0-transaction_line_amount=1&transactionline_set-0-transaction_line_description=TEST+1&transactionline_set-0-transaction_line_tag=08a52446-48c5-4c55-8007-d783bf479d05&transactionline_set-0-transaction_line_tag=a34b8f5b-619d-4301-ba3e-0c00392dc6b1&transactionline_set-0-id=&transactionline_set-0-transaction=&transactionline_set-0-transaction_line_account_1=6b5e3acb-18f9-0-97b2-61e76fd101c2&transactionline_set-0-transaction_line_account_2=8463b972-65ad-0-804a-d916d0b162d5&transactionline_set-0-transaction_line_merchant=200875a9-93e1-4e1b-9b94-466291f5251a&transactionline_set-0-transaction_line_amount=2&transactionline_set-0-transaction_line_description=TEST+2&transactionline_set-0-transaction_line_tag=97ef3869-7db0-4adb-a1c2-232d95431fe7&transactionline_set-0-transaction_line_tag=e75d77b3-1b35-4c91-a0a8-83a0efd06fa9&transactionline_set-0-id=&transactionline_set-0-transaction=

So, quoting from that post data:

transactionline_set-TOTAL_FORMS=2
transactionline_set-INITIAL_FORMS=0
transactionline_set-MIN_NUM_FORMS=0
transactionline_set-MAX_NUM_FORMS=1000
transactionline_set-0-transaction_line_account_1=6b5e3acb-18f9-4871-97b2-61e76fd101c2
transactionline_set-0-transaction_line_account_2=8463b972-65ad-4330-804a-d916d0b162d5
transactionline_set-0-transaction_line_merchant=200875a9-93e1-4e1b-9b94-466291f5251a
transactionline_set-0-transaction_line_amount=1
transactionline_set-0-transaction_line_description=TEST+1
transactionline_set-0-transaction_line_tag=08a52446-48c5-4c55-8007-d783bf479d05
transactionline_set-0-transaction_line_tag=a34b8f5b-619d-4301-ba3e-0c00392dc6b1
transactionline_set-0-id=
transactionline_set-0-transaction=
transactionline_set-0-transaction_line_account_1=6b5e3acb-18f9-0-97b2-61e76fd101c2
transactionline_set-0-transaction_line_account_2=8463b972-65ad-0-804a-d916d0b162d5
transactionline_set-0-transaction_line_merchant=200875a9-93e1-4e1b-9b94-466291f5251a
transactionline_set-0-transaction_line_amount=2
transactionline_set-0-transaction_line_description=TEST+2
transactionline_set-0-transaction_line_tag=97ef3869-7db0-4adb-a1c2-232d95431fe7
transactionline_set-0-transaction_line_tag=e75d77b3-1b35-4c91-a0a8-83a0efd06fa9
transactionline_set-0-id=
transactionline_set-0-transaction=

This is malformed in a couple areas:

  • You have the same index id for both form instances (transactionline_set-0-...)

    • e.g. transactionline_set-0-transaction_line_amount=1
      and transactionline_set-0-transaction_line_amount=2
    • The second instance of the form should be -1-
  • Your second instance has malformed UUIDs:

    • transactionline_set-0-transaction_line_account_1=6b5e3acb-18f9-0-97b2-61e76fd101c2
    • transactionline_set-0-transaction_line_account_2=8463b972-65ad-0-804a-d916d0b162d5

@KenWhitesell - Regarding the malformed UUID’s, as we can see in the HTML they are correct, but when submitted via POST, they become malformed. I am a little lost at how this happens. Even if the index id is fixed (which I will do), that would not fix the malformed UUID’s. How are UUID’s formed correctly in the HTML, but when submitted in the POST, they become malformed?

The obvious assumption - which as an assumption may not be correct - is that there’s some JavaScript involved somewhere on that page that is affecting these values. You might want to walk through the submit processing using the browser’s debugger to see if you can find where these values are getting altered. (Also make sure you’re looking at this HTML using the element tab of the developer tools and not the “view source” of the page.)

But clearly at this point, it’s not a Django issue, as Django is showing that it is receiving and processing exactly what has been sent to it.