from datetime import datetime, date, time from decimal import Decimal from operator import itemgetter from django import forms from django.contrib import admin from django.contrib.admin import widgets from django.contrib.admin.options import csrf_protect_m from django.conf.urls.defaults import patterns, url from django.forms import fields from django.http import HttpResponseRedirect from django.shortcuts import render_to_response from django.template.context import RequestContext from django.utils.formats import localize from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext from constance import config, settings NUMERIC_WIDGET = forms.TextInput(attrs={'size': 10}) INTEGER_LIKE = (fields.IntegerField, {'widget': NUMERIC_WIDGET}) STRING_LIKE = (fields.CharField, {'widget': forms.Textarea(attrs={'rows': 3})}) FIELDS = { bool: (fields.BooleanField, {'required': False}), int: INTEGER_LIKE, long: INTEGER_LIKE, Decimal: (fields.DecimalField, {'widget': NUMERIC_WIDGET}), str: STRING_LIKE, unicode: STRING_LIKE, datetime: (fields.DateTimeField, {'widget': widgets.AdminSplitDateTime}), date: (fields.DateField, {'widget': widgets.AdminDateWidget}), time: (fields.TimeField, {'widget': widgets.AdminTimeWidget}), float: (fields.FloatField, {'widget': NUMERIC_WIDGET}), } class ConstanceForm(forms.Form): def __init__(self, *args, **kwargs): super(ConstanceForm, self).__init__(*args, **kwargs) for name, (default, help_text) in settings.CONFIG.items(): field_class, kwargs = FIELDS[type(default)] self.fields[name] = field_class(label=name, **kwargs) def save(self): for name in self.cleaned_data: setattr(config, name, self.cleaned_data[name]) class ConstanceAdmin(admin.ModelAdmin): def get_urls(self): info = self.model._meta.app_label, self.model._meta.module_name return patterns('', url(r'^$', self.admin_site.admin_view(self.changelist_view), name='%s_%s_changelist' % info ), ) @csrf_protect_m def changelist_view(self, request, extra_context=None): # First load a mapping between config name and default value default_initial = ((name, default) for name, (default, help_text) in settings.CONFIG.iteritems()) # Then update the mapping with actually values from the backend initial = dict(default_initial, **dict(config._backend.mget(settings.CONFIG.keys()))) form = ConstanceForm(initial=initial) if request.method == 'POST': form = ConstanceForm(request.POST) if form.is_valid(): form.save() self.message_user(request, ugettext('Live settings updated successfully.')) return HttpResponseRedirect('.') context = { 'config': [], 'root_path': self.admin_site.root_path, 'title': _('Constance config'), 'app_label': 'constance', 'opts': Config._meta, 'form': form, 'media': self.media + form.media, } for name, (default, help_text) in settings.CONFIG.iteritems(): # 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) context['config'].append({ 'name': name, 'default': localize(default), 'help_text': help_text, 'value': localize(value), 'modified': value != default, 'form_field': form[name] }) context['config'].sort(key=itemgetter('name')) context_instance = RequestContext(request, current_app=self.admin_site.name) return render_to_response('admin/constance/change_list.html', context, context_instance=context_instance) def has_add_permission(self, *args, **kwargs): return False def has_delete_permission(self, *args, **kwargs): return False def has_change_permission(self, request, obj=None, *args, **kwargs): if request.user.is_superuser: return True else: return False class Config(object): class Meta(object): app_label = 'constance' module_name = 'config' verbose_name_plural = 'config' get_ordered_objects = lambda x: False abstract = False _meta = Meta() admin.site.register([Config], ConstanceAdmin)