更新记录
2016-01-26 初稿
序列化时嵌套显示外键关联字段
自动
使用depth
参数指定外键深度手动指定
使用外键对应model
的小写为属性,外键对应的model
序列化程序为值
以下例子在HospitalPic
序列化结果里嵌套显示Hospital
models.py1
2
3
4
5
6
7from django.db import models
class Hospital(models.Model):
name = models.CharField()
class HospitalPic(models.Model):
hospital = models.ForeignKey(Hospital)
serializers.py
1
2
3
4
5
6from rest_framework import serializers
class HospitalSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Hospital
fields = '__all__'
class HospitalPicSerializer(serializers.HyperlinkedModelSerializer):
hospital = HospitalSerializer()
class Meta:
model = HospitalPic
fields = '__all__'
1 | ***反向关系嵌套*** |
在序列化对象里添加关联表的字段内容
定义一个serializer Field
,并添加参数source
指向外键对对应的字段(source
值其实是从当前序列化的实例的属性)1
my_address= serializers.ReadOnlyField(source='address.full_address')
在序列化对象里添加自定义内容
1 | from django.contrib.auth.models import User |
使用ViewSet
,并不有设置queryset
,而是重写了get_queryset
时,需要在router
里增加base_name
参数(base_name
为router
为ViewSet
注册url时自动添加的name前缀,如果未设置则从ViewSet
的queryset
里取,使用ViewSet
自动生成的url name为<base_name>-list <base_name>-detail 等)
views.py1
2
3
4
5
6class ContactViewSet(viewsets.ModelViewSet):
serializer_class = ContactSerializer
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self):
return self.request.user.contact_set.all()
urls.py1
router.register(r'contact', ContactViewSet, base_name='contact')
未设置base_name
会报下面错误1
'base_name' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.
给api接口的url添加了命名空间namespace
urls.py1
url(r'^api/', include(router.urls, namespace='api')),
需要对HyperlinkedRelatedField
字段的参数进行修改
serializers.py1
2
3
4
5
6
7
8class HospitalPicSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = HospitalPic
fields = '__all__'
extra_kwargs = {
'url': {'view_name': 'api:hospitalpic-detail'},
'hospital': {'view_name': 'api:hospital-detail'}
}
不然会出现以下错误1
Could not resolve URL for hyperlinked relationship using view name "user-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
不过话说我们全api的url加namespace
一般是为了版本控制,所以有一种简单的方法,只要在settings.py添加基于namespace
的版本控制,这样就不需要修改HyperlinkedRelatedField
字段的view_name
了
urls.py1
2url(r'^api/v1/', include(router.urls, namespace='v1')),
url(r'^api/v2/', include(router.urls, namespace='v2')),
settings.py1
2
3
4
5REST_FRAMEWORK = {
……
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning',
……
}
要drf的错误提示为中文,需要设置
1 | LANGUAGE_CODE = 'zh-CN' |
如果设置为1
LANGUAGE_CODE = 'zh-Hans'
虽然django默认表单错误会输出中文,但drf还是输出英文
django的validators
可以直接在drf中使用,不需要做任何修改
当字段里的属性editable=False
时,ModelSerializer
里该字段会抛弃model
里显式和隐式(unique)的所有validators
Serializer
里write_only
写在field
里和写在extra_kwargs
里是有区别的,
1 | class UserRegisterSerializer(serializers.ModelSerializer): |
因为create()
这个方法return了一个user
实例,User
里没有的字段code
和re_password
需要将write_only
写在field
参数里,不然会报以下错误1
2
3AttributeError: Got AttributeError when attempting to get a value for field `code` on serializer `UserRegisterSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `User` instance.
Original exception text was: 'User' object has no attribute 'code'.
如果使用django-rest-swagger
报以下错误
1 | Can't read from server. It may not have the appropriate access-control-origin settings. |
注释掉设置里的1
# 'base_path': '127.0.0.1:8000/docs',
serializer.data
和serializer.validated_data
在serializer
只使用data
参数实例化的时:
serializer.data
是原始数据(字符串),serializer.validated_data
是进行数据验证并转换成对应数据类型的数据。- 两者者必须在
serializer
调用is_valid
方法后才能调用
在serializer
只使用instance
参数实例化时: - 只有
serializer.data
没有serializer.validated_data
,并且serializer.data
里的数据也是字符串; - 没有方法
is_valid
; - 即
is_valid
和validated_data
只在有data参数实例化时才可调用;
在serializer
里获取原始请求信息
默认的,上下文信息会被传递到serializer
里,所以在serializer
可以直接使用self.context['request']
来获取请求信息。(在要继承自viewsets.GenericViewSet
的类里使用的serializer
才能取到,如果是继承APIView
的,自己传入即可serializer = self.serializer_class(data=request.data, context={'request': request})
)
自定义serializer
字段
自定义字段继承serializers.Field
,to_representation
方法处理出来的数据用来序列化显示,to_internal_value
处理接收到的数据,get_attribute
方法指定这个字段访问的实例属性,get_value
方法指定1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16class QiNiuField(serializers.Field):
def get_attribute(self, instance):
# (序列化时)从模型实例中取一个值给这个字段处理,也可以使用`source`参数指定
return instance.key
def get_value(self, dictionary):
# (反序列化时)从传入数据中提取一个值给这个字段处理
return super(QiNiuField, self).get_value(dictionary)
def to_representation(self, value):
# (序列化时)处理出来的数据用来序列化显示
return value.url
def to_internal_value(self, data):
# (反序列化时)处理接收到的数据
return data['key']
嵌套序列化,传参问题
官方文档中有这么一个例子Dealing with nested objects
如果是以Content-Type:application/json
形式传数据格式传数据,直接嵌套传就可以了{'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'}
,但如果是以,
但是如果以Content-Type:form-data
或Content-Type:x-www-form-urlencoded
上传,则上传user
信息进不是嵌套,而是就.
连接了,"user.email":"foobar"
.