Dear Django users,
This is my first post on this ML, please excuse me if my question sounds
weird.
My question is about the separation of roles between Widget and Field, in
the context of eg. a serialization/deserialization of a list of values
using JSON. It concerns especially the "Field.to_python", "Field.clean",
"Field.bound_data", "Widget.render" and "Widget.value_from_datadict".
More concretely, I want to manipulate a list of DB entries in a Hidden
field of a form, use some Javascript to populate the Hidden field and send
it back to the form. Until today, I was using
* the to_python method to deserialize the JSON string that was arriving to
the field, and to transform it to a proper list of objects,
* the prepare_value to initialize the JSON string to put into the Hidden
input (non documented, this is the only way I found)
The problem was, after an erroneous form has been sent, the prepare_value
was taking as input a non-deserialized JSON string. Example:
1* initial rendered input: <input id="json-for-list-authors"
name="existing_authors" value="{"authors": []}" type="hidden">
2* after populating it with Javascript: <input id="json-for-list-authors"
name="existing_authors" value="{"authors":
["jean-philippe.XXX"]}" type="hidden">
3* sending the form with error renders the hidden input like this <input
id="json-for-list-authors" name="existing_authors"
value="{"authors": "{"authors":
["jean-philippe.vert"]"}" type="hidden"> (more or less some
").
It is then calling prepare_value on a JSON string received from 2/, and
embedding a JSON into a JSON.
After that, I thought the right approach would be to override a specific
Widget's "render" and "value_from_datadict": the transformation of the
python list into a JSON is done in render, and the deserialization is done
in value_from_datadict. I find that approach cleaner and neat:
* it solves my problem with having a proper serialization/deserialization
in case of errors
* the Field.to_python does not concentrate in the actual representation of
the data: it receives a list of values, regardless of the way I am
serializing the data, and it concentrates on the logic of transforming the
list or elements of this list into adequate python objects (eg. retrieving
entries of the DB, removing duplicates)
* the widget is agnostic to logical errors (eg. entry does not exist in the
DB): it concentrates on serializing/deserializing whatever object has been
passed to it, and can concentrate of malformed string/data error (eg.
unable to deserialize)
* there is no need to call a hidden API prepare_value
However, there are other problems:
* there is no proper way to unit test that: assertFieldOutput tests the
result of the "clean", which is indirectly calling "to_python".
* In the case of list of values, since those are not hashable, they
cannot be used as keys for the "valid"/"invalid" parameters of
assertFieldOutput
* Some weird design issues appear: if for instance I would like to remove
the duplicates in the "to_python", the removal of the duplicates will not
affect the Widget, and the latter may render the duplicate values again in
the form
* I would like to test the Widget (illformed strings) and the Field
(inexisting users, duplicate removal) separately
The other option would be to use the BoundField.data or BoundField.value()
to put the deserialization there. But then
* I would not be able to test it properly until I have a form.
*
To put everything in a nutshell, my question is: what is the best way to
approach this kind of design? What are the responsibilities of those
two/three entities?
Thanks,
Raffi
--
You received this message because you are subscribed to the Google Groups
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-users/51ba6378-b3c7-4a93-b17d-04dd2079c21c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.