Commit f2698add authored by Serge S. Koval's avatar Serge S. Koval

Merge pull request #815 from larkin/remove-hidden-fields

remove not-visible fields from forms
parents 8db79a06 41eca951
...@@ -25,6 +25,13 @@ class BaseRule(object): ...@@ -25,6 +25,13 @@ class BaseRule(object):
self.rule_set = rule_set self.rule_set = rule_set
return self return self
@property
def visible_fields(self):
"""
A list of visible fields for the given rule.
"""
raise NotImplementedError()
def __call__(self, form, form_opts=None, field_args={}): def __call__(self, form, form_opts=None, field_args={}):
""" """
Render rule. Render rule.
...@@ -68,6 +75,17 @@ class NestedRule(BaseRule): ...@@ -68,6 +75,17 @@ class NestedRule(BaseRule):
self.rules = rule_set.configure_rules(self.rules, self) self.rules = rule_set.configure_rules(self.rules, self)
return super(NestedRule, self).configure(rule_set, parent) return super(NestedRule, self).configure(rule_set, parent)
@property
def visible_fields(self):
"""
Return visible fields for all child rules.
"""
visible_fields = []
for rule in self.rules:
for field in rule.visible_fields:
visible_fields.append(field)
return visible_fields
def __iter__(self): def __iter__(self):
""" """
Return rules. Return rules.
...@@ -111,6 +129,10 @@ class Text(BaseRule): ...@@ -111,6 +129,10 @@ class Text(BaseRule):
self.text = text self.text = text
self.escape = escape self.escape = escape
@property
def visible_fields(self):
return []
def __call__(self, form, form_opts=None, field_args={}): def __call__(self, form, form_opts=None, field_args={}):
if self.escape: if self.escape:
return self.text return self.text
...@@ -168,6 +190,10 @@ class Macro(BaseRule): ...@@ -168,6 +190,10 @@ class Macro(BaseRule):
return field return field
@property
def visible_fields(self):
return []
def __call__(self, form, form_opts=None, field_args={}): def __call__(self, form, form_opts=None, field_args={}):
""" """
Render macro rule. Render macro rule.
...@@ -220,6 +246,10 @@ class Container(Macro): ...@@ -220,6 +246,10 @@ class Container(Macro):
self.child_rule.configure(rule_set, self) self.child_rule.configure(rule_set, self)
return super(Container, self).configure(rule_set, parent) return super(Container, self).configure(rule_set, parent)
@property
def visible_fields(self):
return self.child_rule.visible_fields
def __call__(self, form, form_opts=None, field_args={}): def __call__(self, form, form_opts=None, field_args={}):
""" """
Render container. Render container.
...@@ -258,6 +288,10 @@ class Field(Macro): ...@@ -258,6 +288,10 @@ class Field(Macro):
super(Field, self).__init__(render_field) super(Field, self).__init__(render_field)
self.field_name = field_name self.field_name = field_name
@property
def visible_fields(self):
return [self.field_name]
def __call__(self, form, form_opts=None, field_args={}): def __call__(self, form, form_opts=None, field_args={}):
""" """
Render field. Render field.
...@@ -345,6 +379,14 @@ class RuleSet(object): ...@@ -345,6 +379,14 @@ class RuleSet(object):
self.view = view self.view = view
self.rules = self.configure_rules(rules) self.rules = self.configure_rules(rules)
@property
def visible_fields(self):
visible_fields = []
for rule in self.rules:
for field in rule.visible_fields:
visible_fields.append(field)
return visible_fields
def convert_string(self, value): def convert_string(self, value):
""" """
Convert string to rule. Convert string to rule.
......
...@@ -5,6 +5,7 @@ from flask import (request, redirect, flash, abort, json, Response, ...@@ -5,6 +5,7 @@ from flask import (request, redirect, flash, abort, json, Response,
get_flashed_messages) get_flashed_messages)
from jinja2 import contextfunction from jinja2 import contextfunction
from wtforms.fields import HiddenField from wtforms.fields import HiddenField
from wtforms.fields.core import UnboundField
from wtforms.validators import ValidationError, Required from wtforms.validators import ValidationError, Required
from flask_admin.babel import gettext from flask_admin.babel import gettext
...@@ -685,6 +686,10 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -685,6 +686,10 @@ class BaseModelView(BaseView, ActionsMixin):
# Form rendering rules # Form rendering rules
self._refresh_form_rules_cache() self._refresh_form_rules_cache()
# Process form rules
self._validate_form_class(self._form_edit_rules, self._edit_form_class)
self._validate_form_class(self._form_create_rules, self._create_form_class)
# Primary key # Primary key
def get_pk_value(self, model): def get_pk_value(self, model):
""" """
...@@ -1001,6 +1006,51 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -1001,6 +1006,51 @@ class BaseModelView(BaseView, ActionsMixin):
""" """
return validate_form_on_submit(form) return validate_form_on_submit(form)
def _get_ruleset_missing_fields(self, ruleset, form):
missing_fields = []
if ruleset:
visible_fields = ruleset.visible_fields
for field in form:
if field.name not in visible_fields:
missing_fields.append(field.name)
return missing_fields
def _validate_form_class(self, ruleset, form_class, remove_missing=True):
form_fields = []
for name, obj in iteritems(form_class.__dict__):
if isinstance(obj, UnboundField):
form_fields.append(name)
missing_fields = []
if ruleset:
visible_fields = ruleset.visible_fields
for field_name in form_fields:
if field_name not in visible_fields:
missing_fields.append(field_name)
if missing_fields:
warnings.warn('Fields missing from ruleset: %s' % (','.join(missing_fields)))
if remove_missing:
self._remove_fields_from_form_class(missing_fields, form_class)
def _validate_form_instance(self, ruleset, form, remove_missing=True):
missing_fields = self._get_ruleset_missing_fields(ruleset=ruleset, form=form)
if missing_fields:
warnings.warn('Fields missing from ruleset: %s' % (','.join(missing_fields)))
if remove_missing:
self._remove_fields_from_form_instance(missing_fields, form)
def _remove_fields_from_form_instance(self, field_names, form):
for field_name in field_names:
form.__delitem__(field_name)
def _remove_fields_from_form_class(self, field_names, form_class):
for field_name in field_names:
delattr(form_class, field_name)
# Helpers # Helpers
def is_sortable(self, name): def is_sortable(self, name):
""" """
...@@ -1477,6 +1527,8 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -1477,6 +1527,8 @@ class BaseModelView(BaseView, ActionsMixin):
return redirect(return_url) return redirect(return_url)
form = self.create_form() form = self.create_form()
if not hasattr(form, '_validated_ruleset') or not form._validated_ruleset:
self._validate_form_instance(ruleset=self._form_create_rules, form=form)
if self.validate_form(form): if self.validate_form(form):
if self.create_model(form): if self.create_model(form):
...@@ -1514,6 +1566,8 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -1514,6 +1566,8 @@ class BaseModelView(BaseView, ActionsMixin):
return redirect(return_url) return redirect(return_url)
form = self.edit_form(obj=model) form = self.edit_form(obj=model)
if not hasattr(form, '_validated_ruleset') or not form._validated_ruleset:
self._validate_form_instance(ruleset=self._form_create_rules, form=form)
if self.validate_form(form): if self.validate_form(form):
if self.update_model(form, model): if self.update_model(form, model):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment