序列化

#序列化组件是干什么的,
#数据需要处理,不可能把queryset对象传给前台

 

一、自己用for循环处理(太麻烦)

class Books(APIView):
    def get(self,request,*args,**kwargs):
        response = {'status': 100, 'data': None}   
        ret=models.Book.objects.all()
        print(ret)
#<QuerySet [<Book: 西游记>, <Book: 红楼梦>, <Book: 三国演义>, <Book: 水浒传>]>
        l1=[{'name':book.name} for book in ret]
        l2=[{'name':book.name,'price':book.price} for book in ret]        #展示的字段可控
        print(l1)
        print(l2)      
#[{'name': '西游记'}, {'name': '红楼梦'}, {'name': '三国演义'}, {'name': '水浒传'}]


#[{'name': '西游记', 'price': Decimal('11.00')}, {'name': '红楼梦', 'price': Decimal('22.00')}, {'name': '三国演义', 'price': Decimal('23.00')}, {'name': '水浒传', 'price': Decimal('3.00')}]

        response['data'] = l1
        return JsonResponse(response,  json_dumps_params={'ensure_ascii': False})

 

 

 

二、用django提供的序列化组件

# django提供的序列化组件(不可控,展示所有字段,有时候我们并不需要)
#导入   from django.core import serializers
        ret=serializers.serialize('json','queryset对象')
        ret就是序列化之后的字符串了,不需要再序列化了

from django.core import serializers
class Books(APIView):
    def get(self,request):
        response = {'status': 100, 'data': None}
        books = models.Book.objects.all()

        # 先构造出所有书籍的字典的列表
        # 用django提供的序列化组件
        ret=serializers.serialize('json',books)
        print(ret)

        # 返回数据是json格式数据
        response['data'] = ret
        return HttpResponse(ret)

 

 

三、rest-framework序列化之Serializer

from django.db import models

# Create your models here.


class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.IntegerField()
    pub_date=models.DateField()
    publish=models.ForeignKey("Publish")
    authors=models.ManyToManyField("Author")
    def __str__(self):
        return self.title

class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.EmailField()
    def __str__(self):
        return self.name

class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    def __str__(self):
        return self.name
models部分

mySer.py

#可以在views.py中直接写,也可创建一个py文件,在里边写
mySer.py
#1 先导入from rest_framework import serializers

#2 写一个类,继承serializers.Serrializer  
class BookSerializer(serializers.Serializer):     #在类内部写想要的字段
    name = serializers.CharField()
    xx = serializers.CharField(source='name')   #同上,就把字段名改为xx           
    price= serializers.CharField()              
    publish = serializers.CharField()         #支持跨表查询      
    test = serializers.CharField(source='publish.test')   #指定函数


另外,source不仅可以指定字段,也可以指定方法(函数),拿到的是函数的返回结果,没有return,则拿到None
-------------------------------------------------------------------
class BookSerializer(serializers.Serializer):

     publish=serializers.SerializerMethodField()
    # 方法名:叫get_字段名,要传参数,参数是:当前book对象
    def get_publish(self,obj):
        # obj 是当前book对象
        dic={'name':obj.name,'email':obj.publish.email}
        return dic

 

views.py

# 使用:

from app01 import models
from rest_framework.views import APIView
from app01.mySer import BookSerializer
from django.http import JsonResponse


class Book(APIView):
    def get(self,request,*args,**kwargs):
        ret = models.Book.objects.all()   #拿到所有queryset对象

        book_serializer = BookSerializer(instance=ret,many=True)   #需要的两个参数

        return JsonResponse(book_serializer.data,safe=False)

#先生成对象,需要传参数 instance:要序列化的对象   (可能是queryset,也可能是单个对象)    
#序列化多条  many=True

#instance可不写,按位置传参
View Code

 

上边的是一对多字段,多对多字段

class BookSerializer(serializers.Serializer):
   publish=serializers.SerializerMethodField()
    def get_publish(self,obj):
        dic={'name':obj.publish.name,"city":obj.publish.city}
        return dic
#方式一
    authors = serializers.SerializerMethodField()
    def get_authors(self,obj):
        aus=obj.authors.all()
        li=[]
        for a in aus:        #通过for循环拿到所有作者
            c=li.append({'name':a.name,'age':a.age})
            return c
#方式二
    authors = serializers.SerializerMethodField()
    def get_authors(self,obj):
        aus = obj.authors.all()      #拿到书的所有作者
        aus_author = AuthorSerializer(aus,many=True)
        return aus_author.data
SerializerMethodField

 

 

四、rest-framework序列化之ModelSerializer

#上边的都需要手动写字段

class BookSerializers(serializers.ModelSerializer):

    class Meta:       #必须写这么一个类
        model = models.Book     #指定模型表
        # fields = "__all__"         #展示所有字段
        fields=['nid','title','authors','publish']      #展示指定字段

# exclude=('nid',) # 哪个字段不展示 # depth = 1 #深度控制,写 几 往里拿几层,层数越多,响应越慢, #重写属性(如果没有指定deoth,内层的仅显示id,也就是跨表的字段没有显示出来,仅显示当前表,) publish=serializers.SerializerMethodField() def get_publish(self,obj): return obj.publish.name authors=serializers.SerializerMethodField() def get_authors(self,obj): ret=obj.authors.all() ss=AuthorSerializer(ret,many=True) return ss.data

 

五、生成hypermedialink(快速生成链接)

#关键是怎么拼接"http://127.0.0.1:8000/publish/1"这个域名

views.py

from app01.mySer import BookSerializer
from django.http import JsonResponse,HttpResponse
from app01 import models

from rest_framework.views import APIView
class Books(APIView):
    def get(self,request,*args,**kwargs):
        ret = models.Book.objects.all()
        book_ser = BookSerializer(ret, many=True, context={'request': request})
          # context={'request': request},可以从request中拿到http://127.0.0.1:8000
     
        return JsonResponse(book_ser.data,safe=False)

class Publish(APIView):
    def get(self,request,*args,**kwargs):
        return HttpResponse('ok')

urls.py

url(r'^publish/(?P<pk>\d+)',views.Books.as_view(),name='pub_link_name'),
#name='pub_link_name,取别名,方便反向解析

mySer.py

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    name = serializers.CharField()
    # publish = serializers.CharField()
    publish = serializers.HyperlinkedIdentityField(view_name='pub_link_name',lookup_field='publish_id',lookup_url_kwarg='pk')


#view_name='pub_link_name',就是urls中的name,这里拿到publish

#lookup_field:根据表的哪个字段,来拼路径

#,lookup_url_kwarg='pk',反向解析有名分组的名字

 

 

六、请求数据校验与保存

class BookSerializers(serializers.ModelSerializer):
    class Meta:
        model=Book
        fields="__all__"

#————————
class BookView(APIView):

    def post(self, request):
        books=BookSerializers(data=request.data)     #books是BookSerializers的对象
        if books.is_valid(): #是否校验通过
            bs.save()      #把数据同步到数据库 
                            # BookSerializers中没有save方法,找父类,ModelSerializer有,
如果BookSerializers继承的是serializers.Serializer,该类中没有save方法,所以只有继承了ModelSerializer才能掉用save方法
            return Response(bs.data)
        else:

            return Response(bs.errors)                
新增

 

# 前提:
# 1)序列化类中不能修改原字段的深度
# 2)通过 data=请求数据包 得到可以操作orm的序列化对象,instance来明确修改的对象,校验成功后还是走save()来更新
# 3)必须先校验,才能保存或更新

#
class Books(APIView):
    """
    {
        "name":"水浒传",
        "price":"88.88",
        "author":[1, 2, 3 ]
    }
    """
    def post(self, request):
        book_dic = request.data
        book_json = objson.BookJson(data=book_dic)
           # 数据的校验
        if book_json.is_valid():
            book_json.save()  # 不涉及跨表操作
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': book_json.data
        })
# 查改删
class Book(APIView):
    def get(self, request, id):
        book_obj = models.Book.objects.filter(pk=id).first()
        book_data = objson.BookJson(book_obj).data
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': book_data
        })
    def put(self, request, id):
        book_obj = models.Book.objects.filter(pk=id).first()
        # instance来明确修改的对象,校验成功后还是走save()来保存
        book_json = objson.BookJson(data=request.data, instance=book_obj)
        if book_json.is_valid():
            book_json.save()
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': book_json.data
        })
    def delete(self, request, id):
        models.Book.objects.filter(pk=id).delete()
        return Response({
            'status': 2,
            'msg': 'delete success',
        })
增删改

 

# views.py
class Books(APIView):
    def post(self, request):
        book_dic = request.data
        book_json = objson.BookJson(data=book_dic)
           # 数据的校验
        if book_json.is_valid():
            # book_json.save()  # 不涉及跨表操作
            return Response({
                'status': 0,
                'msg': 'ok',
                'results': book_json.data
            })
        return Response({
            'status': 0,
            'msg': book_json.errors,
        })

    
# objson.py
class BookJson(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = '__all__'

    # 认证
    name = serializers.CharField(
        max_length=5,
        min_length=1,
        error_messages={
            "max_length": "太长了",
            "min_length": "太短了",
        }
    )

    # 局部钩子
    def validate_name(self, value):
        from rest_framework.exceptions import ValidationError
        if 'sb' in value:
            raise ValidationError("出现了敏感词汇")
        return value


    # def validate_price(self, value):
    #     from rest_framework.exceptions import ValidationError
    #     if float(value) < 0:
    #         raise ValidationError("价格不合理")
    #     return
    
    
    
# 了解:如果多个字段直接协同校验,采用全局钩子
def validate(self, attrs):
    from rest_framework.exceptions import ValidationError
    pwd = attrs.get('pwd')
    re_pwd = attrs.get('re_pwd')
    if pwd == re_pwd:
        return attrs
    else:
        raise ValidationError('密码校验失败')
数据校验

 

posted @ 2019-05-17 08:02  pdun  阅读(194)  评论(0编辑  收藏  举报