From df67125599ac82cacd116ed60c76fa8111a4d0cd Mon Sep 17 00:00:00 2001 From: Pablo Moreno Date: Mon, 20 Jan 2025 11:40:07 +0100 Subject: [PATCH] feat: mixin for update forms --- config/mixins.py | 66 +++++++++++++++++++ users/forms/change_password.py | 16 +++++ users/forms/info.py | 7 +- web/mixins.py | 51 +------------- web/templates/components/default/form.html | 25 +++++++ web/templates/components/users/info.html | 33 +++++----- .../users/retrieve_update_address.html | 16 ++--- web/templates/users/user_details.html | 11 +++- web/tests/test_change_user_password.py | 30 +++++++++ web/tests/test_customer_addresses.py | 19 ++++-- web/tests/test_user_info.py | 10 +-- web/urls.py | 7 +- web/views/components.py | 56 +++++++++------- 13 files changed, 227 insertions(+), 120 deletions(-) create mode 100644 config/mixins.py create mode 100644 users/forms/change_password.py create mode 100644 web/templates/components/default/form.html create mode 100644 web/tests/test_change_user_password.py diff --git a/config/mixins.py b/config/mixins.py new file mode 100644 index 0000000..5d85e3b --- /dev/null +++ b/config/mixins.py @@ -0,0 +1,66 @@ +from typing import Type + +from django import forms +from django.db import models +from django.shortcuts import render +from django.views.generic import TemplateView + + +class HTMXFormComponent(TemplateView): + form_class: Type[forms.ModelForm] = None + template_name: str = "components/default/form.html" + hx_trigger = "" + view_name = "" + + def get_view_name(self): + return self.view_name + + def get_form_class(self) -> Type[forms.ModelForm]: + return self.form_class + + def get_form(self, initial=True): + instance = self.get_object() + + if initial: + return self.form_class(initial=self.get_initial_values(instance), instance=instance) + + return self.form_class(self.request.POST, instance=instance) + + def get_object(self) -> models.Model: + raise NotImplementedError + + def get_initial_values(self, instance): + return {} + + def get_context_data(self, **kwargs): + form = self.get_form() + + return { + "form": form, + "url": self.get_view_name(), + } + + def post(self, request, *args, **kwargs): + form = self.get_form(initial=False) + + if form.is_valid(): + instance = form.save() + + response = render( + request, + self.template_name, + { + "form": form, + "instance": instance, + }, + ) + response["HX-Trigger"] = self.hx_trigger + return response + + return render( + request, + self.template_name, + { + "form": form, + }, + ) diff --git a/users/forms/change_password.py b/users/forms/change_password.py new file mode 100644 index 0000000..10ca23b --- /dev/null +++ b/users/forms/change_password.py @@ -0,0 +1,16 @@ +from django.contrib.auth import get_user_model +from django.utils.text import gettext_lazy as _ +from django.contrib.auth.forms import PasswordChangeForm + +from web.mixins import StylingMixin + +User = get_user_model() + + +class ChangePasswordForm(StylingMixin, PasswordChangeForm): + styled_fields = ("old_password", "new_password1", "new_password2") + placeholder_for_field = { + "old_password": _("********"), + "new_password1": _("********"), + "new_password2": _("********"), + } diff --git a/users/forms/info.py b/users/forms/info.py index 2eff903..7adcd18 100644 --- a/users/forms/info.py +++ b/users/forms/info.py @@ -15,7 +15,12 @@ class UserInfoForm(StylingMixin, forms.ModelForm): "last_name": _("Moreno"), } - classes = StylingMixin.classes.difference({'w-full'}) + def save(self, commit=True): + self.instance.username = self.cleaned_data.get("email") + return super().save(commit) + + def is_valid(self): + return super().is_valid() class Meta: model = User diff --git a/web/mixins.py b/web/mixins.py index ce87893..987f1c6 100644 --- a/web/mixins.py +++ b/web/mixins.py @@ -1,9 +1,5 @@ from django.conf import settings from django.core.paginator import Paginator -from django import forms -from django.db import models -from django.views.generic import TemplateView -from django.shortcuts import get_object_or_404, render class FilteredQuerysetMixin: @@ -62,11 +58,7 @@ class StylingMixin: for field_name in self.styled_fields: field = self.fields[field_name] field.required = True - field.widget.attrs.update( - { - "class": ' '.join(self.classes) - } - ) + field.widget.attrs.update({"class": " ".join(self.classes)}) if self.placeholder_for_field.get(field_name): field.widget.attrs.update( @@ -74,44 +66,3 @@ class StylingMixin: "placeholder": self.placeholder_for_field.get(field_name), } ) - - -class ReadUpdateView(TemplateView): - model: models.Model = None - form_class: forms.ModelForm = None - template_name: str = "" - ok_template_name: str = "" - error_template_name: str = "" - - def get_model(self): - return self.model - - def get_object(self): - pk = self.kwargs.get('pk') - cls = self.get_model() - return get_object_or_404(cls, pk=pk) - - def get_initial_values(self, instance): - return {} - - def get_context_data(self, **kwargs): - instance = self.get_object() - form = self.form_class(initial=self.get_initial_values(instance)) - - return { - "form": form, - } - - def post(self, request, *args, **kwargs): - form = self.form_class(request.POST) - - if form.is_valid(): - instance = form.save() - return render(request, self.ok_template_name, { - "form": form, - "instance": instance, - }) - - return render(request, self.error_template_name, { - "form": form, - }) diff --git a/web/templates/components/default/form.html b/web/templates/components/default/form.html new file mode 100644 index 0000000..2e2dabb --- /dev/null +++ b/web/templates/components/default/form.html @@ -0,0 +1,25 @@ +{% load i18n %} +{% load static %} +
+ {% csrf_token %} + {% for field in form %} +
+ + {{ field }} +
+ {% endfor %} + + {% for k, error in form.errors.items %} + {{ error }} + {% endfor %} + + +
diff --git a/web/templates/components/users/info.html b/web/templates/components/users/info.html index b4b6b42..2e2dabb 100644 --- a/web/templates/components/users/info.html +++ b/web/templates/components/users/info.html @@ -1,28 +1,25 @@ {% load i18n %} {% load static %} -
- {% csrf_token %} - {% for field in form %} + + {% csrf_token %} + {% for field in form %}
- - - {{ field }} + + {{ field }}
- {% endfor %} + {% endfor %} - {% for k, error in form.errors.items %} + {% for k, error in form.errors.items %} {{ error }} - {% endfor %} + {% endfor %} - - - + > + {% translate 'Guardar' %} +
diff --git a/web/templates/components/users/retrieve_update_address.html b/web/templates/components/users/retrieve_update_address.html index d6263e8..65a2ec1 100644 --- a/web/templates/components/users/retrieve_update_address.html +++ b/web/templates/components/users/retrieve_update_address.html @@ -2,11 +2,11 @@ {% load static %} {% for address in customer_addresses %}