Pylons / deform

A Python HTML form library.
Other
417 stars 161 forks source link

form.render(appstruct) is not respected if form.validate() was called before #236

Open dwt opened 10 years ago

dwt commented 10 years ago

I've had this problem in my application, where this is a reduction from.

The problem is that calling form.validate(post_values) before calling form.render(app_struct) leaves turds in the fields (to quote mcdonc from irc). In practice that means that the app_struct from form.render() is ignored for some values

On IRC mcdonc pointed to this code as being the offender: https://github.com/Pylons/deform/blob/master/deform/widget.py#L1497

Here's the reduction that shows the issue.


#!/usr/bin/env python

import colander
import deform
from deform.widget import TextAreaWidget, SequenceWidget

class AnswerEditSchema(colander.Schema):
    answer_title = colander.SchemaNode(
        colander.String(),
        validator=colander.Length(1, 384),
        title=u"Title",
        missing=u'',
        widget=deform.widget.TextAreaWidget(),
    )

class QuestionEditSchema(colander.Schema):
    question_title = colander.SchemaNode(
        colander.String(),
        validator=colander.Length(2),
        title=u"Title",
        widget=deform.widget.TextAreaWidget(),
    )
    answers = colander.SchemaNode(
        colander.Sequence(),
        AnswerEditSchema(
            title=u"Answer",
            name=u"answer"
        ),
        widget=SequenceWidget(min_len=2),
        title=u"Answers",
    )

schema = QuestionEditSchema().bind()
form = deform.Form(schema=schema)
post_values = [('_charset_', u'UTF-8'), ('question_title', u'english title'), ('__start__', u'answers:sequence'), ('__start__', u':mapping'), ('title', u''), ('__end__', u':mapping'), ('__start__', u':mapping'), ('title', u'english wrong answer'), ('__end__', u':mapping'), ('__end__', u'answers:sequence'), ('submit', u'submit')]

app_struct = form.validate(post_values)
# app_struct = {'answers': [{'answer_title': 'fnord1'}, {'answer_title': u'english wrong answer'}], 'question_title': 'fnord2'}
print 'app_struct:\t', app_struct
app_struct['question_title'] = 'fnord1'
app_struct['answers'][0]['answer_title'] = 'fnord2'
print 'new app struct:\t', app_struct
rendered = form.render(app_struct)
assert 'fnord1' in rendered, "form.render() does not respect app_struct['question_title']" # this works
assert 'fnord2' in rendered, "form.render() does not respect app_struct['answers'][0]['answer_title']" # this doesn't
tsauerwein commented 10 years ago

I was just about to open a ticket for exactly this problem.

In my case I am storing the objects in a database after the validation, and the objects will receive their primary keys. But then, if I am rendering the form, the objects in a SequenceWidget will not have the new primary key.

As a work-around you can simply create a fresh form object, but it would be nice if validate would not leave turds in the fields.