Search code examples
pythondjangodjango-formshtmx

Django & HTMX - make forms render_field a target of HTMX


I've created a django form where user can input partial name of a client. HTMX displays all matching clients and when button is pressed next to clients name, I'd like it to fill multiple form fields. Let's consider simplified Django manual form example:

invoices/templates/invoice_add.html

{% extends 'base.html' %}
{% load widget_tweaks %}
{% block content %}
<form method='POST' autocomplete='off'> {% csrf_token %}
    <label>{{ form.number.label_tag }}</label>
    {{ form.number.errors }}
    {% render_field form.number class="form-control" %}
    <br>

    <label>{{ form.buyer_name.label_tag }}</label>
    {{ form.buyer_name.errors }}
    {% render_field form.buyer_name class="form-control" hx-post="/invoices/check_client/" hx-trigger="keyup" hx-target="#buyer_names_list" %}
    <div id="buyer_names_list"></div>
    <br>

    <label>{{ form.buyer_tax_no.label_tag }}</label>
    {{ form.buyer_tax_no.errors }}
    {% render_field form.buyer_tax_no class="form-control" %}
    <br><div id="tax_no_test"></div>

    <input type='submit' value='save'/>
</form>
{% endblock %}

As mentioned above, when populating buyer_name I'm getting a list of client names with a button next to their name inside buyer_names_list. This button calls below function to pull the tax number:

invoices/views.py

class InvoiceCreateView(CreateView):
    template_name: str = 'invoice_add.html'
    form_class = InvoiceForm
    queryset = Invoice.objects.all()

    def form_valid(self, form):
        return super().form_valid(form)


def particular_client_invoice(request):
    client_obj = Client.objects.all().filter(name=request.POST.get('clientname'))
    context = {'client_tax_no': client_obj.values_list('tax_no', flat=True)[0]}
    return render(request, 'partials/specific-invoice.html', context)

My issue:

While it properly returns desired tax number, I can only return the values from HTMX inside a div (id="tax_no_test" in this case). I'd like field form.buyer_tax_no to be the target field of the tax number. Is that possible? Alternatively (worse scenario), the value could be added to POST request another way, the render_field won't need to be displayed at all.

In case any additional code is required please let me know. Thanks in advance.


Solution

  • I've managed to find some time to come back to this problem. While the solution is not perfect (quite ugly actually) and not as scalable as I'd like it to be, for now this is the best I've got.

    I've installed the django-crispy-forms - I recommend a pretty decent series on integrating it & htmx on YouTube. I've replaced the entire invoices/templates/invoice_add.html to become a simple crispy form and then I was able to set the divs of the form to become a target of hx-target attribute of HTMX button/span.

    The ugly part is that I can't get it to replace only the value attribute of the html div in the form, therefore currently in the template partial I include the entire HTML of the initial div, which is risky (changing forms.py requires a change in partials aswell). Also, in case I'd like to do that with multiple fields, it will get messy.