我遵循了这个example,但我修改了一下以适应我的项目
这就是我所拥有的:
class AgentFormValidation(object):
def __init__(self, context, request):
self.context = context
self.request = request
def __call__(self, form, value):
number = value['identity_information']['number']
print validateID(number)
type = value['identity_information']['type']
q = sqlahelper.get_session().query(Agents.id_number).filter(Agents.id_number == number).first()
if type == "IDNumber":
if not validateID(number):
if q:
exc = colander.Invalid(form["identity_information"], "ID Number %s already exists in Database" % number)
exc.number = "ID Number already exists "
raise exc
else:
exc = colander.Invalid(form["identity_information"], "ID Number %s is not a valid SA ID Number" % number)
exc.number = "Invalid ID number"
raise exc
elif type == "Passport":
if q:
exc = colander.Invalid(form["identity_information"], "Passport number %s already exists in Database" % number)
exc.number = "Passport number already exists"
raise exc
def gen_agent_schema_form(self):
_but = ('create agent',)
_title = "Create Agent"
if not self.context.__is_new__:
_but = ('update agent',)
_title = "Agent Details"
deals = []
if self.context.ou:
deals = [(deal.id, str(deal)) for deal in self.context.ou[0].org_deals]
schema = Agent(validator=AgentFormValidation(self.context, self.request), title=_title).bind(deals=deals)
form = Form(schema, buttons=_but)
return schema, form
验证工作正常。它只是不想突出显示元素。
当我替换:
exc.number = "ID Number already exists"
与
exc['number'] = "ID Number already exists"
它突出显示,但它突出显示表单上的第一个元素,即first_name
,这也是错误的。
我觉得我错过了一些小事。
更新
所以当我这样做时,我玩了一下:
exc = colander.Invalid(form, "ID Number %s already exists in Database" % number)
exc["identity_information"] = "ID Number already exists "
raise exc
我在正确的字段上方收到一个警告消息框(不是js警报):
而不是这个,我需要在上面的例子中突出显示该字段。
答案 0 :(得分:2)
在自定义验证器中,您始终将表单作为第一个参数传递给colander.Invalid()。这样,您可以将验证消息添加到表单的顶部,但不会触发模式节点/元素的突出显示。开始使用处理单个架构节点/元素的简单验证器。
exc = colander.Invalid(form["identity_information"], "ID Number %s already exists in Database" % number)
无论如何,我没有看到对场间验证的明确要求。您可以使用可用的漏勺验证器或在每个代理模式节点上创建自定义验证器,而不是在代理模式上应用复杂的基于类的验证器,从而使验证器尽可能简单。您当前的验证程序实现对于太多用例过多关注。
我假设您有两种不同的用例 - 注册和其他与代理相关的任务。通过发明不同的模式,我可以保持特定于模式节点和用例的验证。 ID的唯一性在创建具有添加/创建表单的内容时可能很重要,在更新表单中,用户可能无法更改所有这些值,只能更改有限的个人信息。
主要思想是通常应用模式节点验证器来获取模式节点上的验证消息。在特殊情况下,应用表单级验证器(代理注册)。
您的用例说明了表单验证的域。验证表单对模式的输入并处理与持久性相关的主题(主键唯一性)的类做得太多了。两者都应该被封装以分别进化。您的业务规则将随时更改,数据库表将始终要求主键唯一。
<强>架构强>
import colander
class AgentRegistration(colander.Schema):
"""schema for agent registration with email validation
Note the form validator is invoked only if none of the individual field validators raise an error.
"""
first_name = colander.SchemaNode(colander.String())
number = colander.SchemaNode(colander.Integer(), validator=can_register_agent)
email = colander.SchemaNode(colander.String(), validator=colander.Email())
verify_email = colander.SchemaNode(colander.String(), validator=colander.Email())
validator = verify_email_validator
class AgentDeals(colander.Schema):
"schema for managing agent deals"
first_name = colander.SchemaNode(colander.String())
number = colander.SchemaNode(colander.Integer(), validator=validateID)
email = colander.SchemaNode(colander.String(), validator=colander.Email())
架构验证器
def agent_unique(node, value):
"validate uniqueness of value in database table Agents"
if sqlahelper.get_session().query(Agents.id_number).filter(Agents.id_number == value).first()
raise Invalid(node,
'ID Number %r is already given to another agent. Please change it' % value)
def valid_SA_ID(node, value):
"validates SA ID Number - just a copy of your requirement calling your custom function"
if not validateID(value):
raise Invalid(node,
'SA ID Number %r is not valid.' % value)
def can_register_agent(node, value):
"ensure Agent ID Number is a valid and not already existing in database"
valid_SA_ID(node, value)
agent_unique(node, value)
def verify_email_validator(form, values):
"""schema level validator with access to all values
validates emails are same
validation messages are displayed on top of form"""
if values['email'] != values['verify_email']:
raise colander.Invalid(form, 'Email values do not match.')
<强>表格强>
class AgentRegistrationView(object)
def __init__(self, request):
"""Set some common variables needed for each view.
"""
self.request = request
self.context = request.context
@view_config(route_name='add_agent', permission='admin', renderer='add_agent.mako')
def add_agent(self):
"""return form to create new agents
may be we do not need to bind any deals data here"""
schema = AgentRegistration()
form = deform.Form(schema, action=self.request.route_url('add_agent'), buttons=('Add Agent','Cancel'))
class AgentDealsView(object)
def __init__(self, request):
"""Set some common variables needed for each view.
"""
self.request = request
self.context = request.context
def get_deals(self)
"""return deals to be bound to Agent Schema"""
if self.context.ou:
return [(deal.id, str(deal)) for deal in self.context.ou[0].org_deals]
@view_config(route_name='edit_agent' permission='edit', renderer='edit_agent.mako')
def edit_agent(self):
# we bind deals data to form
schema = AgentDeals().bind(deals=self.get_deals())
form = deform.Form(schema, action=self.request.route_url('edit_agent'), buttons=('Save','Cancel'))
参考
除此之外,您可能对ColanderAlchemy感兴趣,但它增加了另一层次的抽象。实际上,我不推荐给你。