Search code examples
djangohtmx

Django returns old form data in HTMX response


I changed UpdateView so that it can handle create requests as well if pk=0:

class ObjectView(UpdateView):

    def get_object(self, queryset=None):
        if self.kwargs.get(self.pk_url_kwarg) == 0:
            return None
        return super().get_object(queryset)

    def form_valid(self, form):
        if self.request.htmx:
            return self.render_to_response(self.get_context_data(form=form))
        return redirect(self.object.get_absolute_url())

In my View I am checking if price field was updated and if yes update the price_date field as well:

class PartView(ObjectView):
    model = Part
    form_class = PartForm

    def form_valid(self, form):
        if self.object:
            old = Part.objects.get(id=self.object.id)
            self.object = form.save(commit=False)
            if self.object.price != old.price:
                self.object.price_date = date.today()
            self.object.save()
        else:
            self.object = form.save()
        return super().form_valid(form)

I make an htmx call to it from my template:

<div hx-target="this">
  <form method="post"
        hx-post="{{ hx_url }}"
        hx-on:htmx:validation:failed="this.reportValidity()"
        hx-trigger="click from:#btn-save">
    {% csrf_token %}
    {{ form.price }}
    {{ form.price_date }}
  </form>  
  {% include "btn_save.html" %}
</div>

The problem is even though it successfully updates the price_date in the DB it still returns the form with the old value, and now if I press "Save" again, it will overwrite the previous change. Why does it happen?


Solution

  • That's because you're using the old form instance for re-rendering, which does not have the price date value changed.

    To fix it, you should instantiate the form again, before passing it to the template context, eg

    form = PartForm(instance=self.object)
    return self.render_to_response(self.get_context_data(form=form))