动态修改字段可以使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 superclass
request = kwargs.get('context', {}).get('request')
str_fields = request.GET.get('fields', '') if request else None
fields = str_fields.split(',') if str_fields else None
# Instantiate the superclass normally
super(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 = TestModel
fields = '__all__'
def _get_two_values(self, obj):
if not hasattr(self, '_two_values'):
self._two_values = obj.generateTwoValue()
return self._two_values
def get_name_col(self,obj):
name_col, _ = self._get_two_values(obj)
return name_col
def 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 = TestModelSerializer
def 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 TestView
route = 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