Skip to content

Commit e4df3bc

Browse files
authored
feat: django-constance (#1441)
1 parent 2e2f25f commit e4df3bc

File tree

11 files changed

+234
-3
lines changed

11 files changed

+234
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ Unfold Studio lets you visually customize your Django admin without writing code
3535

3636
## Fresh Features & Enhancements
3737

38+
- **django-constance**: Official support with a completely new design and UX improvements
3839
- **Paginated inlines:** Break down large record sets into pages within inlines for better admin performance
3940
- **Conditional fields:** Show or hide fields dynamically based on the values of other fields in the form
4041
- **Infinite paginator:** Efficiently handle large datasets with seamless pagination that reduces server load
4142
- **Checkbox & radio filters:** Enhanced filter options with checkbox and radio interfaces for intuitive filtering
42-
- **Site dropdown:** Configurable dropdown menu in the header area for managing custom navigation links
4343

4444
## Core Features & Capabilities
4545

docs/installation/quickstart.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ INSTALLED_APPS = [
1919
"unfold.contrib.import_export", # optional, if django-import-export package is used
2020
"unfold.contrib.guardian", # optional, if django-guardian package is used
2121
"unfold.contrib.simple_history", # optional, if django-simple-history package is used
22+
"unfold.contrib.location_field", # optional, if django-location-field package is used
23+
"unfold.contrib.constance", # optional, if django-constance package is used
2224
"django.contrib.admin", # required
2325
]
2426
```
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: django-constance
3+
order: 0
4+
description: Integrate django-constance with Unfold admin interface to manage dynamic Django settings with a beautiful UI and enhanced form widgets
5+
---
6+
7+
# django-constance
8+
9+
To get started, follow the installation instructions for django-constance from their official documentation at https://django-constance.readthedocs.io/en/latest/.
10+
11+
After installing django-constance, add `unfold.contrib.constance` to your `INSTALLED_APPS` setting. Make sure to place it before `constance` in the list to ensure the proper templates are loaded correctly.
12+
13+
14+
```python
15+
# admin.py
16+
17+
from django.contrib import admin
18+
from constance.admin import Config, ConstanceAdmin
19+
20+
21+
@admin.register(Config)
22+
class ConstanceConfigAdmin(ConstanceAdmin):
23+
pass
24+
```
25+
26+
Unfold comes with a pre-configured set of supported field types and their corresponding widgets. To use them, configure your `CONSTANCE_ADDITIONAL_FIELDS` setting as demonstrated in the example below. Additionally, `UNFOLD_CONSTANCE_ADDITIONAL_FIELDS` provides extra field types like `image_field` and `file_field` to enhance your form capabilities.
27+
28+
```python
29+
# settings.py
30+
31+
from unfold.contrib.constance.settings import UNFOLD_CONSTANCE_ADDITIONAL_FIELDS
32+
33+
34+
CONSTANCE_ADDITIONAL_FIELDS = {
35+
**UNFOLD_CONSTANCE_ADDITIONAL_FIELDS,
36+
37+
# Example field configuration for select with choices. Not needed.
38+
"choice_field": [
39+
"django.forms.fields.ChoiceField",
40+
{
41+
"widget": "unfold.widgets.UnfoldAdminSelectWidget",
42+
"choices": (
43+
("light-blue", "Light blue"),
44+
("dark-blue", "Dark blue"),
45+
),
46+
},
47+
],
48+
}
49+
```

src/unfold/contrib/constance/__init__.py

Whitespace-only changes.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class ConstanceConfig(AppConfig):
5+
name = "unfold.contrib.constance"
6+
label = "unfold_constance"
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
UNFOLD_CONSTANCE_ADDITIONAL_FIELDS = {
2+
str: [
3+
"django.forms.CharField",
4+
{
5+
"widget": "unfold.widgets.UnfoldAdminTextInputWidget",
6+
},
7+
],
8+
int: [
9+
"django.forms.IntegerField",
10+
{
11+
"widget": "unfold.widgets.UnfoldAdminIntegerFieldWidget",
12+
},
13+
],
14+
bool: [
15+
"django.forms.BooleanField",
16+
{
17+
"widget": "unfold.widgets.UnfoldBooleanSwitchWidget",
18+
},
19+
],
20+
"file_field": [
21+
"django.forms.fields.FileField",
22+
{
23+
"widget": "unfold.widgets.UnfoldAdminFileFieldWidget",
24+
},
25+
],
26+
"image_field": [
27+
"django.forms.fields.ImageField",
28+
{
29+
"widget": "unfold.widgets.UnfoldAdminImageFieldWidget",
30+
},
31+
],
32+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{% extends "admin/base_site.html" %}
2+
3+
{% load admin_list static i18n %}
4+
5+
{% block extrahead %}
6+
{% url 'admin:jsi18n' as jsi18nurl %}
7+
<script type="text/javascript" src="{{ jsi18nurl|default:'../../jsi18n/' }}"></script>
8+
{{ block.super }}
9+
{{ media.js }}
10+
<script type="text/javascript" src="{% static 'admin/js/constance.js' %}"></script>
11+
{% endblock %}
12+
13+
{% block breadcrumbs %}
14+
<div class="px-4">
15+
<div class="container mb-6 mx-auto -my-3 lg:mb-12">
16+
<ul class="flex flex-wrap">
17+
{% url 'admin:index' as link %}
18+
{% trans 'Home' as name %}
19+
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=name %}
20+
21+
{% url 'admin:app_list' app_label=opts.app_label as link %}
22+
{% include 'unfold/helpers/breadcrumb_item.html' with link=link name=opts.app_config.verbose_name %}
23+
24+
{% include 'unfold/helpers/breadcrumb_item.html' with link='' name=opts.verbose_name_plural|capfirst %}
25+
</ul>
26+
</div>
27+
</div>
28+
{% endblock %}
29+
30+
31+
{% block content %}
32+
<div id="content-main" class="constance">
33+
<div id="changelist" class="flex flex-col gap-8 w-full">
34+
<form id="changelist-form" action="" method="post" enctype="multipart/form-data" novalidate class="flex flex-col gap-8 w-full">
35+
{% csrf_token %}
36+
37+
{% include "unfold/helpers/form_errors.html" with errors=form.non_field_errors %}
38+
39+
{% for field in form.hidden_fields %}
40+
{{ field }}
41+
{% endfor %}
42+
43+
{% if fieldsets %}
44+
<div class="border border-base-200 rounded-default overflow-x-auto simplebar-horizontal-scrollbar-top dark:border-base-800" data-simplebar data-simplebar-auto-hide="false">
45+
<table class="w-full border-collapse">
46+
{% for fieldset in fieldsets %}
47+
{% with config_values=fieldset.config_values %}
48+
{% include "admin/constance/includes/results_list.html" %}
49+
{% endwith %}
50+
{% endfor %}
51+
52+
<tfoot>
53+
<tr>
54+
<td class="border-t border-base-200 px-3 py-2 dark:border-base-800" colspan="100%">
55+
<div class="flex justify-end">
56+
{% trans "Save" as title %}
57+
{% include "unfold/helpers/submit.html" with title=title %}
58+
</div>
59+
</td>
60+
</tr>
61+
</tfoot>
62+
</table>
63+
</div>
64+
{% else %}
65+
{% include "admin/constance/includes/results_list.html" %}
66+
{% endif %}
67+
</form>
68+
</div>
69+
</div>
70+
{% endblock %}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
{% load admin_list static i18n %}
2+
3+
<tbody {% if fieldset.collapse %} x-data="{ rowsOpen: false }" {% endif %}>
4+
<tr {% if fieldset.collapse %} x-on:click="rowsOpen = !rowsOpen" {% endif %} class="{% if fieldset.collapse %}cursor-pointer{% endif %}">
5+
<th class="bg-base-50 border-t border-base-200 font-semibold px-3 py-2 text-left text-font-important-light dark:text-font-important-dark dark:border-base-800 dark:bg-white/[.04] {% if forloop.first %}border-t-0{% endif %}" colspan="100%">
6+
{{ fieldset.title }}
7+
8+
{% if fieldset.collapse %}
9+
<span class="material-symbols-outlined float-right select-none transition-all" title="{% trans "Collapse" %}" x-bind:class="rowsOpen ? 'rotate-180' : ''">
10+
expand_more
11+
</span>
12+
{% endif %}
13+
</th>
14+
</tr>
15+
16+
<tr class="border-t border-base-200 dark:border-base-800 *:font-semibold *:px-3 *:py-2 *:text-left *:text-font-important-light dark:*:text-font-important-dark" {% if fieldset.collapse %}x-show="rowsOpen"{% endif %}>
17+
<th>{% trans "Name" %}</th>
18+
<th>{% trans "Value" %}</th>
19+
<th>{% trans "Code" %}</th>
20+
<th>{% trans "Default" %}</th>
21+
<th>{% trans "Modified" %}</th>
22+
<th></th>
23+
</tr>
24+
25+
{% for item in config_values %}
26+
<tr class="border-t border-base-200 h-[55px] *:px-3 *:py-2 *:align-middle dark:border-base-800" {% if fieldset.collapse %}x-show="rowsOpen"{% endif %}>
27+
<th class="font-normal text-left">
28+
{{ item.help_text|linebreaksbr }}
29+
</th>
30+
31+
<td class="{% if item.form_field.errors %}group errors{% endif %}">
32+
{{ item.form_field }}
33+
34+
{% include "unfold/helpers/form_errors.html" with errors=item.form_field.errors %}
35+
</td>
36+
37+
38+
<td>
39+
<a class="item-name item-anchor" href="#{{ item.name|slugify }}" id="{{ item.name|slugify }}" title="Link to this setting">
40+
{% include "unfold/helpers/label.html" with text=item.name type="info" %}
41+
</a>
42+
</td>
43+
44+
<td>
45+
{% if item.default %}
46+
{% include "unfold/helpers/label.html" with text=item.default %}
47+
{% else %}
48+
-
49+
{% endif %}
50+
</td>
51+
52+
<td>
53+
{% include "unfold/helpers/boolean.html" with value=item.modified %}
54+
</td>
55+
56+
<td class="w-px">
57+
{% if not item.is_file %}
58+
<a href="#"
59+
class="flex items-center gap-1 reset-link whitespace-nowrap"
60+
data-default="{% spaceless %}{% if item.is_checkbox %}{% if item.raw_default %} true {% else %} false {% endif %}{% elif item.is_date %}{{ item.raw_default|date:"U" }}{% elif item.is_datetime %}{{ item.raw_default|date:"U" }}{% else %}{{ item.default }}{% endif %}{% endspaceless %}"
61+
data-field-type="{% spaceless %}{% if item.is_checkbox %}checkbox{% elif item.is_datetime %}datetime{% elif item.is_date %}date{% endif %}{% endspaceless %}"
62+
data-field-id="{{ item.form_field.auto_id }}">
63+
<span class="material-symbols-outlined text-base-400 hover:text-base-700 dark:border-base-700 dark:text-base-500 dark:hover:text-base-200" title="{% trans "Reset to default" %}">
64+
refresh
65+
</span>
66+
</a>
67+
{% endif %}
68+
</td>
69+
</tr>
70+
{% endfor %}
71+
</tbody>

src/unfold/static/unfold/css/styles.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
<button type="submit" {% if name %}name="{{ name}}"{% endif %} class="bg-primary-600 block border border-transparent font-medium px-3 py-2 rounded-default self-end text-sm text-white">
1+
<button type="submit" {% if name %}name="{{ name}}"{% endif %} class="bg-primary-600 block border border-transparent cursor-pointer font-medium px-3 py-2 rounded-default self-end text-sm text-white">
22
{{ title }}
33
</button>

0 commit comments

Comments
 (0)