Skip to content

Commit

Permalink
refactor(relations): integrate RelationFormHX into RelationForm
Browse files Browse the repository at this point in the history
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
  • Loading branch information
b1rger committed Oct 3, 2024
1 parent cda3436 commit a51702f
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 36 deletions.
50 changes: 19 additions & 31 deletions apis_core/relations/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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
7 changes: 2 additions & 5 deletions apis_core/relations/views.py
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -42,6 +40,8 @@ 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:
Expand All @@ -58,9 +58,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"
Expand Down

0 comments on commit a51702f

Please sign in to comment.