Serializer 类
- 指定序列化需要返回的 field,source为指定数据库字段,可以通过 ‘. ’ 获取外键关联对象。
- get_xxx_display 获取CharField choices 对应的值
- SerializerMethodField:自定义方法,执行实例化对象的 get_obj() 方法
- 每个field对象触发的to_representation方法 。
class AccountSerializers(serializers.Serializer):
name = serializers.CharField(source='username')
status = serializers.CharField(source='get_status_display') #拿到choice
gender = serializers.CharField(source='get_gender_display')
gp = serializers.CharField(source='group.group_name')
user_roles = serializers.SerializerMethodField()
gender_toast = serializers.SerializerMethodField()
def get_gender_toast(self, obj):
if obj.status == '1':
return "英俊潇洒"
def get_user_roles(self, obj):
return obj.roles.values_list('name', flat=True)
ModelSerializer 类
内部实现fields的映射:serializer_field_mapping
serializer_field_mapping = {
...
models.CharField: CharField,
models.CommaSeparatedIntegerField: CharField,
models.DateField: DateField
....
}
直接指定返回字段获取自定义返回字段。
class Myfield(serializers.BaseSerializer):
"""
自定义field, 实现to_representation方法。
"""
def to_representation(self, value):
result = value.values_list('name', flat=True)
return result
class AccountSerializers(serializers.ModelSerializer):
gp = serializers.CharField(source='group.group_name', allow_null=True)
user_roles = serializers.SerializerMethodField()
#自定义field
my_roles = Myfield(read_only=True, source='roles.all')
#返回路由系统对应的链接。xxx为传递的参数名
# re_path(r"^group/(?P<xxx>\w+)", views.GroupsView.as_view(),
# name='user_group')
# 序列化时,需要传递 request参数,例如:
# serializers = AccountSerializers(accounts,many=True, context={'request':request})
# serilizer:user_group(app_name+view_name)
group_link = serializers.HyperlinkedIdentityField(
view_name='serilizer:user_group',
lookup_field='group_id',
lookup_url_kwarg='xxx',
)
class Meta:
model = AccountModel
# fields = '__all__'
# 额外返回参数
extra_kwargs = {'ggg': {'source': 'get_gender_display'}}
# 需返回参数
fields = ['username', 'gp', 'user_roles', 'ggg', 'my_roles', 'group_link']
# 除了列表中,全部返回
# exclude = ['id', 'roles', 'group']
# 如果你想要显示多对多字段外键的所有字段 用depth=1
# depth = 1
def get_user_roles(self, obj):
return obj.roles.values_list('name', flat=True)
#output:
[
{
"username": "donghao",
"gp": "第一组",
"user_roles": [
"学生",
"it",
"worker"
],
"ggg": "男",
"my_roles": [
"学生",
"it",
"worker"
],
"group_link": "http://127.0.0.1:8000/api/group/1"
},
{
"username": "ttt",
"gp": null,
"user_roles": [],
"ggg": "男",
"my_roles": [],
"group_link": "http://127.0.0.1:8000/api/group/None"
}
]
源码流程
- 进行序列化,实例化对象,执行
BaseSerializer
的 __new__ , __init__ 方法。 - 根据serializer类(是否指定many参数,默认False),分配给不容的serializer处理。
def __new__(cls, *args, **kwargs):
# `ListSerializer` classes instead when `many=True` is set.
if kwargs.pop('many', False):
#交给 ListSerializer 类处理, 执行其 __init__方法
return cls.many_init(*args, **kwargs)
return super().__new__(cls, *args, **kwargs) #执行baseserializer __init__ 方法
- 执行serializer.data时,执行BaseSerializer类的data方法,再执行系列化对象的 to_representation 方法。
当是返回单个instance时,执行serializer.to_representation() 方法
当是返回列表时,执行listserializer.to_representation()方法, 遍历每一个对象,执行to_representation方法
# self.child = kwargs.pop('child', copy.deepcopy(self.child))
return [self.child.to_representation(item) for item in iterable]
to_representation:
for field in fields: #循环每个字段
try:
attribute = field.get_attribute(instance)
except SkipField:
continue
get_attribute:
def get_attribute(instance, attrs):
# self.source_attrs = self.source.split('.') 通过 ' . '分割符号,连续去取相关的值,然后重新赋值
for attr in attrs:# 循环取外键关联对象
try:
if isinstance(instance, Mapping):
instance = instance[attr]
else:
instance = getattr(instance, attr)
except ObjectDoesNotExist:
return None
# 是可以执行的一个函数。则直接调用。例如get_xxx_display等...
if is_simple_callable(instance): #isinstance(object, types.FunctionType)
try:
instance = instance()
except (AttributeError, KeyError) as exc:
raise ValueError('Exception raised in callable attribute "{}"; original exception was: {}'.format(attr, exc))
return instance
demo代码
views:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.parsers import JSONParser
from rest_framework.status import HTTP_200_OK, HTTP_404_NOT_FOUND
from .serializers import AccountSerializers, GroupSerializers
from .models import AccountModel, GroupModel
class CreateAccount(APIView):
parser_classes = [JSONParser, ]
def post(self, request):
AccountModel.objects.create(**request.data)
return Response(data='ok', status=HTTP_200_OK)
class AllAccounts(APIView):
def get(self, request):
accounts = AccountModel.objects.all()
serializers = AccountSerializers(accounts, many=True, context={'request': request})
return Response(data=serializers.data, status=HTTP_200_OK)
class GroupsView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get("xxx", None)
if not pk or pk == 'None':
return Response(status=HTTP_404_NOT_FOUND)
groups = GroupModel.objects.get(pk=pk)
serializers = GroupSerializers(groups, many=False)
return Response(data=serializers.data, status=HTTP_200_OK)
models 模型:
from django.db import models
class AccountModel(models.Model):
Gender = (
('0', '未知'),
('1', '男'),
('2', '女'),
)
STATUS = (
('0', '冻结'),
('1', '正常'),
('2', '删除'),
)
phone = models.CharField('手机号', max_length=11, blank=True, null=True)
username = models.CharField('姓名', max_length=10, blank=True, null=True)
wechat = models.CharField('微信号', max_length=150, blank=True, null=True)
gender = models.CharField("性别", choices=Gender, default='0', max_length=1)
status = models.CharField('状态', max_length=10, choices=STATUS, default='1')
group = models.ForeignKey("GroupModel", on_delete=models.PROTECT, null=True)
roles = models.ManyToManyField("RoleModel")
class GroupModel(models.Model):
group_name = models.CharField("组名", max_length=10)
class RoleModel(models.Model):
name = models.CharField("角色名", max_length=10)
局部urls:
from django.urls import path, re_path
from . import views
from rest_framework.urlpatterns import format_suffix_patterns
app_name = "serilizer" # serializers 打错
urlpatterns = [
path("account_create/", views.CreateAccount.as_view(), name='account_create'),
path("accounts/", views.AllAccounts.as_view(), name='accounts'),
re_path(r"^group/(?P<xxx>\w+)", views.GroupsView.as_view(),
name='user_group')
]