Foreword
When we need to verify the option field, we need to use ChoiceField to verify
options
There is a field in the model model that is an option field. goods_status can have two statuses, 0 means off the shelf, 1 means on sale, the default
class Goods(models.Model): """Product list""" goods_status = models.IntegerField(choices=( (0, 'Removed'), (1, 'For sale') ), default=1, verbose_name="0 off the shelves 1 on sale")
When we query, goods_status displays 0 and 1
We want it to show Discontinued and For Sale so it looks more friendly
Serialization
Use the get_
method in the serialization class. This method obtains the data corresponding to the choice field. It is being removed and sold.
This involves a very useful instance method: get_
For fields in the model that contain the choices
parameter,
is the name of the field, get_FOO_display()
returns a human-readable string of the option
# Author-Shanghai Youyou QQ communication group: 717225969 # blog address https://www.cnblogs.com/yoyoketang/ class GoodsSerializer(serializers.ModelSerializer): """Serialized product models""" create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', required=False) update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', required=False) #choce field get_<field name>_display display name goods_status = serializers.CharField(source='get_goods_status_display', required=False) #Required fields goods_code = serializers.CharField(required=True, max_length=15, min_length=8, validators=[validators.UniqueValidator(queryset=Goods.objects.all(), message="goods_code already exists")] ) class Meta: model = Goods fields = '__all__' # Return all fields
When serializing the output, it can display On sale
When source=’get_goods_status_display’ is used, the goods_status field here is set to a read-only field by default. If the post wants to submit create() or modify this field, an error will be reported.
TypeError at /api/v1/goods/ Got a `TypeError` when calling `Goods.objects.create()`. This may be because you have a writable field on the serializer class that is not a valid argument to `Goods.objects.create()`. You may need to make the field read-only, or override the GoodsSerializer.create() method to handle this correctly. Original exception was: Traceback (most recent call last): File "E:\python36\lib\site-packages\rest_framework\serializers.py", line 932, in create instance = ModelClass._default_manager.create(**validated_data) File "E:\python36\lib\site-packages\django\db\models\manager.py", line 82, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "E:\python36\lib\site-packages\django\db\models\query.py", line 415, in create obj = self.model(**kwargs) File "E:\python36\lib\site-packages\django\db\models\base.py", line 495, in __init__ raise TypeError("'%s' is an invalid keyword argument for this function" % kwarg) TypeError: 'get_goods_status_display' is an invalid keyword argument for this function
You can also write a separate method to read the choice field, get_
# Author-Shanghai Youyou QQ communication group: 717225969 # blog address https://www.cnblogs.com/yoyoketang/ class GoodsSerializer(serializers.ModelSerializer): """Serialized product models""" create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', required=False) update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', required=False) # Set SerializerMethodField goods_status = serializers.SerializerMethodField(read_only=False, write_only=False) def get_goods_status(self,obj): """get_<field name> override goods_status""" return obj.get_goods_status_display() class Meta: model = Goods fields = '__all__' # Return all fields
In this way, if you bring goods_status when submitting, you will not get an error, but it will not be saved in the database (which is equivalent to ignoring the verification of this field), which cannot achieve our expected results.
to_representation use
Next, we hope that when submitting data, we still use the original numbers 0 and 1 to submit, and the corresponding names will be displayed when reading them out.
Rewrite the to_representation method in the ModelSerializer class to customize the return of serialized data. At this time, you need to remove the above
# chicoce field get_<field name>_display display name goods_status = serializers.CharField(source='get_goods_status_display', required=False)
Override the to_representation method in the ModelSerializer class
# Author-Shanghai Youyou QQ communication group: 717225969 # blog address https://www.cnblogs.com/yoyoketang/ class GoodsSerializer(serializers.ModelSerializer): """Serialized product models""" create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', required=False) update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', required=False) #Required fields goods_code = serializers.CharField(required=True, max_length=15, min_length=8, validators=[validators.UniqueValidator(queryset=Goods.objects.all(), message="goods_code already exists")] ) def to_representation(self, instance): """return of to_representation custom serialized data""" data = super().to_representation(instance) data.update(goods_status=instance.get_goods_status_display()) return data class Meta: model = Goods fields = '__all__' # Return all fields
At this time, the number corresponding to the status is passed, and the returned query result is the display name
ChoiceField option field
ChoiceField is specially used to deal with problems with choices options. It is more advanced to handle. For example, there are multiple states in the database, but state 2 does not want users to operate, and only allows users to add two states: 0 and 1.
goods_status = models.IntegerField(choices=( (0, 'Removed'), (1, 'for sale'), (2, 'Blacklist') ), default=1, verbose_name="0 off the shelves 1 on sale")
So ChoiceField can be used, and the choices parameter options must be passed.
# Author-Shanghai Youyou QQ communication group: 717225969 # blog address https://www.cnblogs.com/yoyoketang/ class GoodsSerializer(serializers.ModelSerializer): """Serialized product models""" create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', required=False) update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', required=False) # get_<field name>_display goods_status = serializers.ChoiceField(choices=( (0, 'Removed'), (1, 'For sale') ), required=False) def to_representation(self, instance): """return of to_representation custom serialized data""" data = super().to_representation(instance) data.update(goods_status=instance.get_goods_status_display()) return data class Meta: model = Goods fields = '__all__' # Return all fields
The implementation effect is the same as above, but there is an additional limitation in the function. Only the numbers 0 and 1 can be passed in two states, and the state name is displayed when returning.
Rewrite ChoiceField
If we are adding, we can add two statuses of 0 and 1, or we can submit two names of “off the shelf” and “on sale”, and the names will be displayed when querying.
To deserialize the submitted data, you need to override the ChoiceField method.
# Author-Shanghai Youyou QQ communication group: 717225969 # blog address https://www.cnblogs.com/yoyoketang/ class ChoiceField(serializers.ChoiceField): """Override ChoiceField""" def to_representation(self, obj): """Return status name""" if obj == '' and self.allow_blank: return obj return self._choices[obj] def to_internal_value(self, data): """Supports writing the key or value name of choice""" for i in self._choices: # In this way, no matter the user POSTs up, the Key or Value of CHOICES can be accepted. if i == data or self._choices[i] == data: return i raise serializers.ValidationError("Acceptable values are {0}.".format(list(self._choices.values()))) class GoodsSerializer(serializers.ModelSerializer): """Serialized product models""" create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', required=False) update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S', required=False) # Directly use the ChoiceField rewritten above goods_status = ChoiceField(choices=( (0, 'Removed'), (1, 'For sale') ), required=False) #Required fields goods_code = serializers.CharField(required=True, max_length=15, min_length=8, validators=[validators.UniqueValidator(queryset=Goods.objects.all(), message="goods_code already exists")] ) goods_stock = serializers.IntegerField(required=True, min_value=1, max_value=10000) class Meta: model = Goods fields = '__all__' # Return all fields
Passing the status name can support
Passing numbers also supports
If you only want to receive the status name from the user, you can override the to_internal_value method of ChoiceField
def to_internal_value(self, data): """Supports writing the value name of choice""" if data == '' and self.allow_blank: return '' for key, val in self._choices.items(): if val == data: return key self.fail('invalid_choice', input=data)
For related usage of choicefield, please refer to https://stackoverflow.com/questions/28945327/django-rest-framework-with-choicefield