Example #1
0
def get_form(
    model,
    converter,
    base_class=form.BaseForm,
    only=None,
    exclude=None,
    field_args=None,
    allow_pk=False,
    extra_fields=None,
):
    """
        Create form from peewee model and contribute extra fields, if necessary
    """
    result = model_form(
        model,
        base_class=base_class,
        only=only,
        exclude=exclude,
        field_args=field_args,
        allow_pk=allow_pk,
        converter=converter,
    )

    if extra_fields:
        for name, field in iteritems(extra_fields):
            setattr(result, name, form.recreate_field(field))

    return result
Example #2
0
    def convert(self, model, field, field_args):
        # Check if it is overridden field
        if isinstance(field, FieldPlaceholder):
            return form.recreate_field(field.field)

        kwargs = {
            'label': getattr(field, 'verbose_name', field.name),
            'description': '',
            'validators': [],
            'filters': []
        }
        if hasattr(field, 'help_text') and field.help_text:
            kwargs['help_text'] = field.help_text

        if hasattr(field, 'default') and field.default:
            kwargs['default'] = field.default

        if field_args:
            kwargs.update(field_args)

        if hasattr(field, 'required') and field.required:
            kwargs['validators'].append(validators.Required())
        else:
            kwargs['validators'].append(validators.Optional())

        ftype = type(field).__name__

        if hasattr(field, 'choices') and field.choices:
            kwargs['choices'] = list(self._convert_choices(field.choices))

            if ftype in self.converters:
                kwargs["coerce"] = self.coerce(ftype)
            if kwargs.pop('multiple', False):
                return fields.SelectMultipleField(**kwargs)
            return fields.SelectField(**kwargs)

        ftype = type(field).__name__

        if hasattr(field, 'to_form_field'):
            return field.to_form_field(model, kwargs)

        override = self._get_field_override(field.name)
        if override:
            return override(**kwargs)

        if ftype in self.converters:
            return self.converters[ftype](model, field, kwargs)
Example #3
0
    def convert(self, model, field, field_args):
        # Check if it is overridden field
        if isinstance(field, FieldPlaceholder):
            return form.recreate_field(field.field)

        kwargs = {
            'label': getattr(field, 'verbose_name', field.name),
            'description': field.help_text or '',
            'validators': [],
            'filters': [],
            'default': field.default
        }

        if field_args:
            kwargs.update(field_args)

        if field.required:
            kwargs['validators'].append(validators.Required())
        else:
            kwargs['validators'].append(validators.Optional())

        ftype = type(field).__name__

        if field.choices:
            kwargs['choices'] = list(self._convert_choices(field.choices))

            if ftype in self.converters:
                kwargs["coerce"] = self.coerce(ftype)
            if kwargs.pop('multiple', False):
                return fields.SelectMultipleField(**kwargs)
            return fields.SelectField(**kwargs)

        ftype = type(field).__name__

        if hasattr(field, 'to_form_field'):
            return field.to_form_field(model, kwargs)

        override = self._get_field_override(field.name)
        if override:
            return override(**kwargs)

        if ftype in self.converters:
            return self.converters[ftype](model, field, kwargs)
Example #4
0
    def convert(self, model, field, field_args):
        # Check if it is overridden field
        if isinstance(field, FieldPlaceholder):
            return form.recreate_field(field.field)

        kwargs = {
            "label": getattr(field, "verbose_name", field.name),
            "description": field.help_text or "",
            "validators": [],
            "filters": [],
            "default": field.default,
        }

        if field_args:
            kwargs.update(field_args)

        if field.required:
            kwargs["validators"].append(validators.Required())
        else:
            kwargs["validators"].append(validators.Optional())

        ftype = type(field).__name__

        if field.choices:
            kwargs["choices"] = field.choices

            if ftype in self.converters:
                kwargs["coerce"] = self.coerce(ftype)
            if kwargs.pop("multiple", False):
                return fields.SelectMultipleField(**kwargs)
            return fields.SelectField(**kwargs)

        ftype = type(field).__name__

        if hasattr(field, "to_form_field"):
            return field.to_form_field(model, kwargs)

        override = self._get_field_override(field.name)
        if override:
            return override(**kwargs)

        if ftype in self.converters:
            return self.converters[ftype](model, field, kwargs)
Example #5
0
def get_form(model, converter,
             base_class=form.BaseForm,
             only=None,
             exclude=None,
             field_args=None,
             allow_pk=False,
             extra_fields=None):
    """
        Create form from peewee model and contribute extra fields, if necessary
    """
    result = model_form(model,
                        base_class=base_class,
                        only=only,
                        exclude=exclude,
                        field_args=field_args,
                        allow_pk=allow_pk,
                        converter=converter)

    if extra_fields:
        for name, field in iteritems(extra_fields):
            setattr(result, name, form.recreate_field(field))

    return result
Example #6
0
def get_form(model,
             converter,
             base_class=form.BaseForm,
             only=None,
             exclude=None,
             field_args=None,
             extra_fields=None):
    """
    Create a wtforms Form for a given mongoengine Document schema::

        from flask.ext.mongoengine.wtf import model_form
        from myproject.myapp.schemas import Article
        ArticleForm = model_form(Article)

    :param model:
        A mongoengine Document schema class
    :param base_class:
        Base form class to extend from. Must be a ``wtforms.Form`` subclass.
    :param only:
        An optional iterable with the property names that should be included in
        the form. Only these properties will have fields.
    :param exclude:
        An optional iterable with the property names that should be excluded
        from the form. All other properties will have fields.
    :param field_args:
        An optional dictionary of field names mapping to keyword arguments used
        to construct each field object.
    :param converter:
        A converter to generate the fields based on the model properties. If
        not set, ``ModelConverter`` is used.
    """
    if not isinstance(model, (BaseDocument, DocumentMetaclass)):
        raise TypeError('Model must be a mongoengine Document schema')

    field_args = field_args or {}

    # Find properties
    properties = sorted(((k, v) for k, v in iteritems(model._fields)),
                        key=lambda v: v[1].creation_counter)

    if only:
        props = dict(properties)

        def find(name):
            if extra_fields and name in extra_fields:
                return FieldPlaceholder(extra_fields[name])

            p = props.get(name)
            if p is not None:
                return p

            raise ValueError('Invalid model property name %s.%s' %
                             (model, name))

        properties = ((p, find(p)) for p in only)
    elif exclude:
        properties = (p for p in properties if p[0] not in exclude)

    # Create fields
    field_dict = {}
    for name, p in properties:
        field = converter.convert(model, p, field_args.get(name))
        if field is not None:
            field_dict[name] = field

    # Contribute extra fields
    if not only and extra_fields:
        for name, field in iteritems(extra_fields):
            field_dict[name] = form.recreate_field(field)

    field_dict['model_class'] = model
    return type(model.__name__ + 'Form', (base_class, ), field_dict)
Example #7
0
def get_form(model, converter,
             base_class=form.BaseForm,
             only=None,
             exclude=None,
             field_args=None,
             extra_fields=None):
    """
    Create a wtforms Form for a given mongoengine Document schema::

        from flask.ext.mongoengine.wtf import model_form
        from myproject.myapp.schemas import Article
        ArticleForm = model_form(Article)

    :param model:
        A mongoengine Document schema class
    :param base_class:
        Base form class to extend from. Must be a ``wtforms.Form`` subclass.
    :param only:
        An optional iterable with the property names that should be included in
        the form. Only these properties will have fields.
    :param exclude:
        An optional iterable with the property names that should be excluded
        from the form. All other properties will have fields.
    :param field_args:
        An optional dictionary of field names mapping to keyword arguments used
        to construct each field object.
    :param converter:
        A converter to generate the fields based on the model properties. If
        not set, ``ModelConverter`` is used.
    """
    if not isinstance(model, (BaseDocument, DocumentMetaclass)):
        raise TypeError('Model must be a mongoengine Document schema')

    field_args = field_args or {}

    # Find properties
    properties = sorted(((k, v) for k, v in iteritems(model._fields)),
                        key=lambda v: v[1].creation_counter)

    if only:
        props = dict(properties)

        def find(name):
            if extra_fields and name in extra_fields:
                return FieldPlaceholder(extra_fields[name])

            p = props.get(name)
            if p is not None:
                return p

            raise ValueError('Invalid model property name %s.%s' % (model, name))

        properties = ((p, find(p)) for p in only)
    elif exclude:
        properties = (p for p in properties if p[0] not in exclude)

    # Create fields
    field_dict = {}
    for name, p in properties:
        field = converter.convert(model, p, field_args.get(name))
        if field is not None:
            field_dict[name] = field

    # Contribute extra fields
    if not only and extra_fields:
        for name, field in iteritems(extra_fields):
            field_dict[name] = form.recreate_field(field)

    field_dict['model_class'] = model
    return type(model.__name__ + 'Form', (base_class,), field_dict)
