From 9e065f37c24d4d47afa47b29d9eb73e4a3917445 Mon Sep 17 00:00:00 2001 From: Jonas Braathen Date: Wed, 10 Jun 2026 00:40:17 +0200 Subject: [PATCH] Add button for bumping serial --- mdb/admin.py | 18 ++++++++++++++---- mdb/forms.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/mdb/admin.py b/mdb/admin.py index f0cc39d..b4ae848 100644 --- a/mdb/admin.py +++ b/mdb/admin.py @@ -6,7 +6,7 @@ from django.db import models from django.db.models import Count from django.forms import NumberInput -from mdb.forms import InterfaceForm +from mdb.forms import InterfaceForm, SerialNumberInput from mdb.models import ( DhcpConfig, DhcpCustomField, @@ -32,6 +32,16 @@ from mdb.models import ( admin.site.site_header = settings.ADMIN_SITE_NAME +class SerialFieldAdminMixin: + """Render the ``domain_serial`` field with the wide serial widget + button.""" + + def formfield_for_dbfield(self, db_field, request, **kwargs): + formfield = super().formfield_for_dbfield(db_field, request, **kwargs) + if db_field.name == "domain_serial": + formfield.widget = SerialNumberInput() + return formfield + + class Ip6AddressInline(admin.TabularInline): model = Ip6Address extra = 0 @@ -169,7 +179,7 @@ class DhcpCustomFieldInline(admin.TabularInline): extra = 0 -class Ip4SubnetAdmin(admin.ModelAdmin): +class Ip4SubnetAdmin(SerialFieldAdminMixin, admin.ModelAdmin): list_display = [ "name", "network", @@ -209,7 +219,7 @@ class Ip4SubnetAdmin(admin.ModelAdmin): return super(Ip4SubnetAdmin, self).get_queryset(request) -class Ip6SubnetAdmin(admin.ModelAdmin): +class Ip6SubnetAdmin(SerialFieldAdminMixin, admin.ModelAdmin): list_display = [ "name", "network", @@ -266,7 +276,7 @@ class DomainAAAARecordInline(admin.TabularInline): extra = 0 -class DomainAdmin(admin.ModelAdmin): +class DomainAdmin(SerialFieldAdminMixin, admin.ModelAdmin): inlines = [ DomainSrvRecordInline, DomainTxtRecordInline, diff --git a/mdb/forms.py b/mdb/forms.py index 23843b6..b4b9333 100644 --- a/mdb/forms.py +++ b/mdb/forms.py @@ -1,10 +1,55 @@ from django import forms from django.core.exceptions import ValidationError -from django.forms import ModelChoiceField +from django.forms import ModelChoiceField, NumberInput +from django.utils.safestring import mark_safe from mdb.models import Interface, Ip4Address +class SerialNumberInput(NumberInput): + """Number input for DNS SOA serials (YYYYMMDDXX). + + Renders wide enough to show the full 10-digit serial and adds a button + that prefills the field with today's date plus the next available XX + counter (incrementing if the field already holds today's serial). + """ + + def __init__(self, attrs=None): + default_attrs = {"style": "width: 12em"} + if attrs: + default_attrs.update(attrs) + super().__init__(default_attrs) + + def render(self, name, value, attrs=None, renderer=None): + field = super().render(name, value, attrs, renderer) + field_id = (attrs or {}).get("id", "id_%s" % name) + extra = """ + + +""".replace( + "__ID__", field_id + ) + return mark_safe(field + extra) + + class Ip4ModelChoiceField(ModelChoiceField): def label_from_instance(self, obj): if not hasattr(obj, "interface"):