From 4e1f0f962b04d6392c291f80f1f9db637965d9fa Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 7 Mar 2025 14:50:36 +0100 Subject: [PATCH] use nested admin for simpler plan admin --- hub/services/admin.py | 59 +++++++++++++++++++++++++++---------------- hub/settings.py | 1 + pyproject.toml | 1 + uv.lock | 25 ++++++++++++++++++ 4 files changed, 64 insertions(+), 22 deletions(-) diff --git a/hub/services/admin.py b/hub/services/admin.py index 278aafa..804d2b6 100644 --- a/hub/services/admin.py +++ b/hub/services/admin.py @@ -14,6 +14,42 @@ from .models import ( WebsiteFaq, ) +import nested_admin + + +class PlanInline(nested_admin.NestedStackedInline): + model = Plan + extra = 1 + fieldsets = ( + (None, {"fields": ("name", "description", "pricing", "plan_description")}), + ) + + +class ExternalLinkOfferingInline(admin.TabularInline): + model = ExternalLinkOffering + extra = 1 + fields = ("description", "url", "order") + ordering = ("order", "description") + + +class OfferingInline(nested_admin.NestedStackedInline): + model = ServiceOffering + extra = 1 + fieldsets = ( + ( + None, + { + "fields": ( + "description", + "service", + "cloud_provider", + "offer_description", + ) + }, + ), + ) + inlines = [PlanInline] + @admin.register(ReusableText) class ReusableTextAdmin(admin.ModelAdmin): @@ -31,14 +67,8 @@ class CategoryAdmin(admin.ModelAdmin): ordering = ("order", "name") -class OfferingInline(admin.StackedInline): - model = ServiceOffering - extra = 1 - fieldsets = ((None, {"fields": ("description", "service", "cloud_provider")}),) - - @admin.register(CloudProvider) -class CloudProviderAdmin(admin.ModelAdmin): +class CloudProviderAdmin(nested_admin.NestedModelAdmin): list_display = ("name", "slug", "logo_preview") search_fields = ("name", "description") prepopulated_fields = {"slug": ("name",)} @@ -90,21 +120,6 @@ class ServiceAdmin(admin.ModelAdmin): partner_list.short_description = "Consulting Partners" -class PlanInline(admin.StackedInline): - model = Plan - extra = 1 - fieldsets = ( - (None, {"fields": ("name", "description", "pricing", "plan_description")}), - ) - - -class ExternalLinkOfferingInline(admin.TabularInline): - model = ExternalLinkOffering - extra = 1 - fields = ("description", "url", "order") - ordering = ("order", "description") - - @admin.register(ServiceOffering) class ServiceOfferingAdmin(admin.ModelAdmin): list_display = ("service", "cloud_provider") diff --git a/hub/settings.py b/hub/settings.py index 62229c7..b874b85 100644 --- a/hub/settings.py +++ b/hub/settings.py @@ -69,6 +69,7 @@ INSTALLED_APPS = [ "django_prose_editor", "rest_framework", "schema_viewer", + "nested_admin", # local "hub.services", "hub.broker", diff --git a/pyproject.toml b/pyproject.toml index 98498dd..2dfea51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,7 @@ readme = "README.md" requires-python = ">=3.13" dependencies = [ "django>=5.1.5", + "django-nested-admin>=4.1.1", "django-prose-editor[sanitize]>=0.10.3", "django-schema-viewer>=0.5.2", "djangorestframework>=3.15.2", diff --git a/uv.lock b/uv.lock index 081661a..6f04485 100644 --- a/uv.lock +++ b/uv.lock @@ -1,4 +1,5 @@ version = 1 +revision = 1 requires-python = ">=3.13" [[package]] @@ -80,6 +81,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/61/d1/be003d14c880c100d8713b2ca0a286728e6e8b47e50d25e2fab31adc9632/django_js_asset-3.0.1-py3-none-any.whl", hash = "sha256:0b7ee73c45ca65cccbcc2f60cbe8fbc87ff133b543c282cb64fe6c13d7ca4c10", size = 4283 }, ] +[[package]] +name = "django-nested-admin" +version = "4.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-monkey-business" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/d1/bd500d354dcc3ccbf74507c97dabc5aee18bf0620d2df3deb3971b5c14ed/django-nested-admin-4.1.1.tar.gz", hash = "sha256:645d63b38d579b034a65e0983f1f8cbb8824c75b4232f8d62a1583fa7a9f568f", size = 421628 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/e2/2a58c3c21c2e8c383f7e9de2874fa7b443705146e54d0364f1fe6fc31b7e/django_nested_admin-4.1.1-py3-none-any.whl", hash = "sha256:7e72ab7a8ae4c91074f6f709ce38fdf54f9c5f78d19e68772e0f05b83090ec9f", size = 465355 }, +] + [[package]] name = "django-prose-editor" version = "0.10.3" @@ -239,12 +252,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, ] +[[package]] +name = "python-monkey-business" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/bc/a6182bb30701d0df25ad336f2dd74343447032e0995025ba82079a94f745/python-monkey-business-1.1.0.tar.gz", hash = "sha256:8393839cc741415ed5ddc2bd58e2d4ce07f966a7d26b7aebff19dcec64818edc", size = 4270 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/a2/b6a5cbd5822b4d049adfedf496ce0908480e5a41722fda7b7ffaacb086d6/python_monkey_business-1.1.0-py2.py3-none-any.whl", hash = "sha256:15b4f603c749ba9a7b4f1acd36af023a6c5ba0f7e591c945f8253f0ef44bf389", size = 4670 }, +] + [[package]] name = "servala-fe" version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "django" }, + { name = "django-nested-admin" }, { name = "django-prose-editor", extra = ["sanitize"] }, { name = "django-schema-viewer" }, { name = "djangorestframework" }, @@ -262,6 +285,7 @@ dev = [ requires-dist = [ { name = "django", specifier = ">=5.1.5" }, { name = "django-browser-reload", marker = "extra == 'dev'", specifier = "~=1.13" }, + { name = "django-nested-admin", specifier = ">=4.1.1" }, { name = "django-prose-editor", extras = ["sanitize"], specifier = ">=0.10.3" }, { name = "django-schema-viewer", specifier = ">=0.5.2" }, { name = "djangorestframework", specifier = ">=3.15.2" }, @@ -269,6 +293,7 @@ requires-dist = [ { name = "odoorpc", specifier = ">=0.10.1" }, { name = "pillow", specifier = ">=11.1.0" }, ] +provides-extras = ["dev"] [[package]] name = "sqlparse"