http://myapp/get_rates?rooms=5&agency=1
def get_rates():
# http://myapp/get_rates?rooms=5&agency=1
print "request:", request.vars
# <Storage {'agency': '1', 'rooms': '5'}>
form = SQLFORM.factory(
Field("rooms", "integer", required=True)
, Field("agency", "integer", required=True)
, _method="GET"
)
#remove the auto id field
form.fields.pop(0)
print "accepts:", form.accepts(request.vars, session=None, dbio=False)
# False
print "validate:", form.validate(request_vars=request.vars, session=None)
# False
print "fvars:", form.vars
# {}
if form.accepted:
print "All good"
elif form.errors:
print form.errors
print "Done"
return 0.0
request: <Storage {'agency': '1', 'rooms': '5'}>
accepts: False
validate: False
fvars: <Storage {}>
Done
http://myapp/get_rates?rooms=5&agency=1&_formname=no_table/create
request.get_vars._formname = 'no_table/create'
form = SQLFORM.factory(
Field("rooms", "integer", required=True)
# request.vars
<Storage {'rooms': 'asd'}>
request.vars._formname = "get_rates"
print "accepts:", form.accepts(request.vars, session=None, dbio=False, formname="get_rates")
print "validate:", form.validate(request_vars=request.vars, session=None, formname="get_rates")
Thanks Anthony. It worked but now it always validates no matter what.
I have passed
# request.vars
<Storage {'rooms': 'asd'}>
request.vars._formname = "get_rates"
print "accepts:", form.accepts(request.vars, session=None, dbio=False, formname="get_rates")
print "validate:", form.validate(request_vars=request.vars, session=None, formname="get_rates")
And the form is accepted on both cases.
Is not, at least, the variable type compared?
Would it make sense to modify the Field class to add initial validators when it is instantiated, or have in mind the field type and requirement?
I may be wrong but havent seen this behaviour on a post submit. Does this only happen on get submits?
kwargs['request_vars'] = kwargs.get(
'request_vars', current.request.post_vars)
elif field.type == 'integer':
if value is not None:
fields[fieldname] = safe_int(value)
Thanks Anthony.
I think ill submit a patch, Im doing some debugging and i have noted a few things:
Version 2.16.1-stable+timestamp.2017.11.14.05.54.25
gluon/html.py line 2217
kwargs['request_vars'] = kwargs.get(
'request_vars', current.request.post_vars)
the validate method assumes post_vars are used. Using request.vars instead would save us having to declare the request_vars parameter.
Its actually good we are able to override but the form should be aware what variables to test against by default.
gluon/sqlhtml.py line 1904
elif field.type == 'integer':
if value is not None:
fields[fieldname] = safe_int(value)
sqlform.accepts actually does some kind of type checking but it looks that does not affect the acceptation. The lines were executed using .factory so maybe they could be used to check the variable types.
Please allow me some considerations:
- The only case request.vars could be a problem would be when there are variables with the same name on both methods. On this case i dont know which one will be overwritten, the get var most likely.
- The form discards extra variable names not declared for processing, so including get vars should not affect post processing, besides when post and querystring vars collides.
- If the form was not meant to process get vars, implementing the functionality would not break compatibility. This would be easy since request.get_vars and post_vars should be processed/validated the same way when the form uses either methods.
I have made and test the changes and everything is working fine so far.
- The form would do type checking. It does not make sense to pass rooms = "asd" when it expects an integer. or declare field type "integer" and IS_INT_IN_RANGE and so on for every Field on our app.
- The form will detect the variables to test against when _method="get" is passed as parameter. It would be easy to use request.get_vars/post_vars instead request.vars to prevent the issues you mention.
- The form wont auto generate an id field when the adapter is NullAdapter (the one used when Fields does not belong to any table, DAL(None)).
I'm not sure about this. We already have default validators in place when using SQLFORM with a DAL table. This breaks down when using SQLFORM.factory because DAL(None) does not generate the default validators -- but it would probably be a better approach to change that behavior so that DAL(None) does get the default validators. That approach would have more general utility beyond helping with SQLFORM.factory, and it would avoid having to add complexity/duplicate validation code to the FORM class. In other words, let's use a mechanism we already have rather than add more code to the framework.
I havent seen where this happens yet, ill have a look. Agree that it will better to reuse the code but, please correct me if im wrong, validators will only trigger if the form is rendered into a view as they lie into the form's components?I'm not sure about this. We already have default validators in place when using SQLFORM with a DAL table. This breaks down when using SQLFORM.factory because DAL(None) does not generate the default validators -- but it would probably be a better approach to change that behavior so that DAL(None) does get the default validators. That approach would have more general utility beyond helping with SQLFORM.factory, and it would avoid having to add complexity/duplicate validation code to the FORM class. In other words, let's use a mechanism we already have rather than add more code to the framework.
About the id field, i thought it didnt make sense to add it as it does not serve any purpose when the form has a NullAdapter. Would be easier to create custom html without having to pop the field.
We really don't want to try to replicate validation logic directly in the form methods -- you would not only need to validate the data but also provide a way to specify error messages as with the validators. It would be a big unnecessary mess.
The auto id field, may not be a problem, i removed it for convenience for a couple of reason:
- iterate form.fields in the view to create the html. in this case was not needed but also the special treatment as it should lie on hidden inputs.
- the type checking on this case was validating the id which was not part of the factory declaration, not accepting the form. Ofc this could be solved with some code refinement and leave everything how it is.
We really don't want to try to replicate validation logic directly in the form methods -- you would not only need to validate the data but also provide a way to specify error messages as with the validators. It would be a big unnecessary mess.
Hmm i dont know if you would like this but i have also thought about it. Validator's error messages could be done by web2py translator, kinda like IS_DATE already does for date formats. If these messages are automated they could be easily changed at the translation file instead of having to declare them everytime on all the apps. Would also shorten the Fields declarations this way.
I have been recently involved in a project to translate a custom complex app and been thinking on ways to improve web2py translator.