Source code for wtforms_alchemy

import six
import sqlalchemy as sa
from wtforms import Form
from wtforms.form import FormMeta
from wtforms.validators import (
    DataRequired,
    InputRequired,
    Length,
    NumberRange,
    Optional,
    URL
)
from wtforms_components import DateRange, Email, TimeRange

from .exc import (
    AttributeTypeException,
    InvalidAttributeException,
    UnknownConfigurationOption,
    UnknownTypeException
)
from .fields import (  # noqa
    CountryField,
    GroupedQuerySelectField,
    GroupedQuerySelectMultipleField,
    ModelFieldList,
    ModelFormField,
    PhoneNumberField,
    QuerySelectField,
    QuerySelectMultipleField,
    WeekDaysField
)
from .generator import FormGenerator
from .utils import (
    ClassMap,
    is_date_column,
    is_scalar,
    null_or_int,
    null_or_unicode
)
from .validators import Unique  # noqa

__all__ = (
    AttributeTypeException,
    CountryField,
    DateRange,
    InvalidAttributeException,
    ModelFieldList,
    ModelFormField,
    PhoneNumberField,
    Unique,
    UnknownTypeException,
    is_date_column,
    is_scalar,
    null_or_int,
    null_or_unicode,
)


__version__ = '0.16.7'


