feat(config): implement field customization in settings.toml

MK/conditional_fields
mariusrklein 4 months ago
parent f58a7dc4b6
commit c7d1a16cb3

@ -8,8 +8,10 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.urls import path, reverse from django.urls import path, reverse
from django.db import models from django.db import models
from django.contrib.admin import helpers, widgets from django.contrib.admin import helpers, widgets
from django.conf import settings
import rules.contrib.admin import rules.contrib.admin
from rules.permissions import perm_exists from rules.permissions import perm_exists
from utils import OrderedSet
class FieldPermissionsAdminMixin: class FieldPermissionsAdminMixin:
@ -174,6 +176,62 @@ class CommonAdminMixin(FieldPermissionsAdminMixin, ChangeViewAdminMixin, Filtere
# For any other type of field, just call its formfield() method. # For any other type of field, just call its formfield() method.
return db_field.formfield(**kwargs) return db_field.formfield(**kwargs)
@property
def field_key(self):
return f"{self.model._meta.app_label}_{self.model.__name__}".lower()
def get_excluded_fields(self):
return OrderedSet(settings.CUSTOM_MODEL_FIELDS.get(self.field_key, {}).get('exclude', []))
def get_included_fields(self):
return OrderedSet(settings.CUSTOM_MODEL_FIELDS.get(self.field_key, {}).get('fields', []))
def get_fieldsets(self, request, obj=None):
included = self.get_included_fields()
excluded = self.get_excluded_fields()
original_fieldsets = super().get_fieldsets(request, obj)
if original_fieldsets:
print(f"get_fieldsets called for {self.field_key}")
print(f"Original fieldsets: {original_fieldsets}")
new_fieldsets = []
for title, attrs in original_fieldsets:
fields = attrs.get("fields", [])
# Flatten groupings like tuples if needed
filtered_fields = [
f for f in fields
if (
(not included or f in included)
and f not in excluded
)
]
if filtered_fields:
new_fieldsets.append((title, dict(attrs, **{"fields": filtered_fields})))
if new_fieldsets:
print(f"Filtered fieldsets: {new_fieldsets}")
return new_fieldsets
def get_fields(self, request, obj=None):
fields = OrderedSet(super().get_fields(request, obj) or [])
custom_fields = self.get_included_fields() - self.get_excluded_fields()
if custom_fields:
print(f"get_fields called for {self.field_key}, fields: {fields}, custom_fields: {custom_fields}")
return list(custom_fields)
return list(fields)
def get_exclude(self, request, obj=None):
excluded = OrderedSet(super().get_exclude(request, obj) or [])
custom_excluded = self.get_excluded_fields() - self.get_included_fields()
if custom_excluded:
print(f"get_exclude called for {self.field_key}, excluded: {excluded}, custom_excluded: {custom_excluded}")
return list(excluded | custom_excluded)
return list(excluded)
class CommonAdminInlineMixin(CommonAdminMixin): class CommonAdminInlineMixin(CommonAdminMixin):

@ -76,3 +76,8 @@ REPORTS_SECTION = get_var('startpage', 'reports_section', default='reports')
# testing # testing
TEST_MAIL = get_var('testing', 'mail', default='test@localhost') TEST_MAIL = get_var('testing', 'mail', default='test@localhost')
# excluded and included model fields in admin and admin forms
CUSTOM_MODELS = list(get_var('custom_model_fields', default={}).keys())
CUSTOM_MODEL_FIELDS = {model.lower(): get_var('model_fields', model, default=[]) for model in CUSTOM_MODELS}

@ -5,6 +5,7 @@ from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from decimal import Decimal, ROUND_HALF_DOWN from decimal import Decimal, ROUND_HALF_DOWN
import unicodedata import unicodedata
from collections import OrderedDict
def file_size_validator(max_upload_size): def file_size_validator(max_upload_size):
@ -88,3 +89,28 @@ def coming_midnight():
return timezone.datetime(year=base.year, month=base.month, day=base.day, return timezone.datetime(year=base.year, month=base.month, day=base.day,
hour=0, minute=0, second=0, microsecond=0, hour=0, minute=0, second=0, microsecond=0,
tzinfo=base.tzinfo) tzinfo=base.tzinfo)
class OrderedSet(OrderedDict):
def __init__(self, iterable=None):
super().__init__()
if iterable:
for item in iterable:
self[item] = None
def __sub__(self, other):
if not isinstance(other, OrderedSet):
return NotImplemented
return OrderedSet(k for k in self if k not in other)
def add(self, item):
self[item] = None
def discard(self, item):
self.pop(item, None)
def __contains__(self, item):
return item in self.keys()
def __iter__(self):
return iter(self.keys())
Loading…
Cancel
Save