Dan*_*gen 85 django django-rest-framework
根据blogpost 设计实用RESTful API的最佳实践中的建议,我想在fields
基于Django Rest Framework的API中添加一个查询参数,使用户只能为每个资源选择一个字段子集.
串行:
class IdentitySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Identity
fields = ('id', 'url', 'type', 'data')
Run Code Online (Sandbox Code Playgroud)
常规查询将返回所有字段.
GET /identities/
[
{
"id": 1,
"url": "http://localhost:8000/api/identities/1/",
"type": 5,
"data": "John Doe"
},
...
]
Run Code Online (Sandbox Code Playgroud)
带fields
参数的查询应该只返回字段的子集:
GET /identities/?fields=id,data
[
{
"id": 1,
"data": "John Doe"
},
...
]
Run Code Online (Sandbox Code Playgroud)
包含无效字段的查询应忽略无效字段或抛出客户端错误.
这有可能开箱即用吗?如果没有,实现这个的最简单方法是什么?是否有第三方包已经这样做了吗?
小智 100
您可以根据查询参数覆盖序列化程序__init__
方法并fields
动态设置属性.您可以访问request
上下文的对象,传递给序列化程序.
在这里,我创建了一个可重用的mixin,它可以进行动态__init__
修改.
from rest_framework import serializers
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
"""
A ModelSerializer that takes an additional `fields` argument that
controls which fields should be displayed.
"""
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)
class UserSerializer(DynamicFieldsModelSerializer, serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email')
Run Code Online (Sandbox Code Playgroud)
wim*_*wim 46
此功能可从第三方软件包中获得.
pip install djangorestframework-queryfields
Run Code Online (Sandbox Code Playgroud)
像这样声明你的序列化器:
from rest_framework.serializers import ModelSerializer
from drf_queryfields import QueryFieldsMixin
class MyModelSerializer(QueryFieldsMixin, ModelSerializer):
...
Run Code Online (Sandbox Code Playgroud)
然后,现在可以使用查询参数指定字段(客户端):
GET /identities/?fields=id,data
Run Code Online (Sandbox Code Playgroud)
排除过滤也是可能的,例如,返回除 id 之外的每个字段:
GET /identities/?fields!=id
Run Code Online (Sandbox Code Playgroud)
免责声明: 我是作者/维护者.
class DynamicFieldsSerializerMixin(object):
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop('fields', None)
# Instantiate the superclass normally
super(DynamicFieldsSerializerMixin, 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.keys())
for field_name in existing - allowed:
self.fields.pop(field_name)
class UserSerializer(DynamicFieldsSerializerMixin, serializers.HyperlinkedModelSerializer):
password = serializers.CharField(
style={'input_type': 'password'}, write_only=True
)
class Meta:
model = User
fields = ('id', 'username', 'password', 'email', 'first_name', 'last_name')
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username'],
email=validated_data['email'],
first_name=validated_data['first_name'],
last_name=validated_data['last_name']
)
user.set_password(validated_data['password'])
user.save()
return user
Run Code Online (Sandbox Code Playgroud)
class DynamicFieldsViewMixin(object):
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
fields = None
if self.request.method == 'GET':
query_fields = self.request.QUERY_PARAMS.get("fields", None)
if query_fields:
fields = tuple(query_fields.split(','))
kwargs['context'] = self.get_serializer_context()
kwargs['fields'] = fields
return serializer_class(*args, **kwargs)
class UserList(DynamicFieldsViewMixin, ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
34863 次 |
最近记录: |