DRF - Notes

JunePyo Suh·2020년 9월 7일
0

Core arguments in serializer fields

read_only

Set this to True to ensure that the field is used when serializing a representation, but is not used when creating or updating an instance during deserialization.

write_only

Set this to True to ensure that the field may be used when updating or creating an instance, but is not included when serializing the representation.

required

Setting this to False also allows the object attribute or dictionary key to be omitted from output when serializing the instance.
default If set, this gives the default value that will be used for the field if no input value is supplied.

allow_null

Normally an error will be raised if None is passed to a serializer field. Set this keyword argument to True if None should be considered a valid value.

source

The name of the attribute that will be used to populate the field.

validators

A list of validator functions which should be applied to the incoming field input, and which either raise a validation error or simply return.

error_messages

A dictionary of error codes to error messages.

label

A short text string that may be used as the name of the field in HTML form fields or other descriptive elements.

help_text

A text string that may be used as a description of the field in HTML form fields or other descriptive elements.

initial

A value that should be used for pre-populating the value of HTML form fields.

Above information is from GeeksforGeeks.

Understanding ListField

Arguments

  • child : A field instance that should be used for validating the objects in the list. If this argument is not provided then objects in the list will not be validated.
  • allow_empty : Designates if empty lists are allowed.
  • min_length : Validates that the list contains no fewer than this number of elements.
  • max_length : Validates that the list contains no more than this number of elements.

Syntax

field_name = serializers.ListField(*args, **kwargs)

Example

scores = serializers.ListField(
   child=serializers.IntegerField(min_value=0, max_value=100)
)
// Create a dictionary and add invalid values
>>> data = {}
>>> data['integers'] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// dictionary created
>>> data
{'integers': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}

// deserialize the data
>>> serializer = GeeksSerializer(data=data)

// check if data is valid
>>> serializer.is_valid()
True

// print the data
>>> serializer.data
{'integers': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}

// check the errors
>>> serializer.errors
{}
  • context

  • required=True
    For nested relationships

  • partial=True
    updating only partial information

  • source

  • ModelSerializer Fields
    By default, all the model fields on the class will be mapped to a corresponding serializer fields.

Any relationships such as foreign keys on the model will be mapped to PrimaryKeyRelatedField. Reverse relationships are not included by default unless explicitly included as specified in the serializer relations documentation.

Specifying which fields to include

The names in the fields and exclude attributes will normally map to model fields on the model class.

Alternatively names in the fields options can map to properties or methods which take no arguments that exist on the model class.

Since version 3.3.0, it is mandatory to provide one of the attributes fields or exclude.

  • url?!
urlpatterns = [
    ...
    url(r'^api/topic_detail/(?P<name>[a-zA-Z0-9-]+)/content_list/$', views.topic_content_list, name='topic_content_list'),
    ...
]

Replace or edit the lookup parameter in Router

For instance, if you would like to modify the automatic lookup parameter of your router from pk to uuid:

class ProductViewSet(ModelViewSet):
    lookup_field = 'my_uuid_field'

lookup_field tells DRF to use this field instead of pk to get items.

Use different serializers in the same ModelViewSet

If you would like to use different serializer classes for different HTTP request in a same ModelViewSet, override the get_serializer_class() method.

class DualSerializerViewSet(viewsets.ModelViewSet):
    def get_serializer_class(self):
        if self.action == 'list':
            return serializers.ListaGruppi
        if self.action == 'retrieve':
            return serializers.DettaglioGruppi
        return serializers.Default

If this throws an exception, try if hasattr(self, 'action') and self.action == 'list'. (Django rest swagger does not place a self.action parameter, so the function above may throw an exception.

Or, use the mixin below:

class MultiSerializerViewSetMixin(object):
    def get_serializer_class(self):
        /*
        Look for serializer class in self.serializer_action_classes, which
        should be a dict mapping action name (key) to serializer class (value),
        i.e.:

        class MyViewSet(MultiSerializerViewSetMixin, ViewSet):
            serializer_class = MyDefaultSerializer
            serializer_action_classes = {
               'list': MyListSerializer,
               'my_action': MyActionSerializer,
            }

            @action
            def my_action:
                ...

        If there's no entry for that action then just fallback to the regular
        get_serializer_class lookup: self.serializer_class, DefaultSerializer.
        */
        try:
            return self.serializer_action_classes[self.action]
        except (KeyError, AttributeError):
            return super(MultiSerializerViewSetMixin, self).get_serializer_class()

Adding non-model fields on a ModelSerializer

class MySerializer(serializers.ModelSerializer):
    write_only_char_field = serializers.CharField(write_only=True)
    write_only_list_char_field = serializers.ListField(child=serializers.CharField(max_length=100, default=''), write_only=True)
    empty_method_field = serializers.SerializerMethodField()
    read_only_custom_model_field = serializers.CharField(source='custom_property', read_only=True)

    def create(self, validated_data):
        validated_data.pop('write_only_char_field', None)
        validated_data.pop('write_only_list_char_field', None)
        return super().create(validated_data)

The read_only_custom_model_field would use a method on your model to read some data, not strictly a model field, but a custom method. I.e.

class MyModel(models.Model):
    my_field = models.CharField(max_length=100)

    @property
    def custom_property(self):
        return "Perform calculations, combine with related models, etc. etc."

Serialize a queryset from an unrelated model as a nested serialzier

Use SerializerMethodField.

class ResearchSerializer(serializers.ModelSerializer):
    templates = serializers.SerializerMethodField()

    class Meta:
        model = Research
        fields = ('id', 'created', 'speaker', 'body', 'templates')

    def get_templates(self, obj):
        values = obj.get_values() # whatever your filter values are. obj is the Research instance
        templates = ResearchTemplate.objects.filter(mergefields__contained_by=values) # Or whatever queryset filter
        return ResearchTemplateSerializer(templates, many=True).data

Serialize specific fields dynamically

Use DynamicFieldsModelSerializer

class DynamicFieldsModelSerializer(serializers.ModelSerializer):
    def __init__(self, *args, **kwargs):
        # Instantiate the superclass normally
        super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs)

        fields = self.context['request'].query_params.get('fields')
        if fields:
            fields = fields.split(',')
            # Drop any fields that are not specified in the 'fields' argument
            allowed = set(fields)
            existing = set(self.fields.keys())
            for field_name in existing - allowed:
                self.fields.pop(field_name)

Using the request object

Article on how to customize our response based on request parameters

0개의 댓글