def handle_field(field, subdoc, base): ftype = type(field).__name__ if ftype == 'ListField' or ftype == 'SortedListField': 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 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 __init__( self, model, data=None, 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 = [] if data is None: self.all_models = {1: Model(1), 2: Model(2)} else: self.all_models = data self.last_id = len(self.all_models) + 1
def create_editable_list_form(form_base_class, form_class, widget=None): """ 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 widget: WTForms widget class. Defaults to `XEditableWidget`. """ if widget is None: widget = XEditableWidget() class ListForm(form_base_class): list_form_pk = HiddenField(validators=[InputRequired()]) # iterate FormMeta to get unbound fields, replace widget, copy to ListForm for name, obj in iteritems(form_class.__dict__): if isinstance(obj, UnboundField): obj.kwargs['widget'] = widget setattr(ListForm, name, obj) if name == "list_form_pk": raise Exception('Form already has a list_form_pk column.') return ListForm
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, model, field_name): inline_model = getattr(model, field_name, None) is_created = False form_is_empty = True if not inline_model: is_created = True inline_model = self.model() # iterate all inline form fields and fill model for name, field in iteritems(self.form._fields): if name != self._pk: field.populate_obj(inline_model, name) if form_is_empty and not self._looks_empty(field.data): form_is_empty = False # don't create inline model if perhaps one field was not filled if form_is_empty: return # set for our model updated inline model setattr(model, field_name, inline_model) # save results self.inline_view.on_model_change(self.form, model, is_created)
def process(self, formdata, data=unset_value): """ SQLAlchemy returns a dict for HSTORE columns, but WTForms cannot process a dict. This overrides `process` to convert the dict returned by SQLAlchemy to a list of classes before processing. """ if isinstance(data, dict): data = [KeyValue(k, v) for k, v in iteritems(data)] super(InlineHstoreList, self).process(formdata, data)
def populate_obj(self, obj, name): string_pk_models = getattr(self, 'string_pk_models', None) check_for_pk = True if string_pk_models and any([x for x in string_pk_models if isinstance(obj, x)]): check_for_pk = False for name, field in iteritems(self.form._fields): if not check_for_pk or name != self._pk: field.populate_obj(obj, name)
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 __init__(self, model, name=None, category=None, endpoint=None, url=None, **kwargs): for k, v in iteritems(kwargs): setattr(self, k, v) super(CustomModelView, self).__init__(model, 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' % (model, name)) handle_field(field, doc, make_name(base, name))
def get_list_form(self): if self.form_args: 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( ToggleInlineWidget(self.column_toggle_control_list, self.toggle_control_options), validators)
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 handle_subdoc(model, subdoc, base): documents = getattr(subdoc, "_form_subdocuments", {}) for name, doc in iteritems(documents): if name.endswith("__field"): name = name[:-7] field = getattr(model, name, None) if not field: raise ValueError("Invalid subdocument field %s.%s" % (model, name)) handle_field(field, doc, make_name(base, name))
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_admin.contrib.mongoengine.EmbeddedForm, got %s' % type(p)) return result
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_admin.contrib.mongoengine.EmbeddedForm, got %s' % type(p)) return result
def process_ajax_refs(self, info): refs = getattr(info, 'form_ajax_refs', None) result = {} if refs: for name, opts in iteritems(refs): loader = None if isinstance(opts, dict): loader = create_ajax_loader(info.model, name, name, opts) else: loader = opts result[name] = loader self.view._form_ajax_refs[name] = loader 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 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 get_form(model, converter, base_class=form.BaseForm, only=None, exclude=None, field_args=None, extra_fields=None): field_args = field_args or {} # Find properties properties = sorted(((v.name, v) for v in model._meta.fields)) 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 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, 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 enum_create_editable_list_form(form_base_class, form_class, widget=None): if widget is None: widget = EnumEnabledXEditableWidget() # Modification class ListForm(form_base_class): list_form_pk = HiddenField(validators=[InputRequired()]) # iterate FormMeta to get unbound fields, replace widget, copy to ListForm for name, obj in iteritems(form_class.__dict__): if isinstance(obj, UnboundField): if name == 'status': # Modification obj.kwargs['widget'] = StatusEnumEnabledXEditableWidget() else: obj.kwargs['widget'] = widget setattr(ListForm, name, obj) if name == "list_form_pk": raise Exception('Form already has a list_form_pk column.') return ListForm
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_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 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: def find(name): # If field is in extra_fields, it has higher priority if extra_fields and name in extra_fields: return name, FieldPlaceholder(extra_fields[name]) column, path = get_field_with_path(model, name, return_remote_proxy_attr=False) if path and not (is_relationship(column) or is_association_proxy(column)): raise Exception("form column is located in another table and " "requires inline_models: {0}".format(name)) if is_association_proxy(column): return name, column relation_name = column.key if column is not None and hasattr(column, 'property'): return relation_name, column.property raise ValueError('Invalid model property name %s.%s' % (model, name)) # Filter properties while maintaining property order in 'only' list properties = (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, name, 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 populate_obj(self, obj, name): for name, field in iteritems(self.form._fields): if field.type != self.hidden_field_type: field.populate_obj(obj, name)
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 get_form(model, 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_mongoengine.wtf import model_form from myproject.myapp.schemas import Article ArticleForm = model_form(Article) :param model: An RDFAlchemy 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, rdfalchemy.rdfSubject): # raise TypeError('Model must be an RDFAlchemy rdf subject') field_args = field_args or {} # Find properties properties = list(model._sortable_columns.items()) 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 = {"type":TypeField(rel=model.clResource, choice_graph=model.clResource.graph)} for name, p in properties: field = get_field(model, p, name, 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_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 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: def find(name): # If field is in extra_fields, it has higher priority if extra_fields and name in extra_fields: return name, FieldPlaceholder(extra_fields[name]) column, path = get_field_with_path(model, name) if path and not hasattr(column.prop, 'direction'): raise Exception("form column is located in another table and " "requires inline_models: {0}".format(name)) name = column.key if column is not None and hasattr(column, 'property'): return name, column.property raise ValueError('Invalid model property name %s.%s' % (model, name)) # Filter properties while maintaining property order in 'only' list properties = (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 _get_model_fields(self, model=None): if model is None: model = self.model return iteritems(model._meta.fields)
def flash_errors(form, message): from flask_admin.babel import gettext 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 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_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 isinstance(model, str): model = get_document(model) 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)