Beispiel #1
0
class FilterSerializer(serializers.ModelSerializer):
    template_context = dict(url_reverse='filter')
    form_titles = {
        'table': 'Dynamic filter list',
        'new': 'New object',
        'edit': 'Editing object',
    }
    actions = Actions(
        TableAction(TablePosition.FILTER_ROW_END, _('+ Add'), title=_('Add new record'), name='add',
                    action_js="dynamicforms.newRow('{% url url_reverse|add:'-detail' pk='new' format='html' %}'"
                              ", 'record', __TABLEID__);"),
        TableAction(TablePosition.ROW_CLICK, _('Edit'), title=_('Edit record'), name='edit',
                    action_js="dynamicforms.editRow('{% url url_reverse|add:'-detail' pk='__ROWID__' "
                              "format='html' %}'.replace('__ROWID__', $(event.target.parentElement).closest('tr[class=\"df-table-row\"]').attr('data-id')), 'record', __TABLEID__);"),
        TableAction(TablePosition.ROW_END, label=_('Delete'), title=_('Delete record'), name='delete',
                    action_js="dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
                              "{{row.id}}, 'record', __TABLEID__);"),
        TableAction(TablePosition.FILTER_ROW_END, label=_('Filter'), title=_('Filter'), name='filter',
                    action_js="dynamicforms.defaultFilter(event);")
    )
    show_filter = True

    name = NameTestField(
        label='Name field',
        max_length=list(filter(lambda f: f.name == 'name', Filter._meta.fields))[0].max_length,
        allow_null=list(filter(lambda f: f.name == 'name', Filter._meta.fields))[0].null,
        source='*',

    )

    class Meta:
        model = Filter
        exclude = ()
Beispiel #2
0
class PageLoadSerializer(serializers.ModelSerializer):
    form_titles = {
        'table': 'Dynamic page loader list',
        'new': 'New object',
        'edit': 'Editing object',
    }
    actions = Actions(add_default_crud=True, add_default_filter=True)
    show_filter = True

    class Meta:
        model = PageLoad
        exclude = ()
Beispiel #3
0
class HiddenFieldsSerializer(serializers.ModelSerializer):
    form_titles = {
        'table': 'Hidden fields list',
        'new': 'New hidden fields object',
        'edit': 'Editing hidden fields object',
    }

    actions = Actions(
        FieldChangeAction(['note'], 'examples.action_hiddenfields_note'),
        FieldChangeAction(['unit'], 'examples.action_hiddenfields_unit'),
        FormInitAction(
            'examples.hide_fields_on_show("{{ serializer.uuid }}");'),
        add_default_crud=True,
        add_default_filter=False)

    class Meta:
        model = HiddenFields
        exclude = ()
Beispiel #4
0
class SingleDialogSerializer(serializers.Serializer):
    form_titles = {
        'table': '',
        'new': 'Choose a value',
        'edit': '',
    }
    form_template = 'examples/single_dialog.html'

    test = fields.ChoiceField(label='What should we say?', choices=(
        ('Today is sunny', 'Today is sunny'),
        ('Never-ending rain', 'Never-ending rain')
    ))

    actions = Actions(
        FormButtonAction(FormButtonTypes.CANCEL),
        FormButtonAction(FormButtonTypes.CUSTOM, label='Download it', action_js="customSingleDialogBtnPost();"),
        FormButtonAction(FormButtonTypes.CUSTOM, label='Say it', button_is_primary=True,
                         action_js="customSingleDialogBtn();"),
        add_form_buttons=False
    )
Beispiel #5
0
class BasicFieldsSerializer(serializers.ModelSerializer):
    form_titles = {
        'table': 'Basic fields list',
        'new': 'New basic fields object',
        'edit': 'Editing basic fields object',
    }
    form_template = 'examples/form_cols.html'

    actions = Actions(TableAction(TablePosition.HEADER,
                                  _('Modal dialog'),
                                  title=_('Dialog test'),
                                  name='modal_dialog',
                                  action_js="examples.testModalDialog();"),
                      add_default_crud=True,
                      add_form_buttons=True)

    boolean_field = fields.BooleanField()
    nullboolean_field = fields.NullBooleanField()
    char_field = fields.CharField()
    email_field = fields.EmailField()
    slug_field = fields.SlugField()
    url_field = fields.URLField()
    uuid_field = fields.UUIDField()
    ipaddress_field = fields.IPAddressField()
    integer_field = fields.IntegerField()
    nullint_field = fields.IntegerField(allow_null=True)
    float_field = fields.FloatField()
    decimal_field = fields.DecimalField(max_digits=5, decimal_places=2)
    datetime_field = fields.DateTimeField(required=False)
    date_field = fields.DateField()
    time_field = fields.TimeField()
    duration_field = fields.DurationField()
    password_field = fields.CharField(password_field=True)

    class Meta:
        model = BasicFields
        exclude = ()
Beispiel #6
0
class DynamicFormsSerializer(RenderMixin, ActionMixin):
    template_context = {}  # see ViewSet.template_context
    template_name = DYNAMICFORMS.form_base_template  #: template filename for single record view (HTMLFormRenderer)
    actions = Actions(add_default_crud=True, add_form_buttons=True)
    form_titles = {
        'table': '',
        'new': '',
        'edit': '',
    }

    show_filter = False  # When true, filter row is shown for list view

    def __init__(self, *args, is_filter: bool = False, **kwds):
        self.master = None
        self.is_filter = is_filter
        if self.is_filter:
            try:
                instance = self.Meta.model()
                for fld in instance._meta.fields:
                    setattr(instance, fld.name, None)
            except:
                instance = StructDefault(_default_=None)
            kwds.setdefault('instance', instance)
        super().__init__(*args, **kwds)
        try:
            # hide the primary key field (DRF only marks it as R/O)
            field_name = self.Meta.model._meta.pk.name
            if field_name not in self._declared_fields:
                pk_field = self.fields[field_name]
                pk_field.display_form = fields.DisplayMode.HIDDEN
                pk_field.display_table = fields.DisplayMode.FULL
        except:
            pass
        if self.is_filter:
            for field in self.fields.values():
                field.default = None
                field.allow_blank = True
                field.allow_null = True
                field.read_only = False
                field.display_form = field.display_table  # filter's form is same as non-filter's table
                field.allow_tags = False
                field.password_field = False

    @property
    def has_non_field_errors(self):
        """
        Reports whether validation turned up any form-wide validation errors. Used in templates to render the form-wide
        error message

        :return: True | False depending on whether form validation failed
        """
        if hasattr(self, '_errors'):
            return 'non_field_errors' in self.errors
        return False

    @property
    def page_title(self):
        """
        Returns page title from form_titles based on the rendered data
        :return string: page title
        """
        if self.render_type == 'table':
            return self.form_titles.get('table', '')
        elif self.data.get('id', None):
            return self.form_titles.get('edit', '')
        else:
            return self.form_titles.get('new', '')

    # noinspection PyProtectedMember
    @property
    def filter_data(self):
        """
        Returns serializer for filter row in table
        :return:  Serializer
        """
        if getattr(self, '_filter_ser', None) is None:
            # noinspection PyAttributeOutsideInit
            self._filter_ser = type(self)(is_filter=True,
                                          context=getattr(self, 'context', {}))
            self._filter_ser.master = self
        return self._filter_ser  # Just create the same serializer in filter mode (None values, allow_nulls)

    # noinspection PyUnusedLocal
    def suppress_action(self, action, request, viewset):
        """
        Determines whether rendering an action into the DOM should be suppressed. Use when some users don't have access
        to some of the functionality, e.g. when CRUD functionality is only enabled for administrative users
        :param action: action to be checked
        :param request: request that triggered the render (may be None)
        :param viewset: viewset that provided the serialized data (may be None)
        :return: boolean whether action should render (False) or not (True)
        """
        return False

    @property
    def renderable_actions(self: 'serializers.Serializer'):
        """
        Returns those actions that are not suppressed
        :return: List[Action]
        """
        # TODO: Ta funkcija po mojem mora odletet (self.*controls*.actions). Sam zakaj ne? Ali se sploh ne uporablja?
        request = self.context.get('request', None)
        viewset = self.context.get('view', None)
        return [
            action for action in self.controls.actions
            if not self.suppress_action(action, request, viewset)
        ]

    # noinspection PyUnresolvedReferences
    def get_initial(self) -> Any:
        if getattr(self, '_errors', None):
            # This basically reproduces BaseSerializer.data property except that it disregards the _errors member
            if self.instance:
                res = self.to_representation(self.instance)
            # elif hasattr(self, '_validated_data'):
            #     res = self.to_representation(self.validated_data)
            else:
                res = {}
            res.update(super().get_initial())

            return res

        return super().get_initial()

    # noinspection PyUnresolvedReferences
    @property
    def _writable_fields(self):
        """
        Overrides DRF.serializers.Serializer._writable_fields
        This one in particular should return exactly the same list as DRF's version (as of 17.4.2020, DRF version 3.11
        """
        return (field for field in self.fields.values() if not field.read_only)

    # noinspection PyUnresolvedReferences
    @property
    def _readable_fields(self):
        """
        Overrides DRF.serializers.Serializer._readable_fields
        This one adds additional checks on top of DRF's ones - checking if the field is renderable to table or form
        """
        return (field for field in self.fields.values()
                if not (field.write_only or
                        (self.is_rendering_to_list
                         and self.display_table == DisplayMode.SUPPRESS) or
                        (not self.is_rendering_to_list
                         and self.display_form == DisplayMode.SUPPRESS)))

    def to_representation(self, instance, row_data=None):
        """
        Object instance -> Dict of primitive datatypes.
        """
        ret = OrderedDict()
        for field in self._readable_fields:
            try:
                attribute = field.get_attribute(instance)
                if not isinstance(field, RenderMixin):
                    ret[field.field_name] = field.to_representation(attribute)
                else:
                    try:
                        ret[field.field_name] = field.to_representation(
                            attribute, instance)
                    except:
                        if attribute is None and not field.required:
                            # DRF makes a special check for none and then always returns None if the check is None.
                            # We still want to process custom field to_representation, even if value is None.
                            # But when field is a sub-serializer and it (it's FK reference) is none, it's OK
                            # to pass None as result of serialization of such field
                            raise SkipField()
                        else:
                            raise
            except SkipField:
                pass

        return ret