[docs]def model_form_meta_factory(base=FormMeta): """ Create a new class usable as a metaclass for the :func:`model_form_factory`. You only need to concern yourself with this if you desire to have a custom metclass. Otherwise, a default class is created and is used as a metaclass on :func:`model_form_factory`. :param base: The base class to use for the meta class. This is an optional parameter that defaults to :class:`.FormMeta`. If you want to provide your own, your class must derive from this class and not directly from ``type``. :return: A new class suitable as a metaclass for the actual model form. Therefore, it should be passed as the ``meta`` argument to :func:`model_form_factory`. Example usage: .. code-block:: python from wtforms.form import FormMeta class MyModelFormMeta(FormMeta): # do some metaclass magic here pass ModelFormMeta = model_form_meta_factory(MyModelFormMeta) ModelForm = model_form_factory(meta=ModelFormMeta) """ class ModelFormMeta(base): """ Meta class that overrides WTForms base meta class. The primary purpose of this class is allowing ModelForms use special configuration params under the 'Meta' class namespace. ModelForm classes inherit parent's Meta class properties. """ def __init__(cls, *args, **kwargs): bases = [] for class_ in cls.__mro__: if 'Meta' in class_.__dict__: bases.append(getattr(class_, 'Meta')) if object not in bases: bases.append(object) cls.Meta = type('Meta', tuple(bases), {}) base.__init__(cls, *args, **kwargs) if hasattr(cls.Meta, 'model') and cls.Meta.model: generator = cls.Meta.form_generator(cls) generator.create_form(cls) return ModelFormMeta
ModelFormMeta = model_form_meta_factory()
[docs]def model_form_factory(base=Form, meta=ModelFormMeta, **defaults): """ Create a base class for all model forms to derive from. :param base: Class that should be used as a base for the returned class. By default, this is WTForms's base class :class:`wtforms.Form`. :param meta: A metaclass to use on this class. Normally, you do not need to provide this value, but if you want, you should check out :func:`model_form_meta_factory`. :return: A class to be used as the base class for all forms that should be connected to a SQLAlchemy model class. Additional arguments provided to the form override the default configuration as described in :ref:`custom_base`. """ class ModelForm(six.with_metaclass(meta, base)): """ Standard base-class for all forms to be combined with a model. Use :func:`model_form_factory` in case you wish to change its behavior. ``get_session``: If you want to use the Unique validator, you should define this method. If you are using Flask-SQLAlchemy along with WTForms-Alchemy you don't need to set this. If you define this in the superclass, it will not be overriden. """ if not hasattr(base, 'get_session'): get_session = None class Meta(object): model = None default = None #: Whether or not to skip unknown types. If this is set to True, #: fields with types that are not present in FormGenerator type map #: will be silently excluded from the generated form. #: #: By default this is set to False, meaning unknown types throw #: exceptions when encountered. skip_unknown_types = defaults.pop('skip_unknown_types', False) #: Whether or not to assign all fields as optional, useful when #: creating update forms for patch requests all_fields_optional = defaults.pop('all_fields_optional', False) validators = defaults.pop('validators', {}) #: A dict with keys as field names and values as field arguments. field_args = defaults.pop('field_args', {}) #: A dict with keys as field names and values as widget options. widget_options = defaults.pop('widget_options', {}) #: Whether or not to include only indexed fields. only_indexed_fields = defaults.pop('only_indexed_fields', False) #: Whether or not to include primary keys. include_primary_keys = defaults.pop('include_primary_keys', False) #: Whether or not to include foreign keys. By default this is False #: indicating that foreign keys are not included in the generated #: form. include_foreign_keys = defaults.pop('include_foreign_keys', False) #: Whether or not to strip string fields strip_string_fields = defaults.pop('strip_string_fields', False) #: Whether or not to include datetime columns that have a default #: value. A good example is created_at column which has a default #: value of datetime.utcnow. include_datetimes_with_default = defaults.pop( 'include_datetimes_with_default', False ) #: The default validator to be used for not nullable columns. Set #: this to `None` if you wish to disable it. not_null_validator = defaults.pop( 'not_null_validator', InputRequired() ) #: A dictionary that overrides not null validation on type level. #: Keys should be valid SQLAlchemy types and values should be valid #: WTForms validators. not_null_validator_type_map = defaults.pop( 'not_null_validator_type_map', ClassMap( [(sa.String, [InputRequired(), DataRequired()])] ) ) #: Default email validator email_validator = defaults.pop('email_validator', Email) #: Default length validator length_validator = defaults.pop('length_validator', Length) #: Default unique validator unique_validator = defaults.pop('unique_validator', Unique) #: Default number range validator number_range_validator = defaults.pop( 'number_range_validator', NumberRange ) #: Default date range validator date_range_validator = defaults.pop( 'date_range_validator', DateRange ) #: Default time range validator time_range_validator = defaults.pop( 'time_range_validator', TimeRange ) #: Default optional validator optional_validator = defaults.pop( 'optional_validator', Optional ) #: Default URL validator url_validator = defaults.pop('url_validator', URL) #: Which form generator to use. Only override this if you have a #: valid form generator which you want to use instead of the #: default one. form_generator = defaults.pop( 'form_generator', FormGenerator ) #: Default date format date_format = defaults.pop('date_format', '%Y-%m-%d') #: Default datetime format datetime_format = defaults.pop( 'datetime_format', '%Y-%m-%d %H:%M:%S' ) #: Dictionary of SQLAlchemy types as keys and WTForms field classes #: as values. The key value pairs of this dictionary override #: the key value pairs of FormGenerator.TYPE_MAP. #: #: Using this configuration option one can easily configure the #: type conversion in class level. type_map = defaults.pop('type_map', ClassMap()) #: Whether or not to raise InvalidAttributExceptions when invalid #: attribute names are given for include / exclude or only attr_errors = defaults.pop('attr_errors', True) #: Additional fields to include in the generated form. include = defaults.pop('include', []) #: List of fields to exclude from the generated form. exclude = defaults.pop('exclude', []) #: List of fields to only include in the generated form. only = defaults.pop('only', []) def __init__(self, *args, **kwargs): """Sets object as form attribute.""" self._obj = kwargs.get('obj', None) super(ModelForm, self).__init__(*args, **kwargs) if defaults: raise UnknownConfigurationOption( list(defaults.keys())[0] ) return ModelForm
ModelForm = model_form_factory(Form) class ModelCreateForm(ModelForm): pass class ModelUpdateForm(ModelForm): class Meta(object): all_fields_optional = True assign_required = False class ModelSearchForm(ModelForm): class Meta(object): all_fields_optional = True only_indexed_fields = True include_primary_keys = True