From 7353e594f026b32b2a0f298b1a12e4eb36afc14f Mon Sep 17 00:00:00 2001 From: Birger Schacht Date: Thu, 3 Oct 2024 10:52:35 +0200 Subject: [PATCH] refactor(relations): integrate RelationFormHX into RelationForm This way we don't have to use a separate `get_form_class` in the view that is uses the form with htmx functionality. Closes: #1226 --- apis_core/relations/forms.py | 50 ++++++++++++++---------------------- apis_core/relations/views.py | 9 +++---- 2 files changed, 23 insertions(+), 36 deletions(-) diff --git a/apis_core/relations/forms.py b/apis_core/relations/forms.py index 644164c2b..213bc689f 100644 --- a/apis_core/relations/forms.py +++ b/apis_core/relations/forms.py @@ -31,6 +31,12 @@ class RelationForm(GenericModelForm): Relations have generic relations to subj and obj, but we hide those ForeignKey form fields and instead show autocomplete choices fields. + In addition, one can pass a hx_post_route argument to the + form to make the form set the `hx-post` attribute to the + given value. + We also pass a `reverse` boolean, wich gets passed on + to the htmx POST endpoint using url parameters (the endpoint + can then select the success_url based on the `reverse` state). """ class Meta: @@ -80,6 +86,8 @@ def __init__(self, *args, **kwargs): generic apis_entities autocomplete with the correct parameters. """ + self.is_reverse = kwargs.pop("reverse", False) + hx_post_route = kwargs.pop("hx_post_route", False) super().__init__(*args, **kwargs) subj_content_type = kwargs["initial"].get("subj_content_type", None) subj_object_id = kwargs["initial"].get("subj_object_id", None) @@ -133,6 +141,16 @@ def __init__(self, *args, **kwargs): self.helper.form_id = f"relation_{model_ct.model}_form" self.helper.add_input(Submit("submit", "Submit")) + if hx_post_route: + urlparams = kwargs["initial"] + urlparams["reverse"] = self.is_reverse + urlparams = {k: v for k, v in urlparams.items() if v} + self.helper.attrs = { + "hx-post": hx_post_route + "?" + urlencode(urlparams), + "hx-swap": "outerHTML", + "hx-target": f"#{self.helper.form_id}", + } + def clean(self) -> dict: """ We check if there are `subj` or `obj` fields in the form data @@ -156,39 +174,9 @@ def clean(self) -> dict: del cleaned_data["obj"] return cleaned_data - -class RelationFormHX(RelationForm): - """ - A Relation form that sets a hx-post attribute to the - form to make the htmx POST request use another route. - We also pass a `reverse` boolean, wich gets passed on - to the POST endpoint using url parameters. The POST - endpoint then calculates the success_url based on the - `reverse` state. - """ - - def __init__(self, *args, **kwargs): - self.is_reverse = kwargs.pop("reverse", False) - super().__init__(*args, **kwargs) - urlparams = kwargs["initial"] - urlparams["reverse"] = self.is_reverse - urlparams = {k: v for k, v in urlparams.items() if v} - relation_content_type = ContentType.objects.get_for_model(self.Meta.model) - hx_post = ( - reverse( - "apis_core:relations:create_relation_form", args=[relation_content_type] - ) - + "?" - + urlencode(urlparams) - ) - self.helper.attrs = { - "hx-post": hx_post, - "hx-swap": "outerHTML", - "hx-target": f"#{self.helper.form_id}", - } - @property def relation_name(self) -> str: + """A helper method to access the correct name of the relation""" if self.is_reverse: return self._meta.model.reverse_name return self._meta.model.name diff --git a/apis_core/relations/views.py b/apis_core/relations/views.py index 1ae3a7b25..bf86555b2 100644 --- a/apis_core/relations/views.py +++ b/apis_core/relations/views.py @@ -1,11 +1,9 @@ from django.contrib.contenttypes.models import ContentType -from django.forms import modelform_factory from django.shortcuts import get_object_or_404 from django.urls import reverse from django.views.generic.base import TemplateView from apis_core.generic.views import Create -from apis_core.relations.forms import RelationFormHX from apis_core.relations.templatetags.relations import ( possible_relation_types_from, relations_from, @@ -42,6 +40,10 @@ def get(self, *args, **kwargs): def get_form_kwargs(self, *args, **kwargs) -> dict: kwargs = super().get_form_kwargs(*args, **kwargs) kwargs["reverse"] = self.reverse + content_type = ContentType.objects.get_for_model(self.model) + kwargs["hx_post_route"] = reverse( + "apis_core:relations:create_relation_form", args=[content_type] + ) return kwargs def get_success_url(self) -> str: @@ -58,9 +60,6 @@ def get_success_url(self) -> str: ] return reverse("apis_core:relations:list_relations", args=args) - def get_form_class(self, *args, **kwargs): - return modelform_factory(self.model, RelationFormHX) - class ListRelations(TemplateView): template_name = "relations/list_relations.html"