From 9675809c75b93d7683af02d2f2f80802811c867d Mon Sep 17 00:00:00 2001 From: Birger Schacht Date: Thu, 21 Dec 2023 15:33:45 +0100 Subject: [PATCH] feat: make generic crudl views Create generic Create, View, Update, Delete and List views that work with ContentTypes --- .../core/generic_confirm_delete.html | 32 ++++++++++++++ .../core/templates/core/generic_detail.html | 6 +++ .../core/templates/core/generic_form.html | 6 +++ .../core/templates/core/generic_list.html | 6 +++ apis_core/core/urls.py | 36 ++++++++++++++++ apis_core/core/views.py | 43 +++++++++++++++++++ apis_core/urls.py | 1 + 7 files changed, 130 insertions(+) create mode 100644 apis_core/core/templates/core/generic_confirm_delete.html create mode 100644 apis_core/core/templates/core/generic_detail.html create mode 100644 apis_core/core/templates/core/generic_form.html create mode 100644 apis_core/core/templates/core/generic_list.html create mode 100644 apis_core/core/urls.py diff --git a/apis_core/core/templates/core/generic_confirm_delete.html b/apis_core/core/templates/core/generic_confirm_delete.html new file mode 100644 index 000000000..6cf5240c5 --- /dev/null +++ b/apis_core/core/templates/core/generic_confirm_delete.html @@ -0,0 +1,32 @@ +{% extends basetemplate|default:"base.html" %} + +{% block content %} + + +{% endblock content %} diff --git a/apis_core/core/templates/core/generic_detail.html b/apis_core/core/templates/core/generic_detail.html new file mode 100644 index 000000000..1fde32852 --- /dev/null +++ b/apis_core/core/templates/core/generic_detail.html @@ -0,0 +1,6 @@ +{% extends basetemplate|default:"base.html" %} +{% load render_table from django_tables2 %} + +{% block content %} + {{ object }} +{% endblock content %} diff --git a/apis_core/core/templates/core/generic_form.html b/apis_core/core/templates/core/generic_form.html new file mode 100644 index 000000000..1befa0bde --- /dev/null +++ b/apis_core/core/templates/core/generic_form.html @@ -0,0 +1,6 @@ +{% extends basetemplate|default:"base.html" %} +{% load crispy_forms_tags %} + +{% block content %} + {% crispy form %} +{% endblock content %} diff --git a/apis_core/core/templates/core/generic_list.html b/apis_core/core/templates/core/generic_list.html new file mode 100644 index 000000000..d4f3f8f1e --- /dev/null +++ b/apis_core/core/templates/core/generic_list.html @@ -0,0 +1,6 @@ +{% extends basetemplate|default:"base.html" %} +{% load render_table from django_tables2 %} + +{% block content %} + {% render_table table %} +{% endblock content %} diff --git a/apis_core/core/urls.py b/apis_core/core/urls.py new file mode 100644 index 000000000..0b031780c --- /dev/null +++ b/apis_core/core/urls.py @@ -0,0 +1,36 @@ +from django.contrib.contenttypes.models import ContentType +from django.shortcuts import get_object_or_404 +from django.urls import include, path, register_converter + +from apis_core.core import views + + +class ContenttypeConverter: + regex = r"\w+\.\w+" + + def to_python(self, value): + app_label, model = value.split(".") + return get_object_or_404(ContentType, app_label=app_label, model=model) + + def to_url(self, value): + return f"{value.app_label}.{value.model}" + + +register_converter(ContenttypeConverter, "ccc") + +app_name = "core" + +urlpatterns = [ + path( + "/", + include( + [ + path("", views.ListCC.as_view(), name="genericlist"), + path("", views.DetailCC.as_view()), + path("create", views.CreateCC.as_view()), + path("delete/", views.DeleteCC.as_view()), + path("update/", views.UpdateCC.as_view()), + ] + ), + ) +] diff --git a/apis_core/core/views.py b/apis_core/core/views.py index f47b740b8..c078a65f5 100644 --- a/apis_core/core/views.py +++ b/apis_core/core/views.py @@ -1,5 +1,12 @@ import json +from django.views.generic import DetailView, ListView +from django.views.generic.edit import CreateView, UpdateView, DeleteView +from django.urls import reverse + +from django_tables2 import SingleTableView +from django_tables2.tables import table_factory + from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated @@ -25,3 +32,39 @@ def get(self, request, *args, **kwargs): if app_labels: app_labels = app_labels.split(",") return Response(json.loads(datadump_serializer(app_labels, "json"))) + + +class CCMixin: + def get_template_names(self): + return super().get_template_names() + [ + f"core/generic{self.template_name_suffix}.html" + ] + + def get_queryset(self): + return self.kwargs.get("contenttype").model_class().objects.all() + + +class ListCC(CCMixin, SingleTableView): + def get_table_class(self): + return table_factory(self.kwargs.get("contenttype").model_class()) + + +class DetailCC(CCMixin, DetailView): + pass + + +class CreateCC(CCMixin, CreateView): + fields = "__all__" + template_name = "core/generic_form.html" + + +class DeleteCC(CCMixin, DeleteView): + def get_success_url(self): + return reverse( + "apis:core:genericlist", + args=[self.request.resolver_match.kwargs["contenttype"]], + ) + + +class UpdateCC(CCMixin, UpdateView): + fields = "__all__" diff --git a/apis_core/urls.py b/apis_core/urls.py index 5b9a2cbf6..64d235b15 100644 --- a/apis_core/urls.py +++ b/apis_core/urls.py @@ -168,6 +168,7 @@ def build_apis_mock_request(method, path, view, original_request, **kwargs): name="GetEntityGeneric", ), path("api/dumpdata", Dumpdata.as_view()), + path("", include("apis_core.core.urls", namespace="core")) ] if "apis_fulltext_download" in settings.INSTALLED_APPS: