Skip to content

Conversation

owenniles
Copy link

Perhaps I misunderstand the intended serialization and deserialization behaviors of fields.ChoiceField, but I recently noticed that although every ChoiceField instance stores all of the choices, pairs of key and display_name, with which it is initialized, I couldn't figure out when it ever actually uses a choice's display_name. Meanwhile, I found myself manually converting user input values, which match choice display_names, to the underlying data values that match the choice keys.

This pull request modifies the behavior of the ChoiceField so that it automatically deserializes user input into the corresponding underlying data values and does the reverse for serialization.

Here is a link to a related post that I wrote in the Django REST Framework Google group.

…> `key`

during deserialization and `key` --> `display_name` during serialization.

Perhaps I misunderstand the intended behavior of `fields.ChoiceField`, but I
noticed recently that the although every `ChoiceField` instance stores the full
list of choices with which it is initialized (a list of pairs of `key` and
`display_name`), I couldn't figure out when it ever uses a choice's
`display_name`. As a result, I found myself manually converting user input
values, which matched choice `display_name`s, to the underlying data values that
match the choice `key`s.

This commit modifies the behavior of `ChoiceField` instances so that they
automatically deserialize user input into the corresponding underlying data
value and do the reverse for serialization.
@rpkilby
Copy link
Contributor

rpkilby commented Aug 7, 2019

Hi @owenniles. Display values are intended to be the human-readable values that are displayed to the user. Specifically, these are the rendered values you see in a select/dropdown in Django forms and DRF's Browsable API. Because these values are human-readable, they may contain white space, punctuation, and may be translated based on a user's locale. These qualities (especially translation, which can change the value) don't necessarily make them suitable for use as the key/code value used in the API.

That said, the key isn't always optimal either. e.g., let's say a "quality" field is represented as an integer (for sorting purposes). You might have choices like:

choices = [
    (1, 'Poor quality'),
    (2, 'Average quality'),
    (3, 'Good quality'),
]

The integer values aren't necessarily the most intuitive representation in the API, and it might be good to have some kind of intermediary value that is used in the API. Maybe a 3-tuple that contains the (db value, api value, display value). So choices might look like:

choices = [
    (1, 'poor', 'Poor quality'),
    (2, 'avg', 'Average quality'),
    (3, 'good', 'Good quality'),
]

I don't know what a solution here would look like (maybe something incorporating Choices from django-model-utils), but it would probably work best as a 3rd party package.

@rpkilby rpkilby closed this Aug 7, 2019
@owenniles
Copy link
Author

Makes sense, thanks for the explanation @rpkilby!

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

Successfully merging this pull request may close these issues.

2 participants