• Django高级篇二。引用restful写接口。序列化组件基本使用


    一、实现前后端分离,前后端数据交互均已json字符串形式

       路由模式,FBV. ==> url(r'^books/', views.books),

    1)使用原生的json模型

    # 请求 http://127.0.0.1:8000/books/
    # [{"name": "python", "price": 20}, {"name": "linux", "price": 30}]
    import json
    def books(request):
        ll = [{'name':'python','price':20},
               {'name':'linux','price':30}]
        return HttpResponse(json.dumps(ll))

    2)使用JsonResponse。默认safe=True

    from django.http import JsonResponse
    def books(request):
        ll = [{'name':'python','price':20},
               {'name':'linux','price':30}]
        return JsonResponse(ll,safe=False)

     注意在返回数据时,如果是列表类型需要加上fafe=False,其他则不用

    3)在传输json数据时,如果传输中文会出现乱码的情况。需要加参数 ensure_ascii=False

    import json
    dic = {'name':'你好'}
    print(json.dumps(dic,ensure_ascii=False))

    4)在JsonResponse中使用需要加参数。json_dumps_params={'ensure_ascii':False}

    from django.http import JsonResponse
    def books(request):
        ll = [{'name':'python开心','price':20},
               {'name':'linux','price':30}]
        return JsonResponse(ll,safe=False,json_dumps_params={'ensure_ascii':False})

     二、使用djangorestframework,基于drf写resful的接口,写django框架以CBV模式

    1)pip安装

    pip install djangorestframework -i http://pypi.douban.com/simple

     2) 原生的CBV模式。执行过程,as_view() ==>dispatch ==>响应到具体的函数

    url的写法。url(r'^books/', views.Book.as_view()。  类+as_view

    from  django.views import View
    class Book(View):
        def get(self,resquest):
            return HttpResponse('get')
        def post(self,resquest):
            return HttpResponse('post')

    可根据请求模式自动判断该执行类的哪个方法

     会识别到方法是否在这里面  http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    3)使用psotman工具模拟发生请求

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^books/', views.Book.as_view()),
    ]

    FBV模式视图函数

    from rest_framework.views import APIView
    class Book(APIView):
    def get(self,request):
    print(request.method) # GET
    print(request._request.method) # GET
    return HttpResponse('get')
    def post(self,request):
    print(request.method)
    print(request._request.method)
    print(request.POST) # 如果传json格式,这里面没有
    print(request.data)
    return HttpResponse('post')

     

    传json格式

     三、restful的序列化组件

    先生成数据库

    from django.db import models
    
    # Create your models here.
    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish_date = models.DateField(auto_now_add=True)
    
        publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
        authors=models.ManyToManyField(to='Author')
    
        def test(self):
            return 'ttttttt'
        def __str__(self):
            return self.name
    
    
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE)
    
    
    class AuthorDatail(models.Model):
        nid = models.AutoField(primary_key=True)
        telephone = models.BigIntegerField()
        birthday = models.DateField()
        addr = models.CharField(max_length=64)
    
    
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
    
        def __str__(self):
            return self.name
    models.py

    1)第一种,自己写序列化组件

     url(r'^books/', views.Book.as_view())

    from rest_framework.views import APIView
    from app01 import models
    from django.http import JsonResponse
    
    class Book(APIView):
        def get(self, request):
            response={'status':100,'msg':None}  # restful接口
            books = models.Book.objects.all()
            # 第一种常用写法
            # ll = []
            # for book in books:
            #     ll.append({'name':book.name,'price':book.price}.....)
    
            # 第二种 列表推导式
            ll = [ {'name':book.name,'price':book.price} for book in books ]
            response['msg']='查询成功'
            response['data']=ll     # 把查询到的数据列表赋予返回的字典
            return JsonResponse(response,safe=False)
    
        def post(self, request):
            return HttpResponse('post')

     2)第二种,使用Django的序列化组件

    from rest_framework.views import APIView
    from app01 import models
    from django.core import serializers # django的序列号组件
    class Book(APIView):
        def get(self, request):
            books = models.Book.objects.all()
            ret = serializers.serialize("json",books)
            return HttpResponse(ret)
    
        def post(self, request):
            return HttpResponse('post')

     3)使用drf定制序列化组件

     3.1)为了避免代码杂乱,序列号组件写在外部

    查看models模型库

    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish_date = models.DateField(auto_now_add=True)
    
        publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
        authors=models.ManyToManyField(to='Author')
    
        def test(self):
            return 'ttttttt'
        def __str__(self):
            return self.name
    
    
    class Author(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        author_detail = models.OneToOneField(to='AuthorDatail',to_field='nid',unique=True,on_delete=models.CASCADE)
    
    
    class AuthorDatail(models.Model):
        nid = models.AutoField(primary_key=True)
        telephone = models.BigIntegerField()
        birthday = models.DateField()
        addr = models.CharField(max_length=64)
    
    
    class Publish(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        city = models.CharField(max_length=32)
        email = models.EmailField()
    
        def __str__(self):
            return self.name
    models.py

     引入:from rest_framework import serializers

    from rest_framework import serializers
    
    class BookSer(serializers.Serializer):
        nid = serializers.IntegerField()
        name = serializers.CharField()
        price = serializers.CharField()
        # publish_date=serializers.DateField()
        publish_date = serializers.CharField()
        publish = serializers.CharField()
    myserial.py

    视图views写法

    from rest_framework.views import APIView
    from app01 import models
    from app01 import myserial
    from django.http import JsonResponse
    
    class Book(APIView):
        def get(self, request):
            books = models.Book.objects.all()
            ret = myserial.BookSer(books,many=True)     # many=True 序列化多条数据
            return JsonResponse(ret.data,safe=False)   # data 序列化的字典方法
    
        def post(self, request):
            return HttpResponse('post')

    备注:使用sqlite时,日期序列化出来为null,使用mysql则不会

    3.2)增加查询信息

    from rest_framework.views import APIView
    from app01 import models
    from app01 import myserial
    from django.http import JsonResponse
    
    class MyResponse():
        def __init__(self):
            self.status=100
            self.msg=None
        @property
        def get_dic(self):
            return self.__dict__
    
    class Book(APIView):
        def get(self, request):
            response = MyResponse()
            books = models.Book.objects.all()
            ret = myserial.BookSer(books,many=True)     # many=True 序列化多条数据
            response.msg = "查询成功"
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)   # data 序列化的字典方法
    
        def post(self, request):
            return HttpResponse('post')

     3.3)如果要想查询到publish指向邮箱

     publish = serializers.CharField(source='publish.email')

    from rest_framework import serializers
    
    class BookSer(serializers.Serializer):
        nid = serializers.IntegerField()
        name = serializers.CharField()
        price = serializers.CharField()
        # publish_date=serializers.DateField()
        publish_date = serializers.CharField()
        publish = serializers.CharField(source='publish.email')
    myserial.py

     3.4)定制序列号组件时,如果让左边的名字随便定义

    from rest_framework import serializers
    
    class BookSer(serializers.Serializer):
        nid = serializers.IntegerField()
        xxx = serializers.CharField(source='name')
        price = serializers.CharField()
        # publish_date=serializers.DateField()
        publish_date = serializers.CharField()
        publish = serializers.CharField(source='publish.email')
    myserial.py

     3.5)利用source调用models里面的方法

    class Book(models.Model):
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=5, decimal_places=2)
        publish_date = models.DateField(auto_now_add=True)
    
        publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
        authors=models.ManyToManyField(to='Author')
    
        def test(self):
            return 'ttttttt'
        def __str__(self):
            return self.name
    models.py Book

    调用Book类的test方法

    from rest_framework import serializers
    
    class BookSer(serializers.Serializer):
        nid = serializers.IntegerField()
        xxx = serializers.CharField(source='name')
        price = serializers.CharField()
        # publish_date=serializers.DateField()
        publish_date = serializers.CharField()
        publish = serializers.CharField(source='publish.email')
        yyy = serializers.CharField(source='test')
    myserial.py

    3.6)查询多对多,有多个值时

    from rest_framework import serializers
    class BookSer(serializers.Serializer):
        # 下面是查询多个作者
        # authors=serializers.CharField(source='authors.all') # 如果查询多个作者,是查询为query的对象
        # SerializerMethodField,可以写一个方法,方法返回值,会赋值给authers
        authors=serializers.SerializerMethodField()
        def get_authors(self,obj):
            # obj 当前book对象
            authors=obj.authors.all()
            #ll = [ author.name for author in authors ]
            ll = [ {'name':author.name,'age':author.age} for author in authors ]
            return ll
    myserial.py

     3.7)查询多个值的另一种方法,再加一个类方法

    from rest_framework import serializers
    class AuthorSer(serializers.Serializer):
        id = serializers.IntegerField(source='nid')
        age=serializers.CharField()
        name=serializers.CharField()
    
    class BookSer(serializers.Serializer):
        aa=serializers.SerializerMethodField()
        def get_aa(self,obj):
            authors=obj.authors.all()
            ser=AuthorSer(authors,many=True)
            return ser.data
    myserial.py

     3.8)ModelSerializer组件来查询多个值

     class Meta:fields = '__all__'和exclude = ['nid']

    from rest_framework import serializers
    from app01 import models
    class AuthorSer(serializers.Serializer):
        id = serializers.IntegerField(source='nid')
        age=serializers.CharField()
        name=serializers.CharField()
    
    class BookSer(serializers.ModelSerializer):
        class Meta:
            # 指定要序列化的表模型是book
            model = models.Book
            # __all__ 把所有字段都序列化
            fields = '__all__'
            # fields = ['nid','title','age]  # 可传入指定参数
            # exclude = ['nid'] 除了nid 都查找,exclude和fields 不能同时用
        # 如果不写下面的方法,查询出来的是关联表的id
        publish = serializers.CharField(source='publish.name')
        authors = serializers.SerializerMethodField()
        def get_authors(self,obj):
            authors=obj.authors.all()
            ll = [ {'name':author.name,'age':author.age} for author in authors ]
            return ll
    myserial.py

    3.9)更方便的深度自动查询。depth指定深度,最多用3层。内部机制for循环,增加数据库压力

    from rest_framework import serializers
    from app01 import models
    class AuthorSer(serializers.Serializer):
        id = serializers.IntegerField(source='nid')
        age=serializers.CharField()
        name=serializers.CharField()
    
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = '__all__'
            depth=2     # 默认是0,所以前面才会写下面的方法

    四、总结使用resful组件定制序列号组件

    1)导入:from rest_framework import serializers

    2) 写一个类(名字任意),继承serializers.Serializer

      可随意定制该类的序列化内容

    from rest_framework import serializers
    
    class BookSer(serializers.Serializer):
        nid = serializers.IntegerField()
        xxx = serializers.CharField(source='name')
        price = serializers.CharField()
        # publish_date=serializers.DateField()
        publish_date = serializers.CharField()
        publish = serializers.CharField()
        publish_email = serializers.CharField(source='publish.email')
        yyy = serializers.CharField(source='test')
    myserial.py

    3)如果不值得source,字段名,必须跟数据库列名一致

    4)source  ==》既可以指定数据属性,又可以指定方法属性,可以写(publish.name)

    5)使用:

      - 查询出要序列化的数据:books = models.Book.objects.all() (多条)

          - ret = myserial.BookSer(books,many=True)  ===》多条(queryset对象),必须指定many=True

          - ---------------------------

      - 查询出要序列化的数据:books = models.Book.objects.all().first() (一条)

          - ret = myserial.BookSer(books,many=False)  ===》1条(book对象),必须指定many=False

     6)aa=serializers.SerializerMethodField()

             - 必须配套一个方法(get_aa(self,obj)),方法的返回结果,会赋给aa

             - 在方法内部可以继续用序列化组件

    7)序列化组件之serializers.ModelSerializer

      - 用法同Serializer

          - 不同点

               class BookSer(serializers.ModelSerializer):

                     class Meta:

                            # 指定要序列化的表模型是book

                        model=models.Book

                            fields='__all__'   或 exclude=['nid']

                            depth=1

    五、post请求发送数据

    1.1)序列化组件的字段校验和反序列化功能

    from rest_framework import serializers
    from app01 import models
    class AuthorSer(serializers.Serializer):
        id = serializers.IntegerField(source='nid')
        age=serializers.CharField()
        name=serializers.CharField()
    
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            exclude=['authors']
    myserial.py

    post函数反序列化组件

    from rest_framework.views import APIView
    from app01 import models
    from app01 import myserial
    from django.http import JsonResponse
    
    class MyResponse():
        def __init__(self):
            self.status=100
            self.msg=None
        @property
        def get_dic(self):
            return self.__dict__
    
    class Book(APIView):
        def get(self, request):
            response = MyResponse()
            books = models.Book.objects.all()
            # ret = myserial.BookSer(books,many=True)     # many=True 序列化多条数据
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = "查询成功"
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)   # data 序列化的字典方法
    
        def post(self, request):
            print(request.data)
            ser=myserial.BookSer(data=request.data)
            if ser.is_valid():  # 校验字段
                ser.save()
            else:
                print(ser.errors)
            return HttpResponse('post')
    views.py

    小结

    # 只有:ModelSerializer. 能直接保存
    def post(self, request):
        print(request.data)
        # 生成一个序列化对象
        ser=myserial.BookSer(data=request.data)
        # 判断字段是否校验通过
        if ser.is_valid():
            # 通过直接保存
            ser.save()
        else:
            # 错误信息
            print(ser.errors)
        return HttpResponse('post')

     1.2)post提交数据,进行局部校验

    from rest_framework import serializers
    from app01 import models
    class AuthorSer(serializers.Serializer):
        id = serializers.IntegerField(source='nid')
        age=serializers.CharField()
        name=serializers.CharField()
    from rest_framework.exceptions import ValidationError
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            exclude=['authors']
    
        name = serializers.CharField()
        def validate_name(self,value):
            if value.startswith('sb'):
                raise ValidationError('不能以sb开头')
            else:
                return value
    myserial.py

    视图函数编写,返回校验不通过的错误信息

    from rest_framework.views import APIView
    from app01 import models
    from app01 import myserial
    from django.http import JsonResponse
    
    class MyResponse():
        def __init__(self):
            self.status=100
            self.msg=None
        @property
        def get_dic(self):
            return self.__dict__
    
    class Book(APIView):
        def get(self, request):
            response = MyResponse()
            books = models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = "查询成功"
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)
    
        def post(self, request):
            print(request.data)
            ser=myserial.BookSer(data=request.data)
            if ser.is_valid():
                ser.save()
                return HttpResponse('成功')
            else:
                print(ser.errors)
            return JsonResponse(ser.errors)
    views.py

     1.3)全局校验

    from rest_framework import serializers
    from app01 import models
    class AuthorSer(serializers.Serializer):
        id = serializers.IntegerField(source='nid')
        age=serializers.CharField()
        name=serializers.CharField()
    from rest_framework.exceptions import ValidationError
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            exclude=['authors']
    
        name = serializers.CharField()
        # 局部校验
        def validate_name(self,value):
            if value.startswith('sb'):
                raise ValidationError('不能以sb开头')
            else:
                return value
        # 全局校验
        def validate(self, value):
            print(value,type(value))
            name=value.get('name')
            price=value.get('price')
            if name!= price:
                raise ValidationError('他们不相等')
            else:
                return value
    myserial.py

    小结:

    class BookSer(serializers.ModelSerializer):
        class Meta:
            pass
        # 局部校验
        def validate_name(self,value):
            pass
        # 全局校验
        def validate(self, value):
            pass

     六,put修改数据(为了避免日期问题的错误,已换成mysql)

    1) 修改数据

     路由: url(r'^books/(?P<id>d+)/', views.BookDetail.as_view()),

    序列化组建编写

    from rest_framework import serializers
    from app01 import models
    
    from rest_framework.exceptions import ValidationError
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            exclude=['authors']
    myserial.py

    视图函数编写

    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    
    from rest_framework.views import APIView
    from app01 import models
    from app01 import myserial
    from django.http import JsonResponse
    
    class MyResponse():
        def __init__(self):
            self.status=100
            self.msg=None
        @property
        def get_dic(self):
            return self.__dict__
    
    
    
    
    class BookDetail(APIView):
        def get(self,request,id):
            response=MyResponse()
            ret=models.Book.objects.filter(pk=id).first()
            ser=myserial.BookSer(instance=ret,many=False)
            response.msg='查询成功'
            response.data=ser.data
            return JsonResponse(response.get_dic,safe=False)
    
        def put(self,request,id):
            # 修改
            response=MyResponse()
            book=models.Book.objects.filter(pk=id).first()
            ser=myserial.BookSer(instance=book,data=request.data)
    
            if ser.is_valid():
                # 可以新增,可以修改
                ser.save()
                print(ser.data) # 对象的字典
                print(type(ser.instance),ser.instance)
                response.msg='修改成功'
                response.data=ser.data
            else:
                response.msg='修改失败'
                response.status=101
                response.data=ser.errors
            return JsonResponse(response.get_dic,safe=False)
    views.py

     2)引入错误信息中文化

    from rest_framework import serializers
    from app01 import models
    
    class BookSer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            exclude=['authors']
        name = serializers.CharField(error_messages={'required':'该字段必填'})
    myserial.py

    name = serializers.CharField(error_messages={'required':'该字段必填'})

     七、修改数据

    class MyResponse():
        def __init__(self):
            self.status=100
            self.msg=None
        @property
        def get_dic(self):
            return self.__dict__
    
    class BookDetail(APIView):
        def get(self,request,id):
            response=MyResponse()
            ret=models.Book.objects.filter(pk=id).first()
            ser=myserial.BookSer(instance=ret,many=False)
            response.msg='查询成功'
            response.data=ser.data
            return JsonResponse(response.get_dic,safe=False)
    
        def put(self,request,id):
            # 修改
            response=MyResponse()
            book=models.Book.objects.filter(pk=id).first()
            ser=myserial.BookSer(instance=book,data=request.data)
    
            if ser.is_valid():
                # 可以新增,可以修改
                ser.save()
                print(ser.data) # 对象的字典
                print(type(ser.instance),ser.instance)
                response.msg='修改成功'
                response.data=ser.data
            else:
                response.msg='修改失败'
                response.status=101
                response.data=ser.errors
            return JsonResponse(response.get_dic,safe=False)
    
        def delete(self,request,id):
            ret=models.Book.objects.filter(pk=id).delete()
            return HttpResponse('删除成功')
    views.py

    八、项目常规用法

    url写法

    from django.conf.urls import url
    from django.contrib import admin
    from django.urls import path
    from app import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        url(r'^books/$', views.BookView.as_view({'get':'get_all'})),
        url(r'^books/(?P<pk>d+)/', views.BookView.as_view({'get':'get_one'})),
    ]

    视图函数

    from rest_framework.views import APIView
    from rest_framework.viewsets import ViewSetMixin
    class BookView(ViewSetMixin,APIView):
        def get_all(self,request):
            return HttpResponse('返回所有')
        def get_one(self,request,pk):
            return HttpResponse('返回一条')
  • 相关阅读:
    leetcode@ [279]Perfect Squares
    leetcode@ [160]Intersection of Two Linked Lists
    leetcode@ [209]Minimum Size Subarray Sum
    leetcode@ [22]Generate Parentheses (递归 + 卡特兰数)
    jmeter—JDBC request动态参数设置
    Jmeter JDBC Request--测试数据库连接 拒绝解决方案
    转JMeter ----数据库 not allowed to connect to this MySQL
    jmeter ---监控服务器CPU, 内存,网络数据
    在free bsd上跑JMeter 的 plugin "PerfMon Server Agent"
    解决Jmeter插件ERROR: java.io.IOException: Agent is unreachable via TCP的错误
  • 原文地址:https://www.cnblogs.com/linu/p/9977371.html
Copyright © 2020-2023  润新知