def wrap_fields_in_fieldlist(form_base_class, form_class, CustomFieldList): """ Create a form class with all the fields wrapped in a FieldList. Wrapping each field in FieldList allows submitting POST requests in this format: ('<field_name>-<primary_key>', '<value>') Used in the editable list view. :param form_base_class: WTForms form class, by default `form_base_class` from base. :param form_class: WTForms form class generated by `form.get_form`. :param CustomFieldList: WTForms FieldList class. By default, `CustomFieldList` is `ListEditableFieldList`. """ class FieldListForm(form_base_class): pass # iterate FormMeta to get unbound fields for name, obj in iteritems(form_class.__dict__): if isinstance(obj, UnboundField): # wrap field in a WTForms FieldList setattr(FieldListForm, name, CustomFieldList(obj)) return FieldListForm
def handle_field(field, subdoc, base): ftype = type(field).__name__ if ftype == 'ListField': child_doc = getattr(subdoc, '_form_subdocuments', {}).get(None) if child_doc: handle_field(field.field, child_doc, base) elif ftype == 'EmbeddedDocumentField': result = {} ajax_refs = getattr(subdoc, 'form_ajax_refs', {}) for field_name, opts in iteritems(ajax_refs): child_name = make_name(base, field_name) if isinstance(opts, dict): loader = create_ajax_loader(field.document_type_obj, child_name, field_name, opts) else: loader = opts result[field_name] = loader references[child_name] = loader subdoc._form_ajax_refs = result child_doc = getattr(subdoc, '_form_subdocuments', None) if child_doc: handle_subdoc(field.document_type_obj, subdoc, base) else: raise ValueError('Failed to process subdocument field %s' % (field,))
def handle_field(field, subdoc, base): ftype = type(field).__name__ if ftype == 'ListField': child_doc = getattr(subdoc, '_form_subdocuments', {}).get(None) if child_doc: handle_field(field.field, child_doc, base) elif ftype == 'EmbeddedDocumentField': result = {} ajax_refs = getattr(subdoc, 'form_ajax_refs', {}) for field_name, opts in iteritems(ajax_refs): child_name = make_name(base, field_name) if isinstance(opts, dict): loader = create_ajax_loader(field.document_type_obj, child_name, field_name, opts) else: loader = opts result[field_name] = loader references[child_name] = loader subdoc._form_ajax_refs = result child_doc = getattr(subdoc, '_form_subdocuments', None) if child_doc: handle_subdoc(field.document_type_obj, subdoc, base) else: raise ValueError('Failed to process subdocument field %s' % (field, ))
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
def __init__(self, model, session, name=None, category=None, endpoint=None, url=None, **kwargs): for k, v in iteritems(kwargs): setattr(self, k, v) super(CustomModelView, self).__init__(model, session, name, category, endpoint, url)
def handle_subdoc(model, subdoc, base): documents = getattr(subdoc, '_form_subdocuments', {}) for name, doc in iteritems(documents): field = getattr(model, name, None) if not field: raise ValueError('Invalid subdocument field %s.%s') handle_field(field, doc, make_name(base, name))
def _get_model_fields(self, model=None): """ Inspect model and return list of model fields :param model: Model to inspect """ if model is None: model = self.model return sorted(iteritems(model._fields), key=lambda n: n[1].creation_counter)
def convert_subdocuments(values): result = {} for name, p in iteritems(values): if isinstance(p, dict): result[name] = EmbeddedForm(**p) elif isinstance(p, EmbeddedForm): result[name] = p else: raise ValueError('Invalid subdocument type: expecting dict or instance of flask.ext.admin.contrib.mongoengine.EmbeddedForm, got %s' % type(p)) return result
def __init__(self, **kwargs): """ Constructor :param kwargs: Additional options """ for k in self._defaults: if not hasattr(self, k): setattr(self, k, None) for k, v in iteritems(kwargs): setattr(self, k, v)
def convert_subdocuments(values): result = {} for name, p in iteritems(values): if isinstance(p, dict): result[name] = EmbeddedForm(**p) elif isinstance(p, EmbeddedForm): result[name] = p else: raise ValueError( 'Invalid subdocument type: expecting dict or instance of flask.ext.admin.contrib.mongoengine.EmbeddedForm, got %s' % type(p)) return result
def __init__(self, model, name=None, category=None, endpoint=None, url=None, **kwargs): # Allow to set any attributes from parameters for k, v in iteritems(kwargs): setattr(self, k, v) super(MockModelView, self).__init__(model, name, category, endpoint, url) self.created_models = [] self.updated_models = [] self.deleted_models = [] self.search_arguments = [] self.all_models = {1: Model(1), 2: Model(2)} self.last_id = 3
def __init__(self, model, **kwargs): """ Constructor :param model: Target model class :param kwargs: Additional options """ self.model = model for k in self._defaults: if not hasattr(self, k): setattr(self, k, None) for k, v in iteritems(kwargs): setattr(self, k, v)
def _process_ajax_references(self): """ Process `form_ajax_refs` and generate model loaders that will be used by the `ajax_lookup` view. """ result = {} if self.form_ajax_refs: for name, options in iteritems(self.form_ajax_refs): if isinstance(options, dict): result[name] = self._create_ajax_loader(name, options) elif isinstance(options, AjaxModelLoader): result[name] = options else: raise ValueError('%s.form_ajax_refs can not handle %s types' % (self, type(options))) return result
def process_ajax_refs(self, info): refs = getattr(info, "form_ajax_refs", None) result = {} if refs: for name, opts in iteritems(refs): new_name = "%s-%s" % (info.model.__name__.lower(), name) loader = None if isinstance(opts, dict): loader = create_ajax_loader(info.model, self.session, new_name, name, opts) else: loader = opts result[name] = loader self.view._form_ajax_refs[new_name] = loader return result
def process_ajax_refs(self, info): refs = getattr(info, 'form_ajax_refs', None) result = {} if refs: for name, opts in iteritems(refs): new_name = '%s.%s' % (info.model.__name__.lower(), name) loader = None if isinstance(opts, (list, tuple)): loader = create_ajax_loader(info.model, new_name, name, opts) else: loader = opts result[name] = loader self.view._form_ajax_refs[new_name] = loader return result
def process_ajax_refs(self, info): refs = getattr(info, 'form_ajax_refs', None) result = {} if refs: for name, opts in iteritems(refs): new_name = '%s-%s' % (info.model.__name__.lower(), name) loader = None if isinstance(opts, dict): loader = create_ajax_loader(info.model, self.session, new_name, name, opts) else: loader = opts result[name] = loader self.view._form_ajax_refs[new_name] = loader return result
def __init__(self, **kwargs): """ Constructor :param kwargs: Additional options """ for k in self._defaults: if not hasattr(self, k): setattr(self, k, None) for k, v in iteritems(kwargs): setattr(self, k, v) # Convert form rules form_rules = getattr(self, 'form_rules', None) if form_rules: self._form_rules = rules.RuleSet(self, form_rules) else: self._form_rules = None
def get_list_form(self): """ Get form class for the editable list view. Uses only validators from `form_args` to build the form class. Allows overriding the editable list view field/widget. For example:: from flask.ext.admin.model.fields import ListEditableFieldList from flask.ext.admin.model.widgets import XEditableWidget class CustomWidget(XEditableWidget): def get_kwargs(self, subfield, kwargs): if subfield.type == 'TextAreaField': kwargs['data-type'] = 'textarea' kwargs['data-rows'] = '20' # elif: kwargs for other fields return kwargs class CustomFieldList(ListEditableFieldList): widget = CustomWidget() class MyModelView(BaseModelView): def get_list_form(self): return self.scaffold_list_form(CustomFieldList) """ if self.form_args: # get only validators, other form_args can break FieldList wrapper validators = dict( (key, {"validators": value["validators"]}) for key, value in iteritems(self.form_args) if value.get("validators") ) else: validators = None return self.scaffold_list_form(validators=validators)
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
def populate_obj(self, obj, name): for name, field in iteritems(self.form._fields): if name != self._pk: field.populate_obj(obj, name)
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)
def _get_filter_dict(self): """ Return flattened filter dictionary which can be JSON-serialized. """ return dict( (as_unicode(k), v) for k, v in iteritems(self._filter_dict))
def _get_filter_dict(self): """ Return flattened filter dictionary which can be JSON-serialized. """ return dict((as_unicode(k), v) for k, v in iteritems(self._filter_dict))
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)
def flash_errors(form, message): for field_name, errors in iteritems(form.errors): errors = form[field_name].label.text + u": " + u", ".join(errors) flash(gettext(message, error=str(errors)), 'error')
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)
def _get_model_fields(self, model=None): if model is None: model = self.model return iteritems(model._fields)