Added my own base FormView, and replaced the current function-based user form views with a new UserFormView that based on my base FormView in the Mia core application. I do not know if I am doing the right thing.
This commit is contained in:
parent
e06821194c
commit
3c655b8f87
@ -24,6 +24,7 @@ from dirtyfields import DirtyFieldsMixin
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models, connection, OperationalError, transaction
|
from django.db import models, connection, OperationalError, transaction
|
||||||
from django.db.models.functions import Now
|
from django.db.models.functions import Now
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from mia_core.utils import get_multi_lingual_attr, set_multi_lingual_attr, \
|
from mia_core.utils import get_multi_lingual_attr, set_multi_lingual_attr, \
|
||||||
new_pk
|
new_pk
|
||||||
@ -100,6 +101,10 @@ class User(DirtyFieldsMixin, models.Model):
|
|||||||
REQUIRED_FIELDS = ["id", "name"]
|
REQUIRED_FIELDS = ["id", "name"]
|
||||||
USERNAME_FIELD = "login_id"
|
USERNAME_FIELD = "login_id"
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.current_user = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_anonymous(self) -> bool:
|
def is_anonymous(self) -> bool:
|
||||||
return False
|
return False
|
||||||
@ -119,20 +124,23 @@ class User(DirtyFieldsMixin, models.Model):
|
|||||||
return "%s (%s)" % (
|
return "%s (%s)" % (
|
||||||
self.name.__str__(), self.login_id.__str__())
|
self.name.__str__(), self.login_id.__str__())
|
||||||
|
|
||||||
def save(self, current_user=None, force_insert=False, force_update=False,
|
def save(self, force_insert=False, force_update=False, using=None,
|
||||||
using=None, update_fields=None):
|
update_fields=None):
|
||||||
if self.pk is None:
|
if self.pk is None:
|
||||||
self.pk = new_pk(User)
|
self.pk = new_pk(User)
|
||||||
if current_user is not None:
|
if self.current_user is not None:
|
||||||
self.created_by = current_user
|
self.created_by = self.current_user
|
||||||
if current_user is not None:
|
if self.current_user is not None:
|
||||||
self.updated_by = current_user
|
self.updated_by = self.current_user
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
super(User, self).save(
|
super(User, self).save(
|
||||||
force_insert=force_insert, force_update=force_update,
|
force_insert=force_insert, force_update=force_update,
|
||||||
using=using, update_fields=update_fields)
|
using=using, update_fields=update_fields)
|
||||||
User.objects.filter(pk=self.pk).update(updated_at=Now())
|
User.objects.filter(pk=self.pk).update(updated_at=Now())
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("mia_core:users.detail", args=(self,))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = "users"
|
db_table = "users"
|
||||||
app_label = "mia_core"
|
app_label = "mia_core"
|
||||||
|
@ -31,11 +31,11 @@ app_name = "mia_core"
|
|||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("logout", views.logout, name="logout"),
|
path("logout", views.logout, name="logout"),
|
||||||
path("users", views.UserListView.as_view(), name="users"),
|
path("users", views.UserListView.as_view(), name="users"),
|
||||||
path("users/create", views.user_form, name="users.create"),
|
path("users/create", views.UserFormView.as_view(), name="users.create"),
|
||||||
path("users/store", views.user_store, name="users.store"),
|
path("users/store", views.UserFormView.as_view(), name="users.store"),
|
||||||
path("users/<user:user>", views.UserView.as_view(), name="users.detail"),
|
path("users/<user:user>", views.UserView.as_view(), name="users.detail"),
|
||||||
path("users/<user:user>/edit", views.user_form, name="users.edit"),
|
path("users/<user:user>/edit", views.UserFormView.as_view(), name="users.edit"),
|
||||||
path("users/<user:user>/update", views.user_store, name="users.update"),
|
path("users/<user:user>/update", views.UserFormView.as_view(), name="users.update"),
|
||||||
path("users/<user:user>/delete", views.user_delete, name="users.delete"),
|
path("users/<user:user>/delete", views.user_delete, name="users.delete"),
|
||||||
path("api/users/<str:login_id>/exists", views.api_users_exists,
|
path("api/users/<str:login_id>/exists", views.api_users_exists,
|
||||||
name="api.users.exists"),
|
name="api.users.exists"),
|
||||||
|
@ -18,11 +18,16 @@
|
|||||||
"""The views of the Mia core application.
|
"""The views of the Mia core application.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from typing import Dict, Type, Optional, Union
|
||||||
|
|
||||||
|
from dirtyfields import DirtyFieldsMixin
|
||||||
|
from django import forms
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import logout as logout_user
|
from django.contrib.auth import logout as logout_user
|
||||||
from django.contrib.messages.views import SuccessMessageMixin
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
from django.db.models import Model
|
||||||
from django.http import HttpResponse, JsonResponse, HttpRequest, \
|
from django.http import HttpResponse, JsonResponse, HttpRequest, \
|
||||||
HttpResponseRedirect
|
HttpResponseRedirect, Http404
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
@ -30,12 +35,157 @@ from django.utils.translation import gettext_noop
|
|||||||
from django.views.decorators.http import require_POST, require_GET
|
from django.views.decorators.http import require_POST, require_GET
|
||||||
from django.views.generic import DeleteView as CoreDeleteView, ListView, \
|
from django.views.generic import DeleteView as CoreDeleteView, ListView, \
|
||||||
DetailView
|
DetailView
|
||||||
|
from django.views.generic.base import View
|
||||||
|
|
||||||
from . import stored_post
|
from . import stored_post, utils
|
||||||
from .digest_auth import login_required
|
from .digest_auth import login_required
|
||||||
from .forms import UserForm
|
from .forms import UserForm
|
||||||
from .models import User
|
from .models import User
|
||||||
from .utils import strip_post
|
from .utils import strip_post, UrlBuilder
|
||||||
|
|
||||||
|
|
||||||
|
class FormView(View):
|
||||||
|
"""The base form view."""
|
||||||
|
model: Type[Model] = None
|
||||||
|
form: Type[forms.Form] = None
|
||||||
|
template_name: str = None
|
||||||
|
context_object_name: str = "form"
|
||||||
|
error_url: str = None
|
||||||
|
success_url: str = None
|
||||||
|
not_modified_message: str = None
|
||||||
|
success_message: str = None
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self._object = None
|
||||||
|
self._is_object_requested = False
|
||||||
|
|
||||||
|
def dispatch(self, request: HttpRequest, *args, **kwargs):
|
||||||
|
"""The view to store an accounting transaction.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The response.
|
||||||
|
"""
|
||||||
|
obj = self.get_current_object()
|
||||||
|
if self.request.method != "POST":
|
||||||
|
previous_post = stored_post.get_previous_post(self.request)
|
||||||
|
if previous_post is not None:
|
||||||
|
form = self.make_form_from_post(previous_post)
|
||||||
|
elif obj is not None:
|
||||||
|
form = self.make_form_from_model(obj)
|
||||||
|
else:
|
||||||
|
form = self._form()
|
||||||
|
return render(self.request, self.get_template_name(), {
|
||||||
|
self.context_object_name: form
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
post = self.request.POST.dict()
|
||||||
|
utils.strip_post(post)
|
||||||
|
form = self.make_form_from_post(post)
|
||||||
|
if not form.is_valid():
|
||||||
|
url = str(utils.UrlBuilder(self.get_error_url())
|
||||||
|
.query(r=self.request.GET.get("r")))
|
||||||
|
return stored_post.error_redirect(request, url, post)
|
||||||
|
if obj is None:
|
||||||
|
obj = self._model()
|
||||||
|
self._set_current_object(obj)
|
||||||
|
self.fill_model_from_form(obj, form)
|
||||||
|
if isinstance(obj, DirtyFieldsMixin)\
|
||||||
|
and not obj.is_dirty(check_relationship=True):
|
||||||
|
message = self.get_not_modified_message()
|
||||||
|
else:
|
||||||
|
obj.save()
|
||||||
|
message = self.get_success_message()
|
||||||
|
messages.success(request, message)
|
||||||
|
return redirect(str(UrlBuilder(self.get_success_url())
|
||||||
|
.query(r=self.request.GET.get("r"))))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _form(self):
|
||||||
|
if self.form is None:
|
||||||
|
raise AttributeError("The form attribute was not set.")
|
||||||
|
return self.form
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _model(self):
|
||||||
|
if self.model is None:
|
||||||
|
raise AttributeError("The model attribute was not set.")
|
||||||
|
return self.model
|
||||||
|
|
||||||
|
def _set_current_object(self, obj: Model) -> None:
|
||||||
|
"""Sets the current object that we are operating."""
|
||||||
|
self._object = obj
|
||||||
|
self._is_object_requested = True
|
||||||
|
|
||||||
|
def _get_current_object(self) -> Optional[Model]:
|
||||||
|
"""Returns the current object that we are operating and cached."""
|
||||||
|
if not self._is_object_requested:
|
||||||
|
self._object = self.get_current_object()
|
||||||
|
self._is_object_requested = True
|
||||||
|
return self._object
|
||||||
|
|
||||||
|
def get_template_name(self) -> str:
|
||||||
|
"""Returns the name of the template."""
|
||||||
|
if self.template_name is not None:
|
||||||
|
return self.template_name
|
||||||
|
if self.model is not None:
|
||||||
|
app_name = self.request.resolver_match.app_name
|
||||||
|
model_name = self.model.__name__.lower()
|
||||||
|
return F"{app_name}/{model_name}_form.html"
|
||||||
|
raise AttributeError(
|
||||||
|
"Please either define the template_name or the model attribute.")
|
||||||
|
|
||||||
|
def make_form_from_post(self, post: Dict[str, str]) -> forms.Form:
|
||||||
|
"""Creates and returns the form from the POST data."""
|
||||||
|
return self._form(post)
|
||||||
|
|
||||||
|
def make_form_from_model(self, obj: Model) -> forms.Form:
|
||||||
|
"""Creates and returns the form from a data model."""
|
||||||
|
return self._form(obj)
|
||||||
|
|
||||||
|
def fill_model_from_form(self, obj: Model, form: forms.Form) -> None:
|
||||||
|
"""Fills in the data model from the form."""
|
||||||
|
for name in form.data.keys():
|
||||||
|
setattr(obj, name, form.data[name])
|
||||||
|
|
||||||
|
def get_error_url(self) -> str:
|
||||||
|
"""Returns the URL on error."""
|
||||||
|
if self.error_url is not None:
|
||||||
|
return self.error_url
|
||||||
|
raise AttributeError(
|
||||||
|
"Please define either the error_url attribute"
|
||||||
|
" or the get_error_url method.")
|
||||||
|
|
||||||
|
def get_success_url(self) -> str:
|
||||||
|
"""Returns the URL on success."""
|
||||||
|
if self.success_url is not None:
|
||||||
|
return self.success_url
|
||||||
|
obj = self._get_current_object()
|
||||||
|
get_absolute_url = getattr(obj, "get_absolute_url", None)
|
||||||
|
if get_absolute_url is not None:
|
||||||
|
return get_absolute_url()
|
||||||
|
raise AttributeError(
|
||||||
|
"Please define either the success_url attribute,"
|
||||||
|
" the get_absolute_url method on the model,"
|
||||||
|
" or the get_success_url method.")
|
||||||
|
|
||||||
|
def get_not_modified_message(self) -> str:
|
||||||
|
"""Returns the message when the data was not modified."""
|
||||||
|
return self.not_modified_message
|
||||||
|
|
||||||
|
def get_success_message(self) -> str:
|
||||||
|
"""Returns the success message."""
|
||||||
|
return self.success_message
|
||||||
|
|
||||||
|
def get_current_object(self) -> Optional[Model]:
|
||||||
|
"""Finds and returns the current object, or None on a create form."""
|
||||||
|
if "pk" in self.request.resolver_match.kwargs:
|
||||||
|
pk = self.request.resolver_match.kwargs["pk"]
|
||||||
|
try:
|
||||||
|
return self._model.objects.get(pk=pk)
|
||||||
|
except self._model.DoesNotExist:
|
||||||
|
raise Http404
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class DeleteView(SuccessMessageMixin, CoreDeleteView):
|
class DeleteView(SuccessMessageMixin, CoreDeleteView):
|
||||||
@ -79,73 +229,52 @@ class UserView(DetailView):
|
|||||||
return self.request.resolver_match.kwargs["user"]
|
return self.request.resolver_match.kwargs["user"]
|
||||||
|
|
||||||
|
|
||||||
@require_GET
|
@method_decorator(login_required, name="dispatch")
|
||||||
@login_required
|
class UserFormView(FormView):
|
||||||
def user_form(request: HttpRequest, user: User = None) -> HttpResponse:
|
model = User
|
||||||
"""The view to edit an accounting transaction.
|
form = UserForm
|
||||||
|
not_modified_message = gettext_noop("This user account was not changed.")
|
||||||
|
success_message = gettext_noop("This user account was saved successfully.")
|
||||||
|
|
||||||
Args:
|
def make_form_from_post(self, post: Dict[str, str]) -> UserForm:
|
||||||
request: The request.
|
"""Creates and returns the form from the POST data."""
|
||||||
user: The account.
|
form = UserForm(post)
|
||||||
|
form.user = self.get_current_object()
|
||||||
|
form.current_user = self.request.user
|
||||||
|
return form
|
||||||
|
|
||||||
Returns:
|
def make_form_from_model(self, obj: User) -> forms.Form:
|
||||||
The response.
|
"""Creates and returns the form from a data model."""
|
||||||
"""
|
|
||||||
previous_post = stored_post.get_previous_post(request)
|
|
||||||
if previous_post is not None:
|
|
||||||
form = UserForm(previous_post)
|
|
||||||
elif user is not None:
|
|
||||||
form = UserForm({
|
form = UserForm({
|
||||||
"login_id": user.login_id,
|
"login_id": obj.login_id,
|
||||||
"name": user.name,
|
"name": obj.name,
|
||||||
"is_disabled": user.is_disabled,
|
"is_disabled": obj.is_disabled,
|
||||||
})
|
})
|
||||||
else:
|
form.user = self.get_current_object()
|
||||||
form = UserForm()
|
form.current_user = self.request.user
|
||||||
form.user = user
|
return form
|
||||||
form.current_user = request.user
|
|
||||||
return render(request, "mia_core/user_form.html", {
|
|
||||||
"form": form,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
def fill_model_from_form(self, obj: User, form: UserForm) -> None:
|
||||||
|
"""Fills in the data model from the form."""
|
||||||
|
obj.login_id = form["login_id"].value()
|
||||||
|
if form["password"].value() is not None:
|
||||||
|
obj.set_digest_password(
|
||||||
|
form["login_id"].value(), form["password"].value())
|
||||||
|
obj.name = form["name"].value()
|
||||||
|
obj.is_disabled = form["is_disabled"].value()
|
||||||
|
obj.current_user = self.request.user
|
||||||
|
|
||||||
def user_store(request: HttpRequest,
|
def get_error_url(self) -> str:
|
||||||
user: User = None) -> HttpResponseRedirect:
|
"""Returns the URL on error."""
|
||||||
"""The view to store a user.
|
user = self.get_current_object()
|
||||||
|
return reverse("mia_core:users.create") if user is None\
|
||||||
|
else reverse("mia_core:users.edit", args=(user,))
|
||||||
|
|
||||||
Args:
|
def get_current_object(self) -> Optional[Model]:
|
||||||
request: The request.
|
"""Returns the current object, or None on a create form."""
|
||||||
user: The user.
|
if "user" in self.request.resolver_match.kwargs:
|
||||||
|
return self.request.resolver_match.kwargs["user"]
|
||||||
Returns:
|
return None
|
||||||
The response.
|
|
||||||
"""
|
|
||||||
post = request.POST.dict()
|
|
||||||
strip_post(post)
|
|
||||||
form = UserForm(post)
|
|
||||||
form.user = user
|
|
||||||
form.current_user = request.user
|
|
||||||
if not form.is_valid():
|
|
||||||
if user is None:
|
|
||||||
url = reverse("mia_core:users.create")
|
|
||||||
else:
|
|
||||||
url = reverse("mia_core:users.edit", args=(user,))
|
|
||||||
return stored_post.error_redirect(request, url, post)
|
|
||||||
if user is None:
|
|
||||||
user = User()
|
|
||||||
user.login_id = form["login_id"].value()
|
|
||||||
if form["password"].value() is not None:
|
|
||||||
user.set_digest_password(
|
|
||||||
form["login_id"].value(), form["password"].value())
|
|
||||||
user.name = form["name"].value()
|
|
||||||
user.is_disabled = form["is_disabled"].value()
|
|
||||||
if not user.is_dirty():
|
|
||||||
message = gettext_noop("This user account was not changed.")
|
|
||||||
else:
|
|
||||||
user.save(current_user=request.user)
|
|
||||||
message = gettext_noop("This user account was saved successfully.")
|
|
||||||
messages.success(request, message)
|
|
||||||
return redirect("mia_core:users.detail", user)
|
|
||||||
|
|
||||||
|
|
||||||
@require_POST
|
@require_POST
|
||||||
|
Loading…
Reference in New Issue
Block a user