Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected read_only behavior #42

Open
qrilka opened this issue Apr 8, 2016 · 2 comments
Open

Unexpected read_only behavior #42

qrilka opened this issue Apr 8, 2016 · 2 comments

Comments

@qrilka
Copy link

qrilka commented Apr 8, 2016

It looks that read_only doesn't work correctly with WTForms initialization, e.g.:

In [1]: from wtforms_components import read_only

In [2]: from wtforms import Form, TextField

In [3]: class MyForm(Form):
   ...:     foo = TextField()
   ...:     def __init__(self, *args, **kwargs):
   ...:         super(MyForm, self).__init__(*args, **kwargs)
   ...:         read_only(self.foo)
   ...:         

In [4]: from werkzeug.datastructures import MultiDict

In [5]: form=MyForm(MultiDict({'foo':'bar'})
   ...: )

In [6]: form.data
Out[6]: {'foo': 'bar'}

In [7]: form.validate()
Out[7]: True

In [8]: form.data
Out[8]: {'foo': 'bar'}

Is it normal that the field which is supposed to be read-only accepts form data?
I think the problem is in the fact that the field is being modified after form base class constructor where form data gets read

@qrilka
Copy link
Author

qrilka commented Apr 8, 2016

BTW overriding process method is also not quite correct - it will not fill field with "source object" data, I've done readonly field by overriding process_formdata in my form process method and that seems to give me correct behavior

@tvuotila
Copy link
Collaborator

You are correct on why your code works as it does. Form-class constructor calls process-method internally. I have rewrote the code to make the reason more apparent:

In [1]: from wtforms_components import read_only

In [2]: from wtforms import Form, TextField

In [3]: class MyForm(Form):
   ...:         foo = TextField()
   ...:         def __init__(self, *args, **kwargs):
   ...:                 super(MyForm, self).__init__(*args, **kwargs)
   ...:                 

In [4]: from werkzeug.datastructures import MultiDict

In [5]: form = MyForm()

In [6]: form.process(MultiDict({'foo':'bar'}))

In [7]: read_only(form.foo)
Out[7]: <wtforms.fields.simple.TextField at 0x10f14aa50>

In [8]: form.data
Out[8]: {'foo': 'bar'}

In [9]: form.validate()
Out[9]: True

In [10]: form.data
Out[10]: {'foo': 'bar'}

Lets now change the order of two lines:

In [11]: from wtforms_components import read_only

In [12]: from wtforms import Form, TextField

In [13]: class MyForm(Form):
   ....:         foo = TextField()
   ....:         def __init__(self, *args, **kwargs):
   ....:                 super(MyForm, self).__init__(*args, **kwargs)
   ....:                 

In [14]: from werkzeug.datastructures import MultiDict

In [15]: form = MyForm()

In [16]: read_only(form.foo)
Out[16]: <wtforms.fields.simple.TextField at 0x10f14ae10>

In [17]: form.process(MultiDict({'foo':'bar'}))

In [18]: form.data
Out[18]: {'foo': None}

In [19]: form.validate()
Out[19]: True

In [20]: form.data
Out[20]: {'foo': None}

As you can see, the field is read only after read_only-function is called. It makes no difference if I move the function back to constructor.

In [21]: from wtforms_components import read_only

In [22]: from wtforms import Form, TextField

In [23]: class MyForm(Form):
   ....:         foo = TextField()
   ....:         def __init__(self, *args, **kwargs):
   ....:                 super(MyForm, self).__init__(*args, **kwargs)
   ....:                 read_only(self.foo)
   ....:                 

In [24]: from werkzeug.datastructures import MultiDict

In [25]: form = MyForm()

In [26]: form.process(MultiDict({'foo':'bar'}))

In [27]: form.data
Out[27]: {'foo': None}

In [28]: form.validate()
Out[28]: True

In [29]: form.data
Out[29]: {'foo': None}

I know MyForm(MultiDict({'foo':'bar'}) is how examples use forms. It would be nice to set field to read only before constructor is called. Something like foo = read_only(TextField()) or foo = read_only(TextField)(). IMHO

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants