How to change django-rest-framework's ChoiceField selection from a model class?

Th models.py:

from django.db import models

class Type(models.Model):
    letter = models.CharField(max_length = 1)
    name = models.CharField(max_length = 10)

class Code(models.Model):
    type = models.ForeignKey(Type, related_name = 'code', blank = True, default = None)

      

serializers.py:

import collections
from rest_framework import serializers
from code.models import Type, Code

class TypeSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Type
        fields = ('letter','name')

class TypeField(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Type
        fields = ('letter',)

class CodeSerializer(serializers.HyperlinkedModelSerializer):
    type = TypeField() #serializers.ChoiceField(???)

    def create(self, validated_data):
        c = Code()
        c.type = Type.objects.get(letter = validated_data['type']['letter'])
        c.save()
        return c

    class Meta:
        model = Code
        fields = ('type',)

      

view.py:

from rest_framework import viewsets
from code.models import Code, Type
from code.serializers import CodeSerializer, TypeSerializer

class CodeViewSet(viewsets.ModelViewSet):
    queryset = Code.objects.all()
    serializer_class = CodeSerializer

class TypeViewSet(viewsets.ModelViewSet):
    queryset = Type.objects.all()
    serializer_class = TypeSerializer

      

Is it possible to use ChoiseField to select type within code. When do I create a Code object instead of a CharField?

Possible Solution

I find a possible solution, I got a ChoiseField class for DynamicChoiceField

class DynamicChoiceField(serializers.ChoiceField):
    def __init__(self, **kwargs):
        super(DynamicChoiceField, self).__init__([],**kwargs)

    def set_choices(self, choices):
        pairs = [
            isinstance(item, (list, tuple)) and len(item) == 2
            for item in choices
        ]
        if all(pairs):
            self.choices = OrderedDict([(key, display_value) for key, display_value in choices])
        else:
            self.choices = OrderedDict([(item, item) for item in choices])

        self.choice_strings_to_values = dict([
            (six.text_type(key), key) for key in self.choices.keys()
        ])

      

and change the CodeSerializer to:

class CodeSerializer(serializers.HyperlinkedModelSerializer):
    type = TypeField(read_only=True) 
    choise_of_type = DynamicChoiceField(allow_blank=False, write_only=True)

    def __init__(self, *args, **kwargs):
        types = Type.objects.all()
        choices = [(t.letter,t.name) for t in types]
        self.fields['choise_of_type'].set_choices(choices)
        super(CodeSerializer, self).__init__(*args, **kwargs)

    def create(self, validated_data):
        c = Code()
        c.type = Type.objects.get(letter = validated_data['choise_of_type'])
        c.save()
        return c

    class Meta:
        model = Code
        fields = ('type', 'choise_of_type',)

      

The only drawback of this solution is that I need two fields that have only been set to one (type, choise_of_type)

+3


source to share





All Articles