restful之序列化
1.前序
简单表结构:
class Publisher(models.Model): name = models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): author_name = models.CharField(max_length=22) def __str__(self): return self.author_name class Book(models.Model): title = models.CharField(max_length=32,verbose_name="图书名字") CHOICE = ((1,"PYTHON"),(2,"VUE"),(3,"GO"),(4,"JAVA")) category = models.IntegerField(choices=CHOICE) put_time = models.DateField() publisher = models.ForeignKey(to="Publisher") authors = models.ManyToManyField(to="Author") class Meta: # db_table 指定了表名 db_table= "book_list" # verbose_name_plural表示复数形式的显示;中文的单数和复数一般不作区别 verbose_name_plural = db_table
url
urlpatterns = [ url(r'^books/', views.BookView.as_view(),name="book"), url(r'^publisher/(?P<pk>\d+)',views.PublisherView.as_view(),name='pub') ]
视图
class BookView(APIView): def get(self,request,*args,**kwargs): all_obj = models.Book.objects.all() #添加hypermedialink 生成链接 必须加context,否则报错 ser_book = BookSerializer(instance=all_obj,many=True,context={"request":request}) return Response(ser_book.data) class PublisherView(APIView): def get(self,request,pk,*args,**kwargs): print(pk) return Response({"error":400})
2.get请求
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework import serializers
from api import models
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = models.Author
fields = '__all__'
class MyField(serializers.CharField):
"""自定义序列化"""
def to_representation(self, value):
new_value = '《{}》'.format(value)
return new_value
CHOICES = ((1, "Python"), (2, "Linux"), (3, "go"))
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
# 一对多关系,可以用source= 外键名.另一张表字段
pub_name = serializers.CharField(source="publisher.name")
title = serializers.CharField(max_length=32)
#choice字段序列化:读取 通过get_字段_display 可以获取该CHOICE元组第二设置的值
category = serializers.CharField(max_length=32, source="get_category_display", read_only=True)
#写入
post_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
put_time = serializers.DateField()
#多对多关系,定义SerializerMethodField,+ 定义get_多对多字段方法
author = serializers.SerializerMethodField()
#自定义序列化器,source指向title字段
new_title = MyField(source="title")
# 通过hypermedialink 生成publisher的链接:
# view_name :可以根据它找到路由配置的url
# 为Book表关联Publisher的id,传入url设置的参数,这里设置的是id.
pub_url = serializers.HyperlinkedIdentityField(view_name='pub',lookup_field='publisher_id',lookup_url_kwarg="pk")
#对字段进行处理
msg = serializers.SerializerMethodField()
def get_author(self,obj):
author = obj.authors.all()
auth = AuthorSerializer(author,many=True)
return auth.data
def get_msg(self, instance):
# self.context为一个字典, a 里面封装如下字段
"""
{
'_request': < WSGIRequest: GET '/books/' > ,
'parsers': [ < rest_framework.parsers.JSONParser object at 0x000002E3B5E5F470 > , < rest_framework.parsers.FormParser object at 0x000002E3B60D3828 > , < rest_framework.parsers.MultiPartParser object at 0x000002E3B60D3860 > ],
'authenticators': [ < rest_framework.authentication.SessionAuthentication object at 0x000002E3B60D3898 > , < rest_framework.authentication.BasicAuthentication object at 0x000002E3B60D38D0 > ],
'negotiator': < rest_framework.negotiation.DefaultContentNegotiation object at 0x000002E3B5E5F518 > ,
'parser_context': {
'view': < api.views.BookView object at 0x000002E3B59F5AC8 > ,
'args': (),
'kwargs': {},
'request': < rest_framework.request.Request object at 0x000002E3B60D3908 > ,
'encoding': 'utf-8'
},
'_data': < class 'rest_framework.request.Empty' > ,
'_files': < class 'rest_framework.request.Empty' > ,
'_full_data': < class 'rest_framework.request.Empty' > ,
'_content_type': < class 'rest_framework.request.Empty' > ,
'_stream': < class 'rest_framework.request.Empty' > ,
'accepted_renderer': < rest_framework.renderers.BrowsableAPIRenderer object at 0x000002E3B60D39E8 > ,
'accepted_media_type': 'text/html',
'version': None,
'versioning_scheme': None,
'_authenticator': None,
'_user': < django.contrib.auth.models.AnonymousUser object at 0x000002E3B60D3B00 > ,
'_auth': None
}
"""
a = self.context.get("request")
print(a.__dict__)
return "id:%s,title:%s"%(instance.id,instance.title)
3.序列化post请求:
- 把之前序列化简单一下,因为之前序列化为了多的介绍一下功能:
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
pub_name = serializers.CharField(source="publisher.name",read_only=True)
category_name = serializers.CharField(max_length=32, source="get_category_display", read_only=True)
put_time = serializers.DateField()
author = serializers.SerializerMethodField(read_only=True)
title = serializers.CharField(max_length=32)
#标注write_only表示,写入时候会序列化的字段
post_category = serializers.ChoiceField(choices=CHOICES, write_only=True,validators=[about_choice,])
# required=True 表示这个字段不能为空
post_author = serializers.ListField(write_only=True,required=True)
post_pub = serializers.IntegerField(write_only=True,required=True)
def get_author(self,obj):
author = obj.authors.all()
auth = AuthorSerializer(author, many=True)
return auth.data
# 用于发送post请求 创建数据
def create(self,validated_date):
# validated_date为request.data处理后数据
book_obj = models.Book.objects.create(
title = validated_date["title"],
put_time = validated_date['put_time'],
category = validated_date['post_category'],
publisher_id = validated_date['post_pub'],
)
# 多对多关系 存储
book_obj.authors.set(validated_date['post_author'])
return book_obj
- 当我们发送post请求时候,如下图:
- 那么接下来如下在视图中:
class BookView(APIView):
def get(self,request,*args,**kwargs):
...
def post(self,request,*args,**kwargs):
# 首先将请求数据放入序列化器中..
ser_obj = BookSerializer(data=request.data)
# 对其进行验证。
if ser_obj.is_valid():
#没有错误保存
ser_obj.save()
#返回结果
return Response(ser_obj.data)
#存在错误,返回错误信息
return Response(ser_obj.errors)
4.验证:
那么对于提交数据如何验证呢?restframwork提供3种验证方式。
字段内添加validators
def about_choice(value):
print(type(value))
if value == 2:
raise serializers.ValidationError('图书类型不能是2')
return value
# 字段
post_category = serializers.ChoiceField(choices=CHOICES, write_only=True,validators=[about_choice,])
上面给post_category添加一个验证,验证函数是about_choice,如果该字段的值为2会引发一个错误。
- 序列化器定义:validate_字段名
def validate_title(self, attrs):
if 'python' in attrs:
raise serializers.ValidationError("python存在书名中..")
return attrs
# 意思是如果python这个字符串在title字段里,就会引发一个错误。
- 多个字段验证:直接在序列化器里定义validate
def validate(self, attrs):
title = attrs['title']
post_pub = attrs['post_pub']
if title == 'python' and post_pub == 1:
raise serializers.ValidationError("非法输入")
return attrs
# 意思是如果python这个字段在title里,并且post_pub等于1会引发一个错误
5.序列化get请求单个数据
- 请求单个数据
- url定义
url(r'^books/(?P<pk>\d+)/', views.BookView.as_view(),name="book"),
- 视图中定义
class BookView(APIView):
def get(self,request,pk,*args,**kwargs):
if pk:
book_obj = models.Book.objects.filter(pk=pk)
else:
book_obj = models.Book.objects.all()
# 注意如果是单个book_obj对象,需要去除掉many=True
ser_book = BookSerializer(instance=book_obj,many=True,context={"request":request})
- 序列化都一样
6.序列化更新单个数据
- 视图函数定义put方法
def put(self,request,pk,*args,**kwargs):
book_obj = models.Book.objects.filter(pk=pk).first()
ser_obj = BookSerializer(instance=book_obj,data=request.data)
if ser_obj.is_valid():
ser_obj.save()
return Response(ser_obj.data)
return Response(ser_obj.errors)
- 序列化器定义update
def update(self,instance,validated_data):
# instance为Book对象,validated_data为request.data数据
instance.title = validated_data.get("title",instance.title)
instance.put_time = validated_data.get("put_time",instance.put_time)
# 外键对应
instance.publisher_id = validated_data.get("post_pub", instance.publisher_id)
instance.save()
instance.authors.set(validated_data.get("post_author",instance.authors.all()))
return instance
#对于外键更新:外键字段_id
#对于多对多更新: 通过set方式更新
7.序列化删除单个数据
- 视图定义delete方法
def delete(self,request,pk,*args,**kwargs):
obj = models.Book.objects.filter(pk=pk).first()
if obj:
obj.delete()
return Response({"message":"删除成功"})
return Response({"message":"数据不存在"})