DRF序列化和反序列化(一:Serializer)

一:表关系如下

from django.db import models

# Create your models here.
__all__=['Book','Publisher','Authon']

class   Book(models.Model):
     title =models.CharField(max_length=32,verbose_name='图书名称')
     CHOICES=((1,'python'),(2,'go'),(3,'linux'))
     category=models.IntegerField(choices=CHOICES,verbose_name='图书类别')
     pub_time=models.DateTimeField(verbose_name='出版日期')

     authon=models.ManyToManyField('Authon')
     publisher=models.ForeignKey(to='Publisher',on_delete=None)
     def __str__(self):
          return self.title
class Authon(models.Model):
     name= models.CharField(max_length=32, verbose_name='作者姓名')
     def __str__(self):
          return self.name
class  Publisher(models.Model):
     title = models.CharField(max_length=32, verbose_name='出版社名称')

     def __str__(self):
          return self.title  

二:使用django编写接口

  1:使用jsonResponse模块进行数据序列化。

from django.http import JsonResponse
class Bookview(View):
    #使用jsonResponse 当存在外键时,需要自己手动对数据进行处理。
    def get(self,request):
        book_list=models.Book.objects.values('id','title','pub_time','publisher',"category")
        book_list=list(book_list)

        for  book  in  book_list:
            print(book)
            publisher_id  = book['publisher']
            publisher_obj=models.Publisher.objects.filter(id=publisher_id).first()
            book['pulisher']={
                'id':publisher_id,
                'title':publisher_obj.title
            }

        return   JsonResponse(book_list,safe=False,json_dumps_params={'ensure_ascii':False})

 2:使用serialize模块进行数据序列化。

    def get(self,request):
        book_list=models.Book.objects.all()
        book_list=serializers.serialize('json',book_list,ensure_ascii=False )

        return   HttpResponse(book_list)

 3:使用serialize和JsonResponse不方便处

      a:遇到外键关系,需要非常繁琐的处理。

三:使用rest_framework 中 serializers进行序列化和反序列化

      1:基本准备

         a:下载 rest-framewoke模块,pip install rest-framework

         b:首先要明白后端展示给前端页面的数据,可能是经过跨表查询的具体值。而前端传送给后端,并不需要传送具体的值,也就是说前端和后端对同一个资源传递的数据类型可能不一样。比如性别,前端展示的是,男,女。但是后端在数据库存储的时候,往往是0,1

        c:新建文件serializers.py(用于编写序列化规则)

        d:settings中注册app

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'SerDemo',
    'rest_framework'    #app注册
]

  2:serializers序列化

         a:设定路由

            --注意需要调用as_view方法

from django.urls import path,include
from SerDemo import views
urlpatterns = [
    path('list/', views.BookApiView.as_view()),

]

      b:在serializes.py编写序列化规则

         --注意序列化规则内每一个字段都和models字段相对应。重点, 

         --外键关系一对多和多对多需要注意

         --read_only=True(只进行序列化),同理write_only=True(该字段只进行反序列化)

from rest_framework import serializers
from  SerDemo.models import Book
#一对多外键关系序列化处理
class  PublisherSerializers(serializers.Serializer):
     id = serializers.IntegerField()
     title=serializers.CharField(max_length=32)

#多对多外键关系序列化处理
class  AuthonSerializers(serializers.Serializer):
     id = serializers.IntegerField()
     name=serializers.CharField(max_length=32)

class  BookSerializers(serializers.Serializer):
    #不需要校验
    id = serializers.IntegerField(required=False,)
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, 'python'), (2, 'go'), (3, 'linux'))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display",read_only=True)
    pub_time = serializers.DateTimeField()
    #处理一对多
    publisher=PublisherSerializers(read_only=True)
    #处理多对多外键关系  many=True
    authon=AuthonSerializers(many=True,read_only=True)
    

  c:视图函数的编写

         --导包 (APIView,Response)

         --视图函数继承APIView  

         --many默认参数不写默认序列化一个对象,many=True 表示序列化多个对象

         --get请求会对应get方法

from  SerDemo import models
from  rest_framework.views import APIView     #视图函数继承APIView  不是View
from rest_framework.response import Response  #用于返回值
#BookSerializers  自己定义的序列化规则
from SerDemo.serializers import *

class BookApiView(APIView):
    def  get(self,request):
        book_obj = models.Book.objects.all()
        #序列化多组数据 和一个对象,需要many=TRUE  默认一个
       ret  =BookSerializers(book_obj,many=True)
        #序列化的数据在data属性中
        return  Response(ret.data)

  3:serializers反序列化

    a:在serializes.py编写反序列化规则   

       --首先序列化,我们常常需要把外键对象的值获取给前端,而反序列化,后端仅仅需要数据库一个id就能进行数据库值的插入。

       --write_only表示该字段只是反序列化使用,前端发送时key也应该和该值对应

       --注意一对多,多对多关系,choices的字段

