2017-11-06 16:31:00 +00:00
|
|
|
from collections import OrderedDict
|
2024-07-03 14:21:33 +00:00
|
|
|
from datetime import date
|
|
|
|
|
from datetime import datetime
|
2010-08-23 15:23:38 +00:00
|
|
|
from operator import itemgetter
|
2010-08-23 14:18:44 +00:00
|
|
|
|
2024-07-03 14:21:33 +00:00
|
|
|
from django import forms
|
|
|
|
|
from django import get_version
|
2016-11-17 07:42:55 +00:00
|
|
|
from django.apps import apps
|
2024-07-03 14:21:33 +00:00
|
|
|
from django.contrib import admin
|
|
|
|
|
from django.contrib import messages
|
2010-11-10 03:07:53 +00:00
|
|
|
from django.contrib.admin.options import csrf_protect_m
|
2023-04-07 13:16:39 +00:00
|
|
|
from django.core.exceptions import PermissionDenied
|
2010-11-10 03:07:53 +00:00
|
|
|
from django.http import HttpResponseRedirect
|
2015-09-24 09:56:19 +00:00
|
|
|
from django.template.response import TemplateResponse
|
2023-04-07 13:16:39 +00:00
|
|
|
from django.urls import path
|
2010-11-10 03:07:53 +00:00
|
|
|
from django.utils.formats import localize
|
2020-11-18 16:14:05 +00:00
|
|
|
from django.utils.translation import gettext_lazy as _
|
2013-05-23 09:32:10 +00:00
|
|
|
|
2024-07-03 14:21:33 +00:00
|
|
|
from . import LazyConfig
|
|
|
|
|
from . import settings
|
2023-04-07 13:16:39 +00:00
|
|
|
from .forms import ConstanceForm
|
|
|
|
|
from .utils import get_values
|
2017-11-06 16:31:00 +00:00
|
|
|
|
2015-01-06 11:24:58 +00:00
|
|
|
config = LazyConfig()
|
2010-08-23 12:49:54 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class ConstanceAdmin(admin.ModelAdmin):
|
2025-10-07 09:25:07 +00:00
|
|
|
change_list_template = "admin/constance/change_list.html"
|
2016-02-22 13:50:41 +00:00
|
|
|
change_list_form = ConstanceForm
|
2010-08-23 12:49:54 +00:00
|
|
|
|
2021-01-13 19:45:37 +00:00
|
|
|
def __init__(self, model, admin_site):
|
|
|
|
|
model._meta.concrete_model = Config
|
|
|
|
|
super().__init__(model, admin_site)
|
|
|
|
|
|
2010-11-10 03:10:49 +00:00
|
|
|
def get_urls(self):
|
2025-10-07 09:25:07 +00:00
|
|
|
info = f"{self.model._meta.app_label}_{self.model._meta.module_name}"
|
2015-08-25 11:54:11 +00:00
|
|
|
return [
|
2025-10-07 09:25:07 +00:00
|
|
|
path("", self.admin_site.admin_view(self.changelist_view), name=f"{info}_changelist"),
|
|
|
|
|
path("", self.admin_site.admin_view(self.changelist_view), name=f"{info}_add"),
|
2015-08-25 11:54:11 +00:00
|
|
|
]
|
2010-08-23 12:49:54 +00:00
|
|
|
|
2016-08-21 21:45:57 +00:00
|
|
|
def get_config_value(self, name, options, form, initial):
|
|
|
|
|
default, help_text = options[0], options[1]
|
2022-02-12 01:49:08 +00:00
|
|
|
field_type = None
|
|
|
|
|
if len(options) == 3:
|
|
|
|
|
field_type = options[2]
|
2016-08-21 21:45:57 +00:00
|
|
|
# First try to load the value from the actual backend
|
|
|
|
|
value = initial.get(name)
|
|
|
|
|
# Then if the returned value is None, get the default
|
|
|
|
|
if value is None:
|
|
|
|
|
value = getattr(config, name)
|
2022-02-12 01:49:08 +00:00
|
|
|
|
|
|
|
|
form_field = form[name]
|
2016-08-21 21:45:57 +00:00
|
|
|
config_value = {
|
2025-10-07 09:25:07 +00:00
|
|
|
"name": name,
|
|
|
|
|
"default": localize(default),
|
|
|
|
|
"raw_default": default,
|
|
|
|
|
"help_text": _(help_text),
|
|
|
|
|
"value": localize(value),
|
|
|
|
|
"modified": localize(value) != localize(default),
|
|
|
|
|
"form_field": form_field,
|
|
|
|
|
"is_date": isinstance(default, date),
|
|
|
|
|
"is_datetime": isinstance(default, datetime),
|
|
|
|
|
"is_checkbox": isinstance(form_field.field.widget, forms.CheckboxInput),
|
|
|
|
|
"is_file": isinstance(form_field.field.widget, forms.FileInput),
|
2016-08-21 21:45:57 +00:00
|
|
|
}
|
2022-02-12 01:49:08 +00:00
|
|
|
if field_type and field_type in settings.ADDITIONAL_FIELDS:
|
|
|
|
|
serialized_default = form[name].field.prepare_value(default)
|
2025-10-07 09:25:07 +00:00
|
|
|
config_value["default"] = serialized_default
|
|
|
|
|
config_value["raw_default"] = serialized_default
|
|
|
|
|
config_value["value"] = form[name].field.prepare_value(value)
|
2016-08-21 21:45:57 +00:00
|
|
|
|
|
|
|
|
return config_value
|
|
|
|
|
|
2017-02-14 00:21:51 +00:00
|
|
|
def get_changelist_form(self, request):
|
2024-07-05 14:38:26 +00:00
|
|
|
"""Returns a Form class for use in the changelist_view."""
|
2017-02-14 00:21:51 +00:00
|
|
|
# Defaults to self.change_list_form in order to preserve backward
|
|
|
|
|
# compatibility
|
|
|
|
|
return self.change_list_form
|
|
|
|
|
|
2010-11-10 03:10:49 +00:00
|
|
|
@csrf_protect_m
|
|
|
|
|
def changelist_view(self, request, extra_context=None):
|
2020-04-29 17:02:04 +00:00
|
|
|
if not self.has_view_or_change_permission(request):
|
2013-03-02 14:43:27 +00:00
|
|
|
raise PermissionDenied
|
2016-11-27 05:55:21 +00:00
|
|
|
initial = get_values()
|
2017-02-14 00:21:51 +00:00
|
|
|
form_cls = self.get_changelist_form(request)
|
2020-04-29 17:02:04 +00:00
|
|
|
form = form_cls(initial=initial, request=request)
|
2025-10-07 09:25:07 +00:00
|
|
|
if request.method == "POST" and request.user.has_perm("constance.change_config"):
|
2024-07-03 14:21:33 +00:00
|
|
|
form = form_cls(data=request.POST, files=request.FILES, initial=initial, request=request)
|
2010-08-23 14:40:01 +00:00
|
|
|
if form.is_valid():
|
|
|
|
|
form.save()
|
2025-10-07 09:25:07 +00:00
|
|
|
messages.add_message(request, messages.SUCCESS, _("Live settings updated successfully."))
|
|
|
|
|
return HttpResponseRedirect(".")
|
|
|
|
|
messages.add_message(request, messages.ERROR, _("Failed to update live settings."))
|
2025-10-07 15:16:51 +00:00
|
|
|
context = {
|
|
|
|
|
**self.admin_site.each_context(request),
|
|
|
|
|
**(extra_context or {}),
|
|
|
|
|
"config_values": [],
|
|
|
|
|
"title": self.model._meta.app_config.verbose_name,
|
|
|
|
|
"app_label": "constance",
|
|
|
|
|
"opts": self.model._meta,
|
|
|
|
|
"form": form,
|
|
|
|
|
"media": self.media + form.media,
|
|
|
|
|
"icon_type": "svg",
|
|
|
|
|
"django_version": get_version(),
|
|
|
|
|
}
|
2015-06-08 14:13:40 +00:00
|
|
|
for name, options in settings.CONFIG.items():
|
2025-10-07 09:25:07 +00:00
|
|
|
context["config_values"].append(self.get_config_value(name, options, form, initial))
|
2016-08-21 21:45:57 +00:00
|
|
|
|
|
|
|
|
if settings.CONFIG_FIELDSETS:
|
2022-07-13 15:01:25 +00:00
|
|
|
if isinstance(settings.CONFIG_FIELDSETS, dict):
|
|
|
|
|
fieldset_items = settings.CONFIG_FIELDSETS.items()
|
|
|
|
|
else:
|
|
|
|
|
fieldset_items = settings.CONFIG_FIELDSETS
|
|
|
|
|
|
2025-10-07 09:25:07 +00:00
|
|
|
context["fieldsets"] = []
|
2022-07-13 15:01:25 +00:00
|
|
|
for fieldset_title, fieldset_data in fieldset_items:
|
2024-07-05 14:38:26 +00:00
|
|
|
if isinstance(fieldset_data, dict):
|
2025-10-07 09:25:07 +00:00
|
|
|
fields_list = fieldset_data["fields"]
|
|
|
|
|
collapse = fieldset_data.get("collapse", False)
|
2020-03-16 16:33:19 +00:00
|
|
|
else:
|
|
|
|
|
fields_list = fieldset_data
|
|
|
|
|
collapse = False
|
|
|
|
|
|
2024-07-03 14:21:33 +00:00
|
|
|
absent_fields = [field for field in fields_list if field not in settings.CONFIG]
|
2024-07-05 14:38:26 +00:00
|
|
|
if any(absent_fields):
|
|
|
|
|
raise ValueError(
|
2025-10-07 09:25:07 +00:00
|
|
|
"CONSTANCE_CONFIG_FIELDSETS contains field(s) that does not exist(s): {}".format(
|
|
|
|
|
", ".join(absent_fields)
|
2024-07-05 14:38:26 +00:00
|
|
|
)
|
|
|
|
|
)
|
2018-10-11 17:18:39 +00:00
|
|
|
|
2016-08-21 21:45:57 +00:00
|
|
|
config_values = []
|
|
|
|
|
|
2017-06-02 08:52:16 +00:00
|
|
|
for name in fields_list:
|
|
|
|
|
options = settings.CONFIG.get(name)
|
|
|
|
|
if options:
|
2024-07-03 14:21:33 +00:00
|
|
|
config_values.append(self.get_config_value(name, options, form, initial))
|
2025-10-07 09:25:07 +00:00
|
|
|
fieldset_context = {"title": fieldset_title, "config_values": config_values}
|
2020-03-16 16:33:19 +00:00
|
|
|
|
|
|
|
|
if collapse:
|
2025-10-07 09:25:07 +00:00
|
|
|
fieldset_context["collapse"] = True
|
|
|
|
|
context["fieldsets"].append(fieldset_context)
|
2022-07-13 15:01:25 +00:00
|
|
|
if not isinstance(settings.CONFIG_FIELDSETS, (OrderedDict, tuple)):
|
2025-10-07 09:25:07 +00:00
|
|
|
context["fieldsets"].sort(key=itemgetter("title"))
|
2016-08-21 21:45:57 +00:00
|
|
|
|
2016-10-01 11:07:40 +00:00
|
|
|
if not isinstance(settings.CONFIG, OrderedDict):
|
2025-10-07 09:25:07 +00:00
|
|
|
context["config_values"].sort(key=itemgetter("name"))
|
2015-09-24 09:56:19 +00:00
|
|
|
request.current_app = self.admin_site.name
|
2016-09-14 16:52:58 +00:00
|
|
|
return TemplateResponse(request, self.change_list_template, context)
|
2010-08-23 12:49:54 +00:00
|
|
|
|
|
|
|
|
def has_add_permission(self, *args, **kwargs):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
def has_delete_permission(self, *args, **kwargs):
|
|
|
|
|
return False
|
|
|
|
|
|
2012-09-03 00:28:31 +00:00
|
|
|
def has_change_permission(self, request, obj=None):
|
|
|
|
|
if settings.SUPERUSER_ONLY:
|
|
|
|
|
return request.user.is_superuser
|
2019-12-23 21:20:41 +00:00
|
|
|
return super().has_change_permission(request, obj)
|
2010-08-23 12:49:54 +00:00
|
|
|
|
|
|
|
|
|
2019-12-23 21:20:41 +00:00
|
|
|
class Config:
|
|
|
|
|
class Meta:
|
2025-10-07 09:25:07 +00:00
|
|
|
app_label = "constance"
|
|
|
|
|
object_name = "Config"
|
2021-01-13 19:45:37 +00:00
|
|
|
concrete_model = None
|
2025-10-07 09:25:07 +00:00
|
|
|
model_name = module_name = "config"
|
|
|
|
|
verbose_name_plural = _("config")
|
2011-02-23 15:39:58 +00:00
|
|
|
abstract = False
|
2013-01-19 16:27:35 +00:00
|
|
|
swapped = False
|
2025-01-27 09:12:47 +00:00
|
|
|
is_composite_pk = False
|
2013-03-02 14:43:27 +00:00
|
|
|
|
2015-09-24 09:56:19 +00:00
|
|
|
def get_ordered_objects(self):
|
|
|
|
|
return False
|
|
|
|
|
|
2013-03-02 14:43:27 +00:00
|
|
|
def get_change_permission(self):
|
2025-10-07 09:25:07 +00:00
|
|
|
return f"change_{self.model_name}"
|
2016-11-17 07:42:55 +00:00
|
|
|
|
2016-10-27 16:27:37 +00:00
|
|
|
@property
|
|
|
|
|
def app_config(self):
|
2016-11-17 07:42:55 +00:00
|
|
|
return apps.get_app_config(self.app_label)
|
2013-03-02 14:43:27 +00:00
|
|
|
|
2018-03-06 10:16:44 +00:00
|
|
|
@property
|
|
|
|
|
def label(self):
|
2025-10-07 09:25:07 +00:00
|
|
|
return f"{self.app_label}.{self.object_name}"
|
2018-03-06 10:16:44 +00:00
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def label_lower(self):
|
2025-10-07 09:25:07 +00:00
|
|
|
return f"{self.app_label}.{self.model_name}"
|
2018-03-06 10:16:44 +00:00
|
|
|
|
2010-08-23 12:49:54 +00:00
|
|
|
_meta = Meta()
|
2016-11-17 07:42:55 +00:00
|
|
|
|
2010-08-23 12:49:54 +00:00
|
|
|
|
2024-07-03 14:21:33 +00:00
|
|
|
admin.site.register([Config], ConstanceAdmin)
|