diff options
| author | Étienne Loks <etienne.loks@iggdrasil.net> | 2017-11-21 15:26:41 +0100 | 
|---|---|---|
| committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2017-11-21 15:26:41 +0100 | 
| commit | 1f49ac758d42cd924dd1df39af58835b80f1f77e (patch) | |
| tree | b631fd7d258640517b986708b1db9f35239d95ce /ishtar_common | |
| parent | c410be9b3c3ba193ee8c233cc6a50d065d4090fd (diff) | |
| download | Ishtar-1f49ac758d42cd924dd1df39af58835b80f1f77e.tar.bz2 Ishtar-1f49ac758d42cd924dd1df39af58835b80f1f77e.zip  | |
Custom forms: manage formsets
Diffstat (limited to 'ishtar_common')
| -rw-r--r-- | ishtar_common/forms.py | 180 | ||||
| -rw-r--r-- | ishtar_common/tests.py | 2 | 
2 files changed, 108 insertions, 74 deletions
diff --git a/ishtar_common/forms.py b/ishtar_common/forms.py index da6a1c051..8b97cfbab 100644 --- a/ishtar_common/forms.py +++ b/ishtar_common/forms.py @@ -105,7 +105,92 @@ def get_readonly_clean(key):      return func -class FormSet(BaseFormSet): +class CustomForm(object): +    form_admin_name = "" +    form_slug = "" +    need_user_for_initialization = True + +    def __init__(self, *args, **kwargs): +        current_user = None +        if 'user' in kwargs: +            try: +                current_user = kwargs.pop('user').ishtaruser +            except AttributeError: +                pass +        super(CustomForm, self).__init__(*args, **kwargs) +        available, excluded = self.check_availability_and_excluded_fields( +            current_user) +        for exc in excluded: +            if hasattr(self, 'fields'): +                self.remove_field(exc) +            else: +                # formset +                for form in self.forms: +                    if exc in form.fields: +                        form.fields.pop(exc) + +    def are_available(self, keys): +        for k in keys: +            if k not in self.fields: +                return False +        return True + +    def remove_field(self, key): +        if key in self.fields: +            self.fields.pop(key) + +    @classmethod +    def check_availability_and_excluded_fields(cls, current_user): +        if not current_user: +            return True, [] +        base_q = {"form": cls.form_slug, 'available': True} +        # order is important : try for user, user type then all +        query_dicts = [] +        if current_user: +            dct = base_q.copy() +            dct.update({'users__pk': current_user.pk}) +            query_dicts = [dct] +            for user_type in current_user.person.person_types.all(): +                dct = base_q.copy() +                dct.update({'user_types__pk': user_type.pk}), +                query_dicts.append(dct) +        dct = base_q.copy() +        dct.update({'apply_to_all': True}) +        query_dicts.append(dct) +        excluded_lst = [] +        for query_dict in query_dicts: +            q = models.CustomForm.objects.filter(**query_dict) +            if not q.count(): +                continue +            # todo: prevent multiple result in database +            form = q.all()[0] +            if not form.enabled: +                return False, [] +            for excluded in form.excluded_fields.all(): +                # could have be filtered previously +                excluded_lst.append(excluded.field) +            break +        return True, excluded_lst + +    @classmethod +    def get_custom_fields(cls): +        if hasattr(cls, 'base_fields'): +            fields = cls.base_fields +        else: +            # formset +            fields = cls.form.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 FormSet(CustomForm, BaseFormSet):      def __init__(self, *args, **kwargs):          self.readonly = False          if 'readonly' in kwargs: @@ -250,8 +335,23 @@ def get_data_from_formset(data):      return values +class FieldType(object): +    def __init__(self, key, model, is_multiple=False): +        self.key = key +        self.model = model +        self.is_multiple = is_multiple + +    def get_choices(self, initial=None): +        return self.model.get_types( +            empty_first=not self.is_multiple, +            initial=initial) + +    def get_help(self): +        return self.model.get_help() + +  class ManageOldType(object): -    TYPES = []  # (field_name, model, is_multiple) list +    TYPES = []  # FieldType list      def __init__(self, *args, **kwargs):          """ @@ -290,78 +390,12 @@ class ManageOldType(object):                          self.init_data[k].append(val)          self.init_data = MultiValueDict(self.init_data)          super(ManageOldType, self).__init__(*args, **kwargs) -        for field_name, model, is_multiple in self.TYPES: -            self.fields[field_name].choices = \ -                model.get_types( -                    empty_first=not is_multiple, -                    initial=self.init_data.get(field_name)) -            self.fields[field_name].help_text = model.get_help() - - -class CustomForm(object): -    form_admin_name = "" -    form_slug = "" -    need_user_for_initialization = True - -    def __init__(self, *args, **kwargs): -        current_user = None -        if 'user' in kwargs: -            try: -                current_user = kwargs.pop('user').ishtaruser -            except AttributeError: -                pass -        super(CustomForm, self).__init__(*args, **kwargs) -        available, excluded = self.check_availability_and_excluded_fields( -            current_user) -        for exc in excluded: -            if exc in self.fields: -                self.fields.pop(exc) - -    @classmethod -    def check_availability_and_excluded_fields(cls, current_user): -        if not current_user: -            return True, [] -        base_q = {"form": cls.form_slug, 'available': True} -        # order is important : try for user, user type then all -        query_dicts = [] -        if current_user: -            dct = base_q.copy() -            dct.update({'users__pk': current_user.pk}) -            query_dicts = [dct] -            for user_type in current_user.person.person_types.all(): -                dct = base_q.copy() -                dct.update({'user_types__pk': user_type.pk}), -                query_dicts.append(dct) -        dct = base_q.copy() -        dct.update({'apply_to_all': True}) -        query_dicts.append(dct) -        excluded_lst = [] -        for query_dict in query_dicts: -            q = models.CustomForm.objects.filter(**query_dict) -            if not q.count(): +        for field in self.TYPES: +            if field.key not in self.fields:                  continue -            # todo: prevent multiple result in database -            form = q.all()[0] -            if not form.enabled: -                return False, [] -            for excluded in form.excluded_fields.all(): -                # could have be filtered previously -                excluded_lst.append(excluded.field) -            break -        return True, excluded_lst - -    @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]) +            self.fields[field.key].choices = field.get_choices( +                initial=self.init_data.get(field.key)) +            self.fields[field.key].help_text = field.get_help()  class DocumentGenerationForm(forms.Form): diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py index 016596772..7c8b2fd5c 100644 --- a/ishtar_common/tests.py +++ b/ishtar_common/tests.py @@ -1,6 +1,6 @@  #!/usr/bin/env python  # -*- coding: utf-8 -*- -# Copyright (C) 2015-2016 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2015-2017 Étienne Loks  <etienne.loks_AT_peacefrogsDOTnet>  # This program is free software: you can redistribute it and/or modify  # it under the terms of the GNU Affero General Public License as  | 