Beispiel #7
0
class UserSerializer(serializers.ModelSerializer):
    form_template = 'usereditor/user_item.html'
    form_titles = {
        'table': _('Users'),
        'new': _('New user'),
        'edit': _('Editing user'),
    }
    actions = Actions(add_default_crud=True, add_default_filter=True)
    show_filter = True

    password = fields.CharField(label=_('Password'), write_only=True, display_table=fields.DisplayMode.SUPPRESS)
    full_name = fields.SerializerMethodField(label=_('Full name'), read_only=True,
                                             display_form=fields.DisplayMode.SUPPRESS)
    username = fields.CharField(label=_('Username'), display_table=fields.DisplayMode.SUPPRESS)
    email = UserEmailField(label=_('Email'), source='*', required=False, allow_blank=True)
    email_verified = fields.SerializerMethodField(display_table=fields.DisplayMode.SUPPRESS)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def suppress_action(self, action, request, viewset):
        if request and request.user and not request.user.is_staff and action.name in ('add', 'edit', 'delete'):
            return True
        return super().suppress_action(action, request, viewset)

    def get_email(self, obj):
        email = None
        if hasattr(obj, 'emailaddress_set'):
            for e in obj.emailaddress_set.all():
                if e.verified and (not email or e.email == obj.email):
                    # email mora biti verificiran, da povozi onega iz userja,
                    #   če pa je še enak za povrh, je pa sploh super
                    email = e

            if email:
                return email.email, email.verified

        return None, False

    def get_full_name(self, obj):
        if not obj.id:
            return ''
        return obj.get_full_name()

    def validate(self, attrs):
        res = super().validate(attrs)
        email = attrs.get('email', None)
        if not email:
            return res

        from allauth.account.models import EmailAddress
        from rest_framework.exceptions import ValidationError

        qry = EmailAddress.objects.filter(email=email)
        if self.instance:
            qry = qry.exclude(user=self.instance)
        if qry.exists():
            raise ValidationError(dict(email=_('This e-mail address is already associated with another account.')))

        return res

    @transaction.atomic
    def create(self, validated_data):
        res = super().create(validated_data)
        self.update_user_settings(res, validated_data)
        return res

    @transaction.atomic
    def update(self, instance, validated_data):
        # noinspection PyTypeChecker
        self.update_user_settings(instance, validated_data)
        return super().update(instance, validated_data)

    @staticmethod
    def update_user_settings(instance, validated_data, *args, **kwargs):
        from allauth.account.models import EmailAddress

        email = validated_data.get('email', None)
        if email and not EmailAddress.objects.filter(user=instance, email=email).exists():
            EmailAddress.objects.filter(user=instance).update(primary=False)
            EmailAddress.objects.create(user=instance, email=email, primary=True, verified=False)

    def get_email_verified(self, rec):
        return self.get_email(rec)[1]

    class Meta:
        model = get_user_model()
        fields = ('id', 'full_name', 'username', 'password', 'first_name', 'last_name', 'is_staff', 'is_superuser',
                  'is_active', 'email', 'email_verified')
        changed_flds = {
            'id': dict(display=DisplayMode.HIDDEN),
        }
        for f in ['first_name', 'last_name', 'is_superuser', 'is_active']:  # type: fields.RenderMixin
            changed_flds[f] = dict(display_table=DisplayMode.SUPPRESS)
