Skip to content

Programming patterns

This is a list of programming patterns used in MedUX.

Forms pre-population with GET data

his is an often needed feature.

Just use a simple Mixin named PrepopulateFormViewMixin:

# views.py
from django.views.generic import UpdateView
from medux.common.views.mixins import PrepopulateFormViewMixin

class PersonUpdateView(PrepopulateFormViewMixin, UpdateView):
    model = ...
    # or form_class = PersonUpdateForm

And you're done. Calling your FormView with e.g. /person/42/change/?first_name=James&last_name=Bond will pre-populate the view with that values.

Forms with dependent fields

It's often needed in a Form to have a field dependent on another. MedUX uses HTMX and a few helpers to achieve that.

First, prepare your view, so that it accepts GET parameters that pre-populate your form. See Forms pre-population.

Now, inherit your form from DependencyFormMixin, and define a few attributes in Meta, and a on_<field_name>_prepopulated() method:

# forms.py
from django import forms
from django.urls import reverse
from medux.common.forms.mixins import DependencyFormMixin

class PersonUpdateForm(DependencyFormMixin, forms.ModelForm):
    class Meta:
        update_url = reverse("person:add")
        field_dependencies = {"use_first_name": "#div_id_first_name"}
        fields = ["first_name", "last_name"]

    use_first_name = forms.BooleanField()

    def on_changed_use_first_name(self, *args, **kwargs):
        field = self.fields["first_name"]
        field.disabled = True
        # self.fields["friends"].queryset = Friend.objects.filter(
        #     tenant=self.instance.tenant
        # )

The Mixin sets the correct HTMX attributes to your "use_first_name" field to dynamically update the #div_id_first_name tag each time the value of the checkbox changes. You define in the on_changed_<field_name>() what should change. Options e.g. would be disabling or hiding the field, or dynamically change select options (queryset).

Note

Keep in mind that if you are hiding a field using hidden_widget() and re-render it using HTMX, the corresponding #id is removed from the DOM, and you won't be able to hx-swap into it again.

Note

When you disable a required field, you might get problems with your validation logic. Make sure your form's clean() method deals with that.

The update_url attribute can be dynamically created too by overriding the get_update_url() method, e.g. for Create-/UpdateForms:

def get_update_url(self):
    if self.instance.pk:
        return reverse("person:update", args=(self.instance.pk,))
    else:
        return reverse("person:add")