Posible bug in SQLFORM

25 views
Skip to first unread message

Alfonso Serra

unread,
Apr 26, 2017, 10:42:32 PM4/26/17
to web...@googlegroups.com
I have declared a table as
db.define_table("agencies",
   
Field("hotel", "reference hotels", notnull=True),
   
Field("subgroup", "reference subgroups", label="Subgroup"),
   
Field("agency", "string", length=100, writable= False, label="Agency", notnull=True),
   
Field("alias", "string"),
   
Field("commission", "double"),
    auth
.signature
)

At the controller:
frm2 = SQLFORM(db.agencies, formstyle="rows").process(formname="agencies")
if frm2.accepted:
   dd
("All good")
elif frm2.errors:
   dd
(frm2.errors)

dd is a print to browser and stop execution function, not related.

request.post_vars:

<Storage {
 
'agency': 'My Cool Agency'
 ,
'modified_by': '2'
 ,
'alias': ''
 ,
'hotel': '7'
 ,
'is_active': ''
 ,
'created_by': '1'
 ,
'id': '1'
 ,
'commission': ''
 ,
'created_on': '2016-03-31 14:47:34'
 ,
'modified_on': '2016-04-01 17:25:32'
 ,
'_formkey': 'beee6ee6-d9d4-4de9-85c5-b248cb5f6f20'
 ,
'_formname': 'agencies'
 ,
'subgroup': '43'}>

i get this frm2.errors:
<Storage {'hotel': 'no data'}>

hotel is a referenced field and it has a value of 7 on the request.post_vars

inspecting sqlhtml.py accepts function, line 1673:

            elif field.default is None and field.type != 'blob':
               
self.errors[fieldname] = 'no data'
               
self.accepted = False
               
return False
            value
= fields.get(fieldname, None)
           
if field.type == 'list:string':
               
if not isinstance(value, (tuple, list)):
                    fields
[fieldname] = value and [value] or []
           
elif isinstance(field.type, str) and field.type.startswith('list:'):
               
if not isinstance(value, list):
                    fields
[fieldname] = [safe_int(
                        x
) for x in (value and [value] or [])]
           
elif field.type == 'integer':
               
if value is not None:
                    fields
[fieldname] = safe_int(value)
           
elif field.type.startswith('reference'):
               
## Avoid "constraint violation" exception when you have a
               
## optional reference field without the dropdown in form. I.e.,
               
## a field with code to be typed, in a data-entry form.

the reference field is falling in

elif field.default is None and field.type != 'blob':

instead

 elif field.type.startswith('reference'):

why field.default is None returns True?

Tried this in the controller:
print db.agencies.hotel.default == ""
True
print db.agencies.hotel.default is not None
False

This case should not fall into field.default is None

Thanks



Alfonso Serra

unread,
Apr 27, 2017, 12:11:07 AM4/27/17
to web...@googlegroups.com
Before i drive you crazy, i have commented the function SQLFORM.createform so i could implement my own form styles just passing the SQLFORM instance to a function like:

def renderform(self):
    style
= self.formstyle
   
   
return str(self.formstyles[style](self))
   
response
.formstyle = "default"
SQLFORM
.formstyles['default'] = frm_default_style
SQLFORM
.formstyles['rows'] = frm_table_style
SQLFORM
.xml = renderform

self.components werent created and i guess thats why default fields were messed up. (i cant see the relationship but uncommenting createform did fix the problem)

To fix all this and be able to create my own styles with absolute freedom, this worked, sqlhml.py line 1402:
 def createform(self, xfields):
        formstyle
= self.formstyles["ul"]
       
# if isinstance(formstyle, basestring):
       
#     if formstyle in SQLFORM.formstyles:
       
#         formstyle = SQLFORM.formstyles[formstyle]
       
#     else:
       
#         raise RuntimeError('formstyle not found')

       
if callable(formstyle):
           
try:
                table
= formstyle(self, xfields)
               
for id, a, b, c in xfields:
                   
self.field_parent[id] = getattr(b, 'parent', None) \
                       
if isinstance(b, XmlComponent) else None

Trick the SQLFORM to always use a light representation, just so field.default gets populated properly, and then hack it with the .xml() trick above
That way im able to represent the form however i like with full self aware state, with a custom function like:

def frm_default_style(self):
   
#create any custom header
    frm
= FORM(_class="myform")

    keepvalues
= self.keepvalues if hasattr(self, "keepvalues") else False
   
#iterate over the fields and create any behaviour and style you like
   
   
for fld in self.fields:
        field
= self.table[fld] #access the SQLFORM to inspect field properties
       
       
#implemented keepvalues
       
if keepvalues:
           
out = LABEL(fld, _for=fld) + INPUT(_name=fld, requires=field.requires, _value=self.vars[fld])
       
else:
           
out = LABEL(fld, _for=fld) + INPUT(_name=fld, requires=field.requires)
           
        frm
.append(out)
   
   
# add the hidden fields + token    
    frm
.append(self.hidden_fields())
   
   
#add any submit
    frm
.append(INPUT(_type="submit", _value="submit"))
   
   
return frm

Reply all
Reply to author
Forward
0 new messages