Beispiel #8
0
class ValidatedSerializer(serializers.ModelSerializer):
    form_titles = {
        'table': 'Validated list',
        'new': 'New validated object',
        'edit': 'Editing validated object',
    }
    actions = Actions(
        TableAction(
            TablePosition.HEADER,
            label=_('+ Add (refresh record)'),
            title=_('Add new record'),
            action_js=
            "dynamicforms.newRow('{% url url_reverse|add:'-detail' pk='new' format='html' %}'"
            ", 'record', __TABLEID__);"),
        TableAction(
            TablePosition.HEADER,
            label=_('+ Add (refresh table)'),
            title=_('Add new record'),
            action_js=
            "dynamicforms.newRow('{% url url_reverse|add:'-detail' pk='new' format='html' %}'"
            ", 'table', __TABLEID__);"),
        TableAction(
            TablePosition.HEADER,
            label=_('+ Add (no refresh)'),
            title=_('Add new record'),
            action_js=
            "dynamicforms.newRow('{% url url_reverse|add:'-detail' pk='new' format='html' %}'"
            ", 'no refresh', __TABLEID__);"),
        TableAction(
            TablePosition.ROW_CLICK,
            label=_('Edit'),
            title=_('Edit record'),
            action_js=
            "dynamicforms.editRow('{% url url_reverse|add:'-detail' pk='__ROWID__' format='html'"
            " %}'.replace('__ROWID__', $(event.target.parentElement).closest('tr[class=\"df-table-row\"]').attr('data-id'))"
            ", 'record', __TABLEID__);"),
        TableAction(
            TablePosition.ROW_END,
            label=_('Delete (refresh record)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            + "{{row.id}}, 'record', __TABLEID__);"),
        TableAction(
            TablePosition.ROW_END,
            label=_('Delete (refresh table)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            + "{{row.id}}, 'table', __TABLEID__);"),
        TableAction(
            TablePosition.ROW_END,
            label=_('Delete (no refresh)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            + "{{row.id}}, 'no refresh', __TABLEID__);"),
        # The following action is duplicated unnecessarily just to later eliminate it in suppress_action
        TableAction(
            TablePosition.ROW_END,
            name='del 1',
            label=_('Delete (no refresh)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            + "{{row.id}}, 'no refresh', __TABLEID__);"))

    def validate(self, attrs):
        attrs = super().validate(attrs)

        if attrs['amount'] != 5:
            if attrs['code'] != '123':
                raise ValidationError({
                    'amount':
                    'amount can only be different than 5 if code is "123"'
                })

        if attrs['enabled'] is True and attrs['item_type'] == 3:
            raise ValidationError(
                'When enabled you can only choose from first three item types')

        return attrs

    def suppress_action(self, action, request, viewset):
        if action.name == 'del 1':
            return True
        return super().suppress_action(action, request, viewset)

    class Meta:
        model = Validated
        exclude = ()
Beispiel #9
0
class RefreshTypesSerializer(serializers.ModelSerializer):
    form_titles = {
        'table': 'Refresh type list',
        'new': 'New refresh type object',
        'edit': 'Editing refresh type object',
    }
    actions = Actions(
        # Add actions
        # refresh record
        TableAction(
            TablePosition.HEADER,
            label=_('+ Add (refresh record)'),
            title=_('Add new record'),
            action_js=
            "dynamicforms.newRow('{% url url_reverse|add:'-detail' pk='new' format='html' %}'"
            ", 'record', __TABLEID__);"),
        # refresh table
        TableAction(
            TablePosition.HEADER,
            label=_('+ Add (refresh table)'),
            title=_('Add new record'),
            action_js=
            "dynamicforms.newRow('{% url url_reverse|add:'-detail' pk='new' format='html' %}'"
            ", 'table', __TABLEID__);"),
        # no refresh
        TableAction(
            TablePosition.HEADER,
            label=_('+ Add (no refresh)'),
            title=_('Add new record'),
            action_js=
            "dynamicforms.newRow('{% url url_reverse|add:'-detail' pk='new' format='html' %}'"
            ", 'no refresh', __TABLEID__);"),
        # page reload
        TableAction(
            TablePosition.HEADER,
            label=_('+ Add (page reload)'),
            title=_('Add new record'),
            action_js=
            "dynamicforms.newRow('{% url url_reverse|add:'-detail' pk='new' format='html' %}'"
            ", 'page', __TABLEID__);"),
        # redirect
        TableAction(
            TablePosition.HEADER,
            label=_('+ Add (redirect)'),
            title=_('Add new record'),
            action_js=
            "dynamicforms.newRow('{% url url_reverse|add:'-detail' pk='new' format='html' %}'"
            ", 'redirect:{% url 'validated-list' format='html' %}', __TABLEID__);"
        ),
        # custom function
        TableAction(
            TablePosition.HEADER,
            label=_('+ Add (custom function)'),
            title=_('Add new record'),
            action_js=
            "dynamicforms.newRow('{% url url_reverse|add:'-detail' pk='new' format='html' %}'"
            ", 'testRefreshType', __TABLEID__);"),

        # Edit actions
        TableAction(
            TablePosition.ROW_CLICK,
            label=_('Edit'),
            title=_('Edit record'),
            action_js=
            "dynamicforms.editRow('{% url url_reverse|add:'-detail' pk='__ROWID__' format='html'"
            " %}'.replace('__ROWID__', $(event.target.parentElement).closest('tr[class=\"df-table-row\"]').attr('data-id'))"
            ", 'record', __TABLEID__);"),

        # Delete actions
        # refresh record
        TableAction(
            TablePosition.ROW_END,
            label=_('Delete (refresh record)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            + "{{row.id}}, 'record', __TABLEID__);"),
        # refresh table
        TableAction(
            TablePosition.ROW_END,
            label=_('Delete (refresh table)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            + "{{row.id}}, 'table', __TABLEID__);"),
        # no refresh
        TableAction(
            TablePosition.ROW_END,
            label=_('Delete (no refresh)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            + "{{row.id}}, 'no refresh', __TABLEID__);"),
        # The following action is duplicated unnecessarily just to later eliminate it in suppress_action
        TableAction(
            TablePosition.ROW_END,
            name='del 1',
            label=_('Delete (no refresh)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            + "{{row.id}}, 'no refresh', __TABLEID__);"),
        # page reload
        TableAction(
            TablePosition.ROW_END,
            label=_('Delete (page reload)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            + "{{row.id}}, 'page', __TABLEID__);"),
        # redirect
        TableAction(
            TablePosition.ROW_END,
            label=_('Delete (redirect)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            +
            "{{row.id}}, 'redirect:{% url 'validated-list' format='html' %}', __TABLEID__);"
        ),
        # custom function
        TableAction(
            TablePosition.ROW_END,
            label=_('Delete (custom function)'),
            title=_('Delete record'),
            action_js=
            "dynamicforms.deleteRow('{% url url_reverse|add:'-detail' pk=row.id %}', "
            + "{{row.id}}, 'testRefreshType', __TABLEID__);"),
    )

    rich_text_field = fields.RTFField(required=False, allow_blank=True)

    def suppress_action(self, action, request, viewset):
        if action.name == 'del 1':
            return True
        return super().suppress_action(action, request, viewset)

    class Meta:
        model = RefreshType
        exclude = ()