Skip to content

Instantly share code, notes, and snippets.

@kluchrj
Created July 1, 2025 21:15
Show Gist options
  • Select an option

  • Save kluchrj/5e4d018c792cc6a4031a1db262704b0c to your computer and use it in GitHub Desktop.

Select an option

Save kluchrj/5e4d018c792cc6a4031a1db262704b0c to your computer and use it in GitHub Desktop.
Django Unfold - Constance Admin Page
from datetime import date
from datetime import datetime
from datetime import time
from datetime import timedelta
from decimal import Decimal
from django.contrib import admin
from django.forms import fields
from unfold import widgets
from constance import settings, forms as constance_forms
from constance.admin import ConstanceAdmin, Config
NUMERIC_WIDGET = widgets.UnfoldAdminTextInputWidget(attrs={'size': 10})
INTEGER_LIKE = (fields.IntegerField, {'widget': NUMERIC_WIDGET})
STRING_LIKE = (
fields.CharField,
{
'widget': widgets.UnfoldAdminTextareaWidget(attrs={'rows': 3}),
'required': False,
},
)
FIELDS = {
bool: (fields.BooleanField, {'required': False, 'widget': widgets.UnfoldBooleanSwitchWidget}),
int: INTEGER_LIKE,
Decimal: (fields.DecimalField, {'widget': NUMERIC_WIDGET}),
str: STRING_LIKE,
datetime: (fields.SplitDateTimeField, {'widget': widgets.UnfoldAdminSplitDateTimeWidget}),
timedelta: (fields.DurationField, {'widget': widgets.UnfoldAdminTextInputWidget}),
date: (fields.DateField, {'widget': widgets.UnfoldAdminDateWidget}),
time: (fields.TimeField, {'widget': widgets.UnfoldAdminTimeWidget}),
float: (fields.FloatField, {'widget': NUMERIC_WIDGET}),
}
# Don't call parse_additional_fields again - constance calls it before us.
FIELDS.update(settings.ADDITIONAL_FIELDS)
# Monkey patch constance module to use our custom fields.
constance_forms.FIELDS = FIELDS
class UnfoldConstanceForm(constance_forms.ConstanceForm):
pass
if admin.site.is_registered(ConstanceAdmin):
admin.site.unregister(ConstanceAdmin)
if admin.site.is_registered(Config):
admin.site.unregister([Config])
class CustomConstanceAdmin(ConstanceAdmin):
change_list_template = 'unfold/constance/index.html'
change_list_form = UnfoldConstanceForm
admin.site.register([Config], CustomConstanceAdmin)
{% extends 'unfold/layouts/skeleton.html' %}
{% load unfold i18n admin_urls %}
{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
{% include "unfold/helpers/site_branding.html" %}
{% endblock %}
{% block base %}
<div id="page" class="flex min-h-screen">
{% if not is_popup and is_nav_sidebar_enabled %}
{% block nav-sidebar %}
{% include "admin/nav_sidebar.html" %}
{% endblock %}
{% endif %}
<div id="main" class="bg-white flex flex-col grow min-w-0 dark:bg-base-900 {% element_classes 'main' %}">
{% block content_before %}
{% include "unfold/helpers/header.html" %}
{% endblock %}
{% if not is_popup %}
{% spaceless %}
{% block breadcrumbs %}{% endblock %}
{% endspaceless %}
{% endif %}
{% block messages %}
<div class="{% if not cl.model_admin.list_fullwidth %}container{% endif %} mx-auto">
{% include "unfold/helpers/messages.html" %}
</div>
{% endblock messages %}
{% block content %}
<div id="content-main" class="constance">
<div class="module" id="changelist">
<form id="changelist-form" action="" method="post" enctype="multipart/form-data">{% csrf_token %}
<div class="px-4 pb-4">
<div class="container mx-auto {% block coltype %}colM{% endblock %}">
{% if form.non_field_errors %}
<ul class="errorlist">
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% if form.errors %}
<ul class="errorlist">
{% endif %}
{% for field in form.hidden_fields %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
{{ field }}
{% endfor %}
{% if form.errors %}
</ul>
{% endif %}
{% if fieldsets %}
{% for fieldset in fieldsets %}
<fieldset class="module relative {% if fieldset.classes %} {{ fieldset.classes }}{% endif %}" {% if stacked != 1 %}x-show="activeTab == 'general'"{% endif %}>
{% if fieldset.title %}
<h2 class="bg-base-100 font-semibold mb-6 px-4 py-3 rounded-default text-font-important-light text-sm 2xl:-mx-4 dark:bg-white/[.02] dark:text-font-important-dark {% if fieldset.is_collapsible %}cursor-pointer{% endif %}">
{{ fieldset.title }}
</h2>
{% endif %}
{% if fieldset.description %}
<div class="leading-relaxed mb-4 max-w-4xl text-sm">
{{ fieldset.description|safe }}
</div>
{% endif %}
<div class="{% fieldset_rows_classes %}">
{% with config_values=fieldset.config_values %}
{% include "unfold/constance/results_list.html" %}
{% endwith %}
</div>
</fieldset>
{% endfor %}
{% else %}
{% include "unfold/constance/results_list.html" %}
{% endif %}
</div>
</div>
{% include "unfold/constance/submit_line.html" with is_popup=False %}
</form>
</div>
</div>
{% endblock %}
{% block sidebar %}{% endblock %}
{% block footer %}{% endblock %}
</div>
</div>
{% endblock base %}
{% load unfold static i18n %}
<div id="results" class="w-full">
<div class="shadow-xs aligned rounded-default">
<table class="w-full border-collapse text-sm" style="table-layout: fixed">
<thead class="bg-muted text-muted-foreground uppercase tracking-wider text-xs border-b dark:border-base-800 border-base-200">
<tr>
<th class="px-4 py-3 font-semibold text-left">{% trans "Name" %}</th>
<th class="px-4 py-3 font-semibold text-left">{% trans "Default" %}</th>
<th class="px-4 py-3 font-semibold text-left">{% trans "Value" %}</th>
<th class="px-4 py-3 font-semibold text-center whitespace-nowrap">{% trans "Is modified" %}</th>
</tr>
</thead>
<tbody>
{% for item in config_values %}
<tr class="bg-base hover:bg-muted border-b dark:border-base-800 border-base-200 transition">
<!-- Name -->
<td class="px-4 py-4 align-middle" style="width: 20rem">
<div class="flex flex-col gap-1">
<span id="{{ item.name|slugify }}" class="text-sm font-bold uppercase tracking-tight">
{{ item.name }}
<a href="#{{ item.name|slugify }}"
title="{% trans 'Link to this setting' %}"
class="ml-1 text-muted-foreground hover:text-foreground">¶</a>
</span>
{% if item.help_text %}
<p class="text-xs text-muted leading-snug">{{ item.help_text|linebreaksbr }}</p>
{% endif %}
</div>
</td>
<!-- Default -->
<td class="px-4 py-4 text-muted whitespace-pre-wrap align-middle">
{{ item.default }}
</td>
<!-- Field -->
<td class="px-4 py-4 align-middle">
{% if item.form_field.errors %}
<div class="text-sm text-destructive text-red-600 dark:text-red-500 mb-1">{{ item.form_field.errors }}</div>
{% endif %}
<div class="mt-1">
{{ item.form_field }}
</div>
</td>
<!-- Is Modified -->
<td class="px-4 py-4 text-center align-middle whitespace-nowrap">
{% if item.modified %}
<img src="{% static 'admin/img/icon-yes.'|add:icon_type %}" alt="✔" class="inline h-5 w-5" />
{% else %}
<img src="{% static 'admin/img/icon-no.'|add:icon_type %}" alt="✖" class="inline h-5 w-5" />
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% load i18n %}
<div id="submit-row" class="relative lg:sticky lg:bottom-0 z-40">
<div class="backdrop-blur-xs bg-white/80 rounded-b-default pb-4 px-4 dark:bg-base-900/80 lg:border-t lg:border-base-200 relative lg:scrollable-top lg:py-0 dark:border-base-800">
<div class="flex flex-col-reverse gap-3 items-center mx-auto lg:flex-row-reverse container lg:h-[64px]">
<button type="submit"
class="bg-primary-600 block border border-transparent cursor-pointer font-medium px-3 py-2 rounded-default text-white w-full lg:w-auto">
{% trans 'Save' %}
</button>
</div>
</div>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment