From 5e966f385492f021b8af38620fbede2bbeb549e4 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra <kiara@procolix.eu> Date: Tue, 11 Mar 2025 10:42:03 +0100 Subject: [PATCH] Revert "basic versioned forms" This reverts commit 9dd92b4cc180e88ffc14a96ec979a90c84e1676f. --- panel/src/panel/configuration/__init__.py | 5 -- panel/src/panel/configuration/v1.py | 25 ------ panel/src/panel/templates/base.html | 3 - .../panel/templates/configuration_form.html | 13 ---- panel/src/panel/urls.py | 1 - panel/src/panel/views.py | 76 +------------------ 6 files changed, 2 insertions(+), 121 deletions(-) delete mode 100644 panel/src/panel/templates/configuration_form.html diff --git a/panel/src/panel/configuration/__init__.py b/panel/src/panel/configuration/__init__.py index 41231e2..9104cf9 100644 --- a/panel/src/panel/configuration/__init__.py +++ b/panel/src/panel/configuration/__init__.py @@ -5,17 +5,14 @@ import sys from importlib import import_module from importlib.util import find_spec from django.utils.functional import classproperty -from django_pydantic_field import SchemaField from django.apps import apps from django.db import models -from django import forms class Version(): model: models.Model - form: forms.ModelForm @classproperty def latest(cls): @@ -32,5 +29,3 @@ class Version(): def __init__(self, version: int): module = import_module(f"{__name__}.v{version}") self.model = getattr(module, "Configuration") - - self.form = getattr(module, "Form") diff --git a/panel/src/panel/configuration/v1.py b/panel/src/panel/configuration/v1.py index 15f2bbb..f15fc43 100644 --- a/panel/src/panel/configuration/v1.py +++ b/panel/src/panel/configuration/v1.py @@ -1,8 +1,5 @@ -from django import forms -from django.db import models from pydantic import BaseModel, Field from enum import Enum -from django_pydantic_field import SchemaField class Configuration(BaseModel): enable: bool = Field( @@ -20,25 +17,3 @@ class Configuration(BaseModel): default=Domain.EU, description="DNS domain where to expose services" ) - -# TODO@(fricklerhandwerk): -# generate this automatically from the Pydantic model so this code can go away: -# - add custom types, splicing `forms.Form` into `pydantic.BaseModel` and `forms.Field` into `pydantic.Field` so we can attach Django validators to Pydantic models -# - map primitive or well-known field types as captured by `pydantic.Field` to `forms.Field` constructors, and `BaseModel` to `Form` using `BaseModel.model_fields` -# - use a custom widget that renders nested forms in e.g. a `<div>` -# - likely this also needs overriding `as_p()`, `as_li()` -# more inspiration: https://levelup.gitconnected.com/how-to-export-pydantic-models-as-django-forms-c1b59ddca580 -# that work goes through the JSON Schema generated by Pydantic, which seems unnecessary to me, but it follows the same princple -# TODO(@fricklerhandwerk): -# eventually we probably want to validate each field separately, -# so we should also auto-generate views per field that will be called by htmx directives defined in the templates. -# those htmx parts can be generated by each form field using `attrs` -class Form(forms.Form): - enable = forms.BooleanField(required=False) - domain = forms.ChoiceField(choices=[(d.name, d.value) for d in Configuration.Domain]) - - def to_python(self): - return Configuration( - enable=self.cleaned_data['enable'], - domain=Configuration.Domain[self.cleaned_data['domain']] - ) diff --git a/panel/src/panel/templates/base.html b/panel/src/panel/templates/base.html index 913b19f..aa29745 100644 --- a/panel/src/panel/templates/base.html +++ b/panel/src/panel/templates/base.html @@ -26,9 +26,6 @@ <li> <a href="{% url 'service_list' %}">Services</a> </li> - <li> - <a href="{% url 'configuration_form' %}">Configuration</a> - </li> {% load custom_tags %} <li> diff --git a/panel/src/panel/templates/configuration_form.html b/panel/src/panel/templates/configuration_form.html deleted file mode 100644 index d5fad4a..0000000 --- a/panel/src/panel/templates/configuration_form.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "base.html" %} -{% block content %} -<form method="post" enctype="multipart/form-data" action="{% url 'configuration_form' %}"> - {% csrf_token %} - - {{ form.as_p }} - - <button class="button" disabled>Deploy</button> - <button class="button" type="submit" >Save</button> -</form> - -<p><sub>Configuration schema version {{ version }}</sub></p> -{% endblock %} diff --git a/panel/src/panel/urls.py b/panel/src/panel/urls.py index 2f0ba43..46c765e 100644 --- a/panel/src/panel/urls.py +++ b/panel/src/panel/urls.py @@ -25,5 +25,4 @@ urlpatterns = [ path("", include("django.contrib.auth.urls")), path("account/", views.AccountDetail.as_view(), name='account_detail'), path("services/", views.ServiceList.as_view(), name='service_list'), - path("configuration/", views.ConfigurationForm.as_view(), name='configuration_form'), ] diff --git a/panel/src/panel/views.py b/panel/src/panel/views.py index 7a356fe..1765696 100644 --- a/panel/src/panel/views.py +++ b/panel/src/panel/views.py @@ -1,13 +1,7 @@ -from enum import Enum - -from django.urls import reverse_lazy from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.models import User -from django.views.generic import TemplateView, DetailView -from django.views.generic.edit import FormView - -from panel import models -from panel.configuration import Version +from django.views.generic import TemplateView +from django.views.generic import DetailView class Index(TemplateView): template_name = 'index.html' @@ -20,69 +14,3 @@ class AccountDetail(LoginRequiredMixin, DetailView): class ServiceList(TemplateView): template_name = 'service_list.html' - -class ConfigurationForm(LoginRequiredMixin, FormView): - template_name = 'configuration_form.html' - success_url = reverse_lazy('configuration_form') - - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) - context["version"] = self.get_object().version - return context - - def get_form_class(self): - config = self.get_object() - return Version(config.version).form - - def get_object(self): - """Get or create the configuration object for the current user""" - obj, created = models.Configuration.objects.get_or_create( - operator=self.request.user) - return obj - - # TODO(@fricklerhandwerk): - # this should probably live somewhere else - def convert_enums_to_names(self, data_dict): - """ - Recursively convert all enum values in a dictionary to their string names. - This handles nested dictionaries and lists as well. - - Needed for converting a Pydantic `BaseModel` instance to a `Form` input. - """ - if isinstance(data_dict, dict): - result = {} - for key, value in data_dict.items(): - if isinstance(value, Enum): - # Convert Enum to its name - result[key] = value.name - elif isinstance(value, (dict, list)): - # Recursively process nested structures - result[key] = self.convert_enums_to_names(value) - else: - # Keep other values as is - result[key] = value - return result - elif isinstance(data_dict, list): - # Process each item in the list - return [self.convert_enums_to_names(item) for item in data_dict] - elif isinstance(data_dict, Enum): - # Convert single Enum value - return data_dict.name - else: - # Return non-dict, non-list, non-Enum values as is - return data_dict - - def get_initial(self): - initial = super().get_initial() - config = self.get_object() - config_dict = config.parsed_value.model_dump() - - initial.update(self.convert_enums_to_names(config_dict)) - return initial - - def form_valid(self, form): - obj = self.get_object() - obj.value = form.to_python().model_dump_json() - obj.save() - - return super().form_valid(form)