class  BookSerializers(serializers.Serializer):
    #不需要校验
    id = serializers.IntegerField(required=False,)
    title = serializers.CharField(max_length=32,validators=[my_validata])
    CHOICES = ((1, 'python'), (2, 'go'), (3, 'linux'))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display",read_only=True)
    w_category=serializers.ChoiceField(choices=CHOICES,write_only=True)
    pub_time = serializers.DateTimeField()

    #处理一对多
    publisher=PublisherSerializers(read_only=True)
    publisher_id=serializers.IntegerField(write_only=True)

    #处理多对多外键关系  many=True
    authon=AuthonSerializers(many=True,read_only=True)
    authon_id =serializers.ListField(write_only=True)

    b:views文件中编写post的请求,对数据进行添加。

       --添加数据需要在BookSerializers重新编写create方法

       --注意返回值

       --所有的数据都在request.data方法中,(与View方法存在request.get,request.post中不同,该方法对这些方法进行封装)  

 def post(self,request):
        # print(request.data)
        data = BookSerializers(data=request.data)
        #进行数据验证,并且在BookSerializers中重写create方法
        if  data.is_valid():
            data.save()
            return Response(data.data)
        else:
            return Response(data.errors)

  c:编写create方法

class  BookSerializers(serializers.Serializer):
    #不需要校验
    id = serializers.IntegerField(required=False,)
    title = serializers.CharField(max_length=32,validators=[my_validata])
    CHOICES = ((1, 'python'), (2, 'go'), (3, 'linux'))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display",read_only=True)
    w_category=serializers.ChoiceField(choices=CHOICES,write_only=True)
    pub_time = serializers.DateTimeField()

    #处理一对多
    publisher=PublisherSerializers(read_only=True)
    publisher_id=serializers.IntegerField(write_only=True)

    #处理多对多外键关系  many=True
    authon=AuthonSerializers(many=True,read_only=True)
    authon_id =serializers.ListField(write_only=True)

    #向服务器添加数据,需要实现该方法
    def  create(self, validated_data):
       book =Book.objects.create(title=validated_data['title'],category=validated_data['w_category'],
                                 pub_time=validated_data['pub_time'],
                                 publisher_id=validated_data['publisher_id']
                                 )

       #添加多对多关系
       book.authon.add(*validated_data['authon_id'])

       return book

  d:put实现更新

        --路由分发   path('retrieve/<int:id>',views.BookEditView.as_view())

        --代码编写

            --partial参数

    def put(self,request,id):
        print(request.data)
        book_obj = Book.objects.filter(id=id).first()
        # partial   True 表示可以进行部分字段跟新,Flase 表示全部跟新,默认False
        book_serializers = BookSerializers(book_obj,data=request.data,partial=True)

        #需要重写 update
        if book_serializers.is_valid():
            book_serializers.save()
            return Response(book_serializers.validated_data)
        else:
            return Response(book_serializers.errors)

          --重写update方法

#数据跟新
    def  update(self, instance, validated_data):
         print(validated_data.get('authon'))
         instance.title =validated_data.get('title',instance.title)
         instance.category=validated_data.get('category',instance.category)
         instance.pub_time =validated_data.get('pub_time',instance.pub_time)
         instance.publisher_id =validated_data.get('publisher_id',instance.publisher_id)

         if  validated_data.get('authon_id'):
             instance.authon.set(validated_data.get('authon_id'))
         instance.save()
         return instance

  e:实现delete方法

    def  delete(self,request,id):
        book_obj = Book.objects.filter(id=id).first()
        book_obj.delete()
        return  Response("")

   4:serializers字段校验扩展

    a:局部钩子校验

         --校验字段方法,固定格式validate_字段名

         -- 参数value,就是该字段的值

         -- 返回值 

#单个字段进行校验
    def   validate_title(self, value):
        if  'python' not in value.lower:
            return  serializers.ValidationError('标题必须含有python')
        return value

 b:全局钩子多个字段联合校验

    --方法 validate为固定方法

    --attrs保存联合字段的字段值

    --注意返回值

    #全局钩子对字段进行联合校验
    def  validate(self, attrs):
        if  attrs['category'] =='linux' and  attrs['publisher_id']==3:
            return attrs
        else:
            return serializers.ValidationError('类型或出版社错误')

  c:自定义钩子验证 

#自定义校验
#在需要进行验证的字段引用  title = serializers.CharField(max_length=32,validators=[my_validata])
#优先级大于 validata_title 局部钩子
def  my_validata(value):
    if value in '敏感信息':
        raise serializers.ValidationError('不能含有敏感信息')
    return value

  

  

 

  

 

posted @ 2019-03-26 21:31  pyjar  阅读(1100)  评论(0编辑  收藏  举报