动态修改字段可以使Django rest框架API像graphQL端点一样,只从模型中检索所需的字段。
一旦序列化器被初始化,就可以使用.fields属性访问序列化器上设置的字段字典。访问和修改此属性允许您动态修改序列化器。
显式地修改fields参数可以帮助您做一些奇怪的事情,例如在运行时修改序列化器字段参数,而不是预定义它。
- 创建项目
djang-admin startproject ellistest
- 创建app
cd ellistest
python manage.py startapp testserializer
- 注册app
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','rest_framework','testserializer.apps.TestserializerConfig',
]
- 创建model以及序列化器 models.py
from django.db import models# Create your models here.
class TestModel(models.Model):id = models.BigAutoField(primary_key=True)name = models.CharField(max_length=255)age = models.IntegerField()def generateTwoValue(self):return self.name+'11',str(self.age)+'1'from rest_framework import serializers
class TestModelSerializer(serializers.ModelSerializer):name_col = serializers.SerializerMethodField()age_col = serializers.SerializerMethodField()def __init__(self, *args, **kwargs):# Don't pass the 'fields' arg up to the superclassrequest = kwargs.get('context', {}).get('request')str_fields = request.GET.get('fields', '') if request else Nonefields = str_fields.split(',') if str_fields else None# Instantiate the superclass normallysuper(TestModelSerializer, self).__init__(*args, **kwargs)if fields is not None:# Drop any fields that are not specified in the `fields`# argument.allowed = set(fields)existing = set(self.fields)for field_name in existing - allowed:self.fields.pop(field_name)class Meta:model = TestModelfields = '__all__'def _get_two_values(self, obj):if not hasattr(self, '_two_values'):self._two_values = obj.generateTwoValue()return self._two_valuesdef get_name_col(self,obj):name_col, _ = self._get_two_values(obj)return name_coldef get_age_col(self,obj):_, age_col = self._get_two_values(obj)return age_col
- 数据库迁移
python manage.py makemigrations
python manage.py migrate
- 创建view views.py
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from rest_framework import status
from testserializer.models import TestModel,TestModelSerializer
# Create your views here.
class TestView(GenericViewSet):queryset = TestModel.objects.all()serializer_class = TestModelSerializerdef list(self, request, *args, **kwargs):queryset = self.filter_queryset(self.get_queryset())page = self.paginate_queryset(queryset)if page is not None:serializer = self.get_serializer(page, many=True)return self.get_paginated_response(serializer.data)serializer = self.get_serializer(queryset, many=True)return Response(serializer.data)def create(self, request, *args, **kwargs):serializer = self.get_serializer(data=request.data)serializer.is_valid(raise_exception=True)serializer.save()return Response(serializer.data, status=status.HTTP_201_CREATED)
- 创建路由 urls.py
from django.conf.urls import url, include
from rest_framework import routers
from testserializer.views import TestViewroute = routers.DefaultRouter(trailing_slash=False)
route.register(r'test',TestView,'test')urlpatterns = [url(r'^',include(route.urls)),
]
访问:
http://127.0.0.1:9999/api/v1/test?fields=name,age
https://stackoverflow.com/questions/40663579/call-method-once-to-set-multiple-fields-in-django-rest-framework-serializer
https://joel-hanson.medium.com/advanced-serializer-usage-dynamically-modifying-fields-e7c3bc28efa6