diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2017-11-19 20:08:16 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2017-11-19 20:08:16 +0100 |
commit | 828fc2faebf1b7fd86d9aaaedf1bd3bbd0d3c6dc (patch) | |
tree | 35a98f2c25a922d1e24c9e29c4b0fe76c9a81593 /ishtar_common | |
parent | 2b35177f62678644ed2c3fb7e7982c67eed2070e (diff) | |
download | Ishtar-828fc2faebf1b7fd86d9aaaedf1bd3bbd0d3c6dc.tar.bz2 Ishtar-828fc2faebf1b7fd86d9aaaedf1bd3bbd0d3c6dc.zip |
Custom forms: admin forms
Diffstat (limited to 'ishtar_common')
-rw-r--r-- | ishtar_common/admin.py | 87 | ||||
-rw-r--r-- | ishtar_common/forms.py | 27 | ||||
-rw-r--r-- | ishtar_common/models.py | 48 | ||||
-rw-r--r-- | ishtar_common/utils.py | 6 |
4 files changed, 151 insertions, 17 deletions
diff --git a/ishtar_common/admin.py b/ishtar_common/admin.py index 8045bff13..7c21fa4be 100644 --- a/ishtar_common/admin.py +++ b/ishtar_common/admin.py @@ -32,6 +32,7 @@ from django.contrib.sites.admin import SiteAdmin from django.contrib.sites.models import Site from django.contrib.gis.forms import PointField, OSMWidget, MultiPolygonField from django.core.cache import cache +from django.forms import BaseInlineFormSet from django.http import HttpResponseRedirect, HttpResponse from django.shortcuts import render from django.template.defaultfilters import slugify @@ -91,6 +92,7 @@ def gen_import_generic(self, request, queryset): request.POST.getlist(admin.ACTION_CHECKBOX_NAME)}) return render(request, 'admin/import_from_csv.html', {'csv_form': form}) + gen_import_generic.short_description = "Import from a CSV file" @@ -166,6 +168,7 @@ class IshtarSiteProfileAdmin(admin.ModelAdmin): 'find', 'warehouse', 'mapping', 'preservation') model = models.IshtarSiteProfile + admin_site.register(models.IshtarSiteProfile, IshtarSiteProfileAdmin) @@ -173,6 +176,7 @@ class DepartmentAdmin(admin.ModelAdmin): list_display = ('number', 'label',) model = models.Department + admin_site.register(models.Department, DepartmentAdmin) @@ -183,6 +187,7 @@ class OrganizationAdmin(HistorizedObjectAdmin): exclude = ('merge_key', 'merge_exclusion', 'merge_candidate', ) model = models.Organization + admin_site.register(models.Organization, OrganizationAdmin) @@ -194,6 +199,7 @@ class PersonAdmin(HistorizedObjectAdmin): form = make_ajax_form(models.Person, {'attached_to': 'organization'}) model = models.Person + admin_site.register(models.Person, PersonAdmin) @@ -251,6 +257,7 @@ class AuthorAdmin(admin.ModelAdmin): model = models.Author form = make_ajax_form(models.Author, {'person': 'person'}) + admin_site.register(models.Author, AuthorAdmin) @@ -259,11 +266,14 @@ class PersonTypeAdmin(admin.ModelAdmin): model = models.PersonType filter_vertical = ('groups',) + admin_site.register(models.PersonType, PersonTypeAdmin) class GlobalVarAdmin(admin.ModelAdmin): list_display = ['slug', 'description', 'value'] + + admin_site.register(models.GlobalVar, GlobalVarAdmin) @@ -290,16 +300,22 @@ class ImporterDefaultAdmin(admin.ModelAdmin): list_display = ('importer_type', 'target') model = models.ImporterDefault inlines = (ImporterDefaultValuesInline,) + + admin_site.register(models.ImporterDefault, ImporterDefaultAdmin) class ImporterTypeAdmin(admin.ModelAdmin): list_display = ('name', 'associated_models', 'available') + + admin_site.register(models.ImporterType, ImporterTypeAdmin) class RegexpAdmin(admin.ModelAdmin): list_display = ('name', 'description', "regexp") + + admin_site.register(models.Regexp, RegexpAdmin) @@ -327,6 +343,8 @@ class ImporterColumnAdmin(admin.ModelAdmin): 'targets_lbl', 'duplicate_fields_lbl', 'required') list_filter = ('importer_type',) inlines = (ImportTargetInline, ImporterDuplicateFieldInline) + + admin_site.register(models.ImporterColumn, ImporterColumnAdmin) @@ -392,6 +410,8 @@ admin_site.register(models.SpatialReferenceSystem, SpatialReferenceSystemAdmin) class ItemKeyAdmin(admin.ModelAdmin): list_display = ('content_type', 'key', 'content_object', 'importer') search_fields = ('key', ) + + admin_site.register(models.ItemKey, ItemKeyAdmin) @@ -449,18 +469,10 @@ def get_choices_form(): cache_key, value = get_cache(models.CustomForm, ['associated-forms']) if value: return value - forms = set() - for app_form in ISHTAR_FORMS: - for form in dir(app_form): - if 'Form' not in form: - # not very clean... but do not treat inappropriate items - continue - form = getattr(app_form, form) - if not issubclass(form, common_forms.CustomForm)\ - or not getattr(form, 'form_slug', None): - continue - forms.add((form.form_slug, form.form_admin_name)) - forms = list(forms) + forms = [] + for slug in models.CustomForm.register(): + forms.append((slug, models.CustomForm._register[slug].form_admin_name)) + forms = sorted(forms, key=lambda x: x[1]) cache.set(cache_key, forms, settings.CACHE_TIMEOUT) return forms @@ -474,9 +486,57 @@ class CustomFormForm(forms.ModelForm): label=_(u"Users")) +class ExcludeFieldFormset(BaseInlineFormSet): + def get_form_kwargs(self, index): + kwargs = super(ExcludeFieldFormset, self).get_form_kwargs(index) + if not self.instance or not self.instance.pk: + return kwargs + form = self.instance.get_form_class() + if not form: + kwargs['choices'] = [] + return kwargs + kwargs['choices'] = [('', '--')] + form.get_custom_fields() + return kwargs + + +class ExcludeFieldForm(forms.ModelForm): + class Meta: + model = models.ExcludedField + exclude = [] + field = forms.ChoiceField(label=_(u"Field")) + + def __init__(self, *args, **kwargs): + choices = kwargs.pop('choices') + super(ExcludeFieldForm, self).__init__(*args, **kwargs) + self.fields['field'].choices = choices + + +class ExcludeFieldInline(admin.TabularInline): + model = models.ExcludedField + extra = 2 + form = ExcludeFieldForm + formset = ExcludeFieldFormset + + class CustomFormAdmin(admin.ModelAdmin): - list_display = ['name', 'form', 'available'] + list_display = ['name', 'form', 'available', 'apply_to_all', + 'users_lbl', 'user_types_lbl'] + fields = ('name', 'form', 'available', 'apply_to_all', 'users', + 'user_types') form = CustomFormForm + inlines = [ExcludeFieldInline] + + def get_inline_instances(self, request, obj=None): + # no inline on creation + if not obj: + return [] + return super(CustomFormAdmin, self).get_inline_instances(request, + obj=obj) + + def get_readonly_fields(self, request, obj=None): + if obj: + return ('form',) + return [] admin_site.register(models.CustomForm, CustomFormAdmin) @@ -515,6 +575,7 @@ class AdministrationTaskAdmin(admin.ModelAdmin): return ("script", ) + self.readonly_fields return self.readonly_fields + admin_site.register(models.AdministrationTask, AdministrationTaskAdmin) diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index d0c2bb035..0f1fa20f8 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -302,6 +302,33 @@ class CustomForm(object): form_admin_name = "" form_slug = "" + def __init__(self, *args, **kwargs): + super(CustomForm, self).__init__(*args, **kwargs) + # todo: filter by user / group... + q = models.CustomForm.objects.filter(form=self.form_slug, + available=True, apply_to_all=True) + if not q.count(): + return + # todo: prevent multiple result in database + form = q.all()[0] + for excluded in form.excluded_fields.all(): + # could have be filtered previously + if excluded.field in self.fields: + self.fields.pop(excluded.field) + + @classmethod + def get_custom_fields(cls): + fields = cls.base_fields + customs = [] + for key in fields: + field = fields[key] + # cannot customize display of required and hidden field + # field with no label are also rejected + if field.required or field.widget.is_hidden or not field.label: + continue + customs.append((key, field.label)) + return sorted(customs, key=lambda x: x[1]) + class DocumentGenerationForm(forms.Form): """ diff --git a/ishtar_common/models.py b/ishtar_common/models.py index a5a3d96c1..c888e87fd 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -1647,14 +1647,58 @@ class CustomForm(models.Model): verbose_name_plural = _(u"Custom forms") ordering = ['name', 'form'] + def users_lbl(self): + users = [unicode(user) for user in self.users.all()] + return " ; ".join(users) + + users_lbl.short_description = _(u"Users") + + def user_types_lbl(self): + user_types = [unicode(u) for u in self.user_types.all()] + return " ; ".join(user_types) + + user_types_lbl.short_description = _(u"User types") + + @classmethod + def register(cls): + if hasattr(cls, '_register'): + return cls._register + cache_key, value = get_cache(cls.__class__, ['dct-forms'], + app_label='ishtar_common') + if value: + cls._register = value + return cls._register + cls._register = {} + # ideally should be improved but only used in admin + from ishtar_common.admin import ISHTAR_FORMS + from ishtar_common.forms import CustomForm + + for app_form in ISHTAR_FORMS: + for form in dir(app_form): + if 'Form' not in form: + # not very clean... but do not treat inappropriate items + continue + form = getattr(app_form, form) + if not issubclass(form, CustomForm) \ + or not getattr(form, 'form_slug', None): + continue + cls._register[form.form_slug] = form + return cls._register + + def get_form_class(self): + register = self.register() + if self.form not in self._register: + return + return register[self.form] + class ExcludedField(models.Model): custom_form = models.ForeignKey(CustomForm, related_name='excluded_fields') field = models.CharField(_(u"Field"), max_length=250) class Meta: - verbose_name = _(u"Custom form - excluded field") - verbose_name_plural = _(u"Custom form - excluded fields") + verbose_name = _(u"Excluded field") + verbose_name_plural = _(u"Excluded fields") class GlobalVar(models.Model, Cached): diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index 5d9e85c60..ae178a752 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -51,9 +51,11 @@ def get_current_year(): return datetime.datetime.now().year -def get_cache(cls, extra_args=[]): +def get_cache(cls, extra_args=tuple(), app_label=None): + if not app_label: + app_label = cls._meta.app_label cache_key = u"{}-{}-{}".format( - settings.PROJECT_SLUG, cls._meta.app_label, cls.__name__) + settings.PROJECT_SLUG, app_label, cls.__name__) for arg in extra_args: if not arg: cache_key += '-0' |