Example #8
0
def get_form(model, converter,
             base_class=form.BaseForm,
             only=None,
             exclude=None,
             field_args=None,
             hidden_pk=False,
             ignore_hidden=True,
             extra_fields=None):
    """
        Generate form from the model.

        :param model:
            Model to generate form from
        :param converter:
            Converter class to use
        :param base_class:
            Base form class
        :param only:
            Include fields
        :param exclude:
            Exclude fields
        :param field_args:
            Dictionary with additional field arguments
        :param hidden_pk:
            Generate hidden field with model primary key or not
        :param ignore_hidden:
            If set to True (default), will ignore properties that start with underscore
    """

    # TODO: Support new 0.8 API
    if not hasattr(model, '_sa_class_manager'):
        raise TypeError('model must be a sqlalchemy mapped model')

    mapper = model._sa_class_manager.mapper
    field_args = field_args or {}

    properties = ((p.key, p) for p in mapper.iterate_properties)

    if only:
        props = dict(properties)

        def find(name):
            # If field is in extra_fields, it has higher priority
            if extra_fields and name in extra_fields:
                return FieldPlaceholder(extra_fields[name])

            # Try to look it up in properties list first
            p = props.get(name)

            if p is not None:
                return p

            # If it is hybrid property or alias, look it up in a model itself
            p = getattr(model, name, None)
            if p is not None and hasattr(p, 'property'):
                return p.property

            raise ValueError('Invalid model property name %s.%s' % (model, name))

        # Filter properties while maintaining property order in 'only' list
        properties = ((x, find(x)) for x in only)
    elif exclude:
        properties = (x for x in properties if x[0] not in exclude)

    field_dict = {}
    for name, p in properties:
        # Ignore protected properties
        if ignore_hidden and name.startswith('_'):
            continue

        prop = _resolve_prop(p)

        field = converter.convert(model, mapper, prop, field_args.get(name), hidden_pk)
        if field is not None:
            field_dict[name] = field

    # Contribute extra fields
    if not only and extra_fields:
        for name, field in iteritems(extra_fields):
            field_dict[name] = form.recreate_field(field)

    return type(model.__name__ + 'Form', (base_class, ), field_dict)
Example #9
0
    def convert(self, model, mapper, prop, field_args, hidden_pk):
        # Properly handle forced fields
        if isinstance(prop, FieldPlaceholder):
            return form.recreate_field(prop.field)

        kwargs = {
            'validators': [],
            'filters': []
        }

        if field_args:
            kwargs.update(field_args)

        # Check if it is relation or property
        if hasattr(prop, 'direction'):
            return self._convert_relation(prop, kwargs)
        else:
            # Ignore pk/fk
            if hasattr(prop, 'columns'):
                # Check if more than one column mapped to the property
                if len(prop.columns) > 1:
                    columns = filter_foreign_columns(model.__table__, prop.columns)

                    if len(columns) > 1:
                        raise TypeError('Can not convert multiple-column properties (%s.%s)' % (model, prop.key))

                    column = columns[0]
                else:
                    # Grab column
                    column = prop.columns[0]

                form_columns = getattr(self.view, 'form_columns', None) or ()

                # Do not display foreign keys - use relations, except when explicitly instructed
                if column.foreign_keys and prop.key not in form_columns:
                    return None

                # Only display "real" columns
                if not isinstance(column, Column):
                    return None

                unique = False

                if column.primary_key:
                    if hidden_pk:
                        # If requested to add hidden field, show it
                        return fields.HiddenField()
                    else:
                        # By default, don't show primary keys either
                        # If PK is not explicitly allowed, ignore it
                        if prop.key not in form_columns:
                            return None

                        # Current Unique Validator does not work with multicolumns-pks
                        if not has_multiple_pks(model):
                            kwargs['validators'].append(Unique(self.session,
                                                               model,
                                                               column))
                            unique = True

                # If field is unique, validate it
                if column.unique and not unique:
                    kwargs['validators'].append(Unique(self.session,
                                                       model,
                                                       column))

                optional_types = getattr(self.view, 'form_optional_types', (Boolean,))

                if not column.nullable and not isinstance(column.type, optional_types):
                    kwargs['validators'].append(validators.InputRequired())

                # Apply label and description if it isn't inline form field
                if self.view.model == mapper.class_:
                    kwargs['label'] = self._get_label(prop.key, kwargs)
                    kwargs['description'] = self._get_description(prop.key, kwargs)

                # Figure out default value
                default = getattr(column, 'default', None)
                value = None

                if default is not None:
                    value = getattr(default, 'arg', None)

                    if value is not None:
                        if getattr(default, 'is_callable', False):
                            value = lambda: default.arg(None)
                        else:
                            if not getattr(default, 'is_scalar', True):
                                value = None

                if value is not None:
                    kwargs['default'] = value

                # Check nullable
                if column.nullable:
                    kwargs['validators'].append(validators.Optional())

                # Override field type if necessary
                override = self._get_field_override(prop.key)
                if override:
                    return override(**kwargs)

                # Check choices
                form_choices = getattr(self.view, 'form_choices', None)

                if mapper.class_ == self.view.model and form_choices:
                    choices = form_choices.get(column.key)
                    if choices:
                        return form.Select2Field(
                            choices=choices,
                            allow_blank=column.nullable,
                            **kwargs
                        )

                # Run converter
                converter = self.get_converter(column)

                if converter is None:
                    return None

                return converter(model=model, mapper=mapper, prop=prop,
                                 column=column, field_args=kwargs)

        return None
Example #10
0
def get_form(model,
             converter,
             base_class=form.BaseForm,
             only=None,
             exclude=None,
             field_args=None,
             hidden_pk=False,
             ignore_hidden=True,
             extra_fields=None):
    """
        Generate form from the model.

        :param model:
            Model to generate form from
        :param converter:
            Converter class to use
        :param base_class:
            Base form class
        :param only:
            Include fields
        :param exclude:
            Exclude fields
        :param field_args:
            Dictionary with additional field arguments
        :param hidden_pk:
            Generate hidden field with model primary key or not
        :param ignore_hidden:
            If set to True (default), will ignore properties that start with underscore
    """

    # TODO: Support new 0.8 API
    if not hasattr(model, '_sa_class_manager'):
        raise TypeError('model must be a sqlalchemy mapped model')

    mapper = model._sa_class_manager.mapper
    field_args = field_args or {}

    properties = ((p.key, p) for p in mapper.iterate_properties)

    if only:
        props = dict(properties)

        def find(name):
            # If field is in extra_fields, it has higher priority
            if extra_fields and name in extra_fields:
                return FieldPlaceholder(extra_fields[name])

            # Try to look it up in properties list first
            p = props.get(name)

            if p is not None:
                return p

            # If it is hybrid property or alias, look it up in a model itself
            p = getattr(model, name, None)
            if p is not None and hasattr(p, 'property'):
                return p.property

            raise ValueError('Invalid model property name %s.%s' %
                             (model, name))

        # Filter properties while maintaining property order in 'only' list
        properties = ((x, find(x)) for x in only)
    elif exclude:
        properties = (x for x in properties if x[0] not in exclude)

    field_dict = {}
    for name, p in properties:
        # Ignore protected properties
        if ignore_hidden and name.startswith('_'):
            continue

        prop = _resolve_prop(p)

        field = converter.convert(model, mapper, prop, field_args.get(name),
                                  hidden_pk)
        if field is not None:
            field_dict[name] = field

    # Contribute extra fields
    if not only and extra_fields:
        for name, field in iteritems(extra_fields):
            field_dict[name] = form.recreate_field(field)

    return type(model.__name__ + 'Form', (base_class, ), field_dict)
Example #11
0
    def convert(self, model, mapper, prop, field_args, hidden_pk):
        # Properly handle forced fields
        if isinstance(prop, FieldPlaceholder):
            return form.recreate_field(prop.field)

        kwargs = {'validators': [], 'filters': []}

        if field_args:
            kwargs.update(field_args)

        # Check if it is relation or property
        if hasattr(prop, 'direction'):
            return self._convert_relation(prop, kwargs)
        else:
            # Ignore pk/fk
            if hasattr(prop, 'columns'):
                # Check if more than one column mapped to the property
                if len(prop.columns) != 1:
                    if is_inherited_primary_key(prop):
                        column = get_column_for_current_model(prop)
                    else:
                        raise TypeError(
                            'Can not convert multiple-column properties (%s.%s)'
                            % (model, prop.key))
                else:
                    # Grab column
                    column = prop.columns[0]

                form_columns = getattr(self.view, 'form_columns', None) or ()

                # Do not display foreign keys - use relations, except when explicitly instructed
                if column.foreign_keys and prop.key not in form_columns:
                    return None

                # Only display "real" columns
                if not isinstance(column, Column):
                    return None

                unique = False

                if column.primary_key:
                    if hidden_pk:
                        # If requested to add hidden field, show it
                        return fields.HiddenField()
                    else:
                        # By default, don't show primary keys either
                        # If PK is not explicitly allowed, ignore it
                        if prop.key not in form_columns:
                            return None

                        # Current Unique Validator does not work with multicolumns-pks
                        if not has_multiple_pks(model):
                            kwargs['validators'].append(
                                Unique(self.session, model, column))
                            unique = True

                # If field is unique, validate it
                if column.unique and not unique:
                    kwargs['validators'].append(
                        Unique(self.session, model, column))

                optional_types = getattr(self.view, 'form_optional_types',
                                         (Boolean, ))

                if not column.nullable and not isinstance(
                        column.type, optional_types):
                    kwargs['validators'].append(validators.InputRequired())

                # Apply label and description if it isn't inline form field
                if self.view.model == mapper.class_:
                    kwargs['label'] = self._get_label(prop.key, kwargs)
                    kwargs['description'] = self._get_description(
                        prop.key, kwargs)

                # Figure out default value
                default = getattr(column, 'default', None)
                value = None

                if default is not None:
                    value = getattr(default, 'arg', None)

                    if value is not None:
                        if getattr(default, 'is_callable', False):
                            value = lambda: default.arg(None)
                        else:
                            if not getattr(default, 'is_scalar', True):
                                value = None

                if value is not None:
                    kwargs['default'] = value

                # Check nullable
                if column.nullable:
                    kwargs['validators'].append(validators.Optional())

                # Override field type if necessary
                override = self._get_field_override(prop.key)
                if override:
                    return override(**kwargs)

                # Check choices
                form_choices = getattr(self.view, 'form_choices', None)

                if mapper.class_ == self.view.model and form_choices:
                    choices = form_choices.get(column.key)
                    if choices:
                        return Select2Field(choices=choices,
                                            allow_blank=column.nullable,
                                            **kwargs)

                # Run converter
                converter = self.get_converter(column)

                if converter is None:
                    return None

                return converter(model=model,
                                 mapper=mapper,
                                 prop=prop,
                                 column=column,
                                 field_args=kwargs)

        return None
Example #12
0
    def convert(self, model, mapper, prop, field_args, hidden_pk):
        # Properly handle forced fields
        if isinstance(prop, FieldPlaceholder):
            return form.recreate_field(prop.field)

        kwargs = {
            'validators': [],
            'filters': []
        }

        if field_args:
            kwargs.update(field_args)

        # Check if it is relation or property
        if hasattr(prop, 'direction'):
            remote_model = prop.mapper.class_
            local_column = prop.local_remote_pairs[0][0]

            kwargs['label'] = self._get_label(prop.key, kwargs)
            kwargs['description'] = self._get_description(prop.key, kwargs)

            if local_column.nullable:
                kwargs['validators'].append(validators.Optional())
            elif prop.direction.name != 'MANYTOMANY':
                kwargs['validators'].append(validators.InputRequired())

            # Override field type if necessary
            override = self._get_field_override(prop.key)
            if override:
                return override(**kwargs)

            # Contribute model-related parameters
            if 'allow_blank' not in kwargs:
                kwargs['allow_blank'] = local_column.nullable
            if 'query_factory' not in kwargs:
                kwargs['query_factory'] = lambda: self.session.query(remote_model)

            if prop.direction.name == 'MANYTOONE':
                return QuerySelectField(widget=form.Select2Widget(),
                                        **kwargs)
            elif prop.direction.name == 'ONETOMANY':
                # Skip backrefs
                if not local_column.foreign_keys and getattr(self.view, 'column_hide_backrefs', False):
                    return None

                return QuerySelectMultipleField(
                                widget=form.Select2Widget(multiple=True),
                                **kwargs)
            elif prop.direction.name == 'MANYTOMANY':
                return QuerySelectMultipleField(
                                widget=form.Select2Widget(multiple=True),
                                **kwargs)
        else:
            # Ignore pk/fk
            if hasattr(prop, 'columns'):
                # Check if more than one column mapped to the property
                if len(prop.columns) != 1:
                    raise TypeError('Can not convert multiple-column properties (%s.%s)' % (model, prop.key))

                # Grab column
                column = prop.columns[0]

                # Do not display foreign keys - use relations
                if column.foreign_keys:
                    return None

                # Only display "real" columns
                if not isinstance(column, Column):
                    return None

                unique = False

                if column.primary_key:
                    if hidden_pk:
                        # If requested to add hidden field, show it
                        return fields.HiddenField()
                    else:
                        # By default, don't show primary keys either
                        form_columns = getattr(self.view, 'form_columns', None)

                        if form_columns is None:
                            return None

                        # If PK is not explicitly allowed, ignore it
                        if prop.key not in form_columns:
                            return None

                        kwargs['validators'].append(Unique(self.session,
                                                           model,
                                                           column))
                        unique = True

                # If field is unique, validate it
                if column.unique and not unique:
                    kwargs['validators'].append(Unique(self.session,
                                                       model,
                                                       column))

                if not column.nullable and not isinstance(column.type, Boolean):
                    kwargs['validators'].append(validators.InputRequired())

                # Apply label and description if it isn't inline form field
                if self.view.model == mapper.class_:
                    kwargs['label'] = self._get_label(prop.key, kwargs)
                    kwargs['description'] = self._get_description(prop.key, kwargs)

                # Figure out default value
                default = getattr(column, 'default', None)
                value = None

                if default is not None:
                    value = getattr(default, 'arg', None)

                    if value is not None:
                        if getattr(default, 'is_callable', False):
                            value = lambda: default.arg(None)
                        else:
                            if not getattr(default, 'is_scalar', True):
                                value = None

                if value is not None:
                    kwargs['default'] = value

                # Check nullable
                if column.nullable:
                    kwargs['validators'].append(validators.Optional())

                # Override field type if necessary
                override = self._get_field_override(prop.key)
                if override:
                    return override(**kwargs)

                # Check choices
                if mapper.class_ == self.view.model and self.view.form_choices:
                    choices = self.view.form_choices.get(column.key)
                    if choices:
                        return Select2Field(
                            choices=choices,
                            allow_blank=column.nullable,
                            **kwargs
                        )

                # Run converter
                converter = self.get_converter(column)

                if converter is None:
                    return None

                return converter(model=model, mapper=mapper, prop=prop,
                                column=column, field_args=kwargs)

        return None