django 学习之DRF (一)

Django框架基础DRF-01

前后端分离介绍

    1.前后端不分离图解

 


     

 


    2.前后端分离图解
    

 


    3.为什么要学习DRF    DRF可以帮助我们开发者快速的开发⼀个依托于Django的前后后端分离的项目

RESTful 介绍
    1.认识 RESTful
        1.在前后端分离的应⽤模式⾥,后端API接⼝如何定义?
              需要⼀种规范和⻛格来约束后端程序员对接⼝的定义
              RESTful 就是⽤来约束后端程序员对接⼝的定义的⼀种⻛格
        2.描述
            REST,即Representational State Transfer的缩写。维基百科称其为“ 具象状态传输” ,国内⼤部分⼈理解为“ 表现层状态转化” 。
            RESTful是⼀种开发理念。维基百科说:REST是设计⻛格⽽不是标准
            RESTful架构就是:
                • 每⼀个URL代表⼀种资源;
                • 客户端和服务器之间,传递这种资源的某种表现层;
                • 客户端通过四个HTTP动词,对服务器端资源进⾏操作,实现" 表现层状态转化" 。
    2.RESTful 设计⽅法
        域名
        版本
        路径
        HTTP动词
        过滤信息
        状态码
        错误处理
        返回结果
        超媒体
        数据传输格式
    3.Django和 DRF对⽐
        1.Django可以实现前后端分离
            Django开发前后端分离的周期⻓
            Django如果要遵守RESTful设计⻛格需要⾃⼰写对应⻛格的路由
        2.DRF专⻔实现前后端分离
            DRF开发前后端分离的周期短
            默认遵守的是RESTful设计⻛格

使⽤Django定义REST API

    0.⽬的 为了学习在没有DRF的情况下,如何使⽤Django原⽣的形式实现前后端分离且遵守RETSful设计⻛格的项⽬
    1.REST API 路由说明
        """
        GET /books/ 提供所有记录
        POST /books/ 新增⼀条记录
        GET /books/<pk>/ 提供指定id的记录
        PUT /books/<pk>/ 修改指定id的记录
        DELETE /books/<pk>/ 删除指定id的记录
        响应数据 JSON
        """
    2.提供所有记录

def get(self, request):
"""提供所有记录
GET /books/
"""
    # 查询所有记录 books = [BookInfo,BookInfo,BookInfo,BookInfo,BookInfo]
    books = BookInfo.objects.all()
    # 将模型列表转成字典列表
    book_list = []
    for book in books:
        book_list.append({
        'id': book.id,
        ' btitle' : book.btitle,
        ' bpub_date' : book.bpub_date,
        'bread': book.bread,
        ' bcomment' : book.bcomment,
        'image': book.image.url if book.image else ''
        })
    # 响应JSON数据
    return JsonResponse(book_list, safe= False)

 


    3.新增⼀条记录

def post(self, request):
"""新增⼀条记录
POST /books/
"""
    # 读取客户端传⼊的JSON数据
    json_bytes = request.body
    json_str = json_bytes.decode()
    book_dict = json.loads( json_str)
    # 创建新的记录
    book = BookInfo.objects.create(
            btitle=book_dict.get(' btitle' ),
            bpub_date=datetime.strptime(book_dict.get(' bpub_date' ), '%Y-%m-%d').date(),
            bread = book_dict['bread'],
            bcomment = book_dict[' bcomment' ]
        )
    # 构造响应数据
    response_book_dict = {
                'id': book.id,
                ' btitle' : book.btitle,
                ' bpub_date' : book.bpub_date,
                'bread': book.bread,
                ' bcomment' : book.bcomment,
                'image': book.image.url if book.image else ''
                }
    # 响应结果
    return JsonResponse(response_book_dict, status= 201)

 


    4.提供指定id的记录

def get(self, request, pk):
"""提供指定id的记录
GET /books/<pk>/
"""
    # 判断pk是否合法
    try:
        book = BookInfo.objects.get(id=pk)
        except BookInfo.DoesNotExist:
        return HttpResponse(status= 404)
    # 构造响应数据
    response_book_dict = {
                'id': book.id,
                ' btitle' : book.btitle,
                ' bpub_date' : book.bpub_date,
                'bread': book.bread,
                ' bcomment' : book.bcomment,
                'image': book.image.url if book.image else ''
                }
    # 响应结果
    return JsonResponse(response_book_dict)

 


    5.修改指定id的记录
 

def put(self, request, pk):
"""修改指定id的记录
PUT /books/<pk>
"""
    # 判断pk是否合法
    try:
        book = BookInfo.objects.get(id=pk)
        except BookInfo.DoesNotExist:
        return HttpResponse(status= 404)
    # 读取客户端传⼊的JSON数据
    json_bytes = request.body
    json_str = json_bytes.decode()
    book_dict = json.loads( json_str)
    # 修改记录
    book.btitle = book_dict.get(' btitle' )
    book.save()
    # 构造响应数据
    response_book_dict = {
            'id': book.id,
            ' btitle' : book.btitle,
            ' bpub_date' : book.bpub_date,
            'bread': book.bread,
            ' bcomment' : book.bcomment,
            'image': book.image.url if book.image else ''
            }
    # 响应结果
    return JsonResponse(response_book_dict)

 


    6.删除指定id的记录

def delete(self, request, pk):
"""删除指定id的记录
DELETE /books/<pk>/
"""
# 判断pk是否合法
    try:
        book = BookInfo.objects.get(id=pk)
        except BookInfo.DoesNotExist:
        return HttpResponse(status= 404)
    # 删除
    book.delete()
    # 响应
    return HttpResponse(status= 204)

 



序列化和反序列化介绍
0.提示
    在开发REST API接⼝时,视图中做的最主要有三件事:
        • 将请求的数据(如JSON格式)转换为模型类对象(反序列化)
        • 操作数据库
        • 将模型类对象转换为响应的数据(如JSON格式)(序列化)
    1.序列化
        1.概念 将程序中的⼀个数据结构类型转换为其他格式(字典、JSON、 XML等),例如将Django中的模型类对象装换为JSON字符串,这个转换过程我们称为序列化。
        2.序列化⾏为

# 判断pk是否合法
try:
    book = BookInfo.objects.get(id=pk)
    except BookInfo.DoesNotExist:
    return HttpResponse(status= 404)
# 构造响应数据
response_book_dict = {
    'id': book.id,
    ' btitle' : book.btitle,
    ' bpub_date' : book.bpub_date,
    'bread': book.bread,
    ' bcomment' : book.bcomment,
    'image': book.image.url if book.image else ''
    }
# 响应结果
return JsonResponse(response_book_dict)

 


        3.序列化时机 当需要给前端响应模型数据时,需要将模型数据 序列化 成前端需要的格式

    2.反序列化
        1.概念 将其他格式(字典、JSON、 XML等)转换为程序中的数据,例如将JSON字符串转换为Django中的模型类对象,这个过程我们称为反序列化。
        2.反序列化⾏为

# 读取客户端传⼊的JSON数据
json_bytes = request.body
json_str = json_bytes.decode()
book_dict = json.loads( json_str)
# 创建新的记录
book = BookInfo.objects.create(
btitle=book_dict.get(' btitle' ),
bpub_date=datetime.strptime(book_dict.get(' bpub_date' ), '%Y-%m-%d').date(),
bread = book_dict['bread'],
bcomment = book_dict[' bcomment' ]
)

 


        3.反序列化时机 当需要将⽤户发送的数据存储到数据库之前,需要使⽤反序列化
        3.总结
            在开发REST API接⼝时,我们在视图中需要做的最核⼼的事是:
            • 将数据库数据序列化为前端所需要的格式,并返回;
            • 将前端发送的数据反序列化为模型类对象,并保存到数据库中。


1.DRF介绍
    1.序列化和反序列化提示
        1.在序列化与反序列化时,虽然操作的数据不尽相同,但是执⾏的过程却是相似的,也就是说这部分代码是可以复⽤简化编写的。
        2.在开发REST   API的视图中,虽然每个视图具体操作的数据不同,但增、删、改、查的实现流程基本套路化,所以这部分代码也是可以复⽤简化编写的:
            • 增 :校验请求数据 -> 执⾏反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
            • 删 :判断要删除的数据是否存在 -> 执⾏数据库删除
            • 改 :判断要修改的数据是否存在 -> 校验请求的数据 -> 执⾏反序列化过程 -> 保存数据库 -> 将保存的对象序列化并返回
            • 查 :查询数据库 -> 将数据序列化并返回
        3.DRF将序列化和反序列化的业务逻辑进⾏了封装 程序员只需要将序列化和反序列化的数据传给DRF即可
    2.DRF作⽤ Django REST framework可以帮助我们简化序列化和反序列化部分的代码编写,⼤⼤提⾼REST API的开发速度。
    3.DRF特点
            • 提供了定义序列化器Serializer的⽅法,可以快速根据 Django ORM 或者其它库⾃动序列化/ 反序列化;
            • 提供了丰富的类视图、Mixin扩展类,简化视图的编写;
            • 丰富的定制层级:函数视图、类视图、视图集合到⾃动⽣成 API,满⾜各种需要;
            • 多种身份认证和权限认证⽅式的⽀持;
            • 内置了限流系统;
            • 直观的 API web 界⾯;
            • 可扩展性,插件丰富
    4.相关⽂档
          官⽅⽂档 http://www.django-rest-framework.org/
          源码 https://github.com/encode/django-rest-framework/tree/master

2.DRF安装和配置
    1.DRF环境依赖
        • Python (2.7, 3.2, 3.3, 3.4, 3.5, 3.6)
        • Django (1.10, 1.11, 2.0)
        DRF是以Django扩展应⽤的⽅式提供的,所以我们可以直接利⽤已有的Django环境⽽⽆需从新创建。(若没有Django环境,需要先创建环境安装Django)
    2.安装DRF pip install djangorestframework
    3.添加rest_framework应⽤

INSTALLED_APPS = [
        ' django.contrib.admin' ,
        ' django.contrib.auth' ,
        ' django.contrib.contenttypes' ,
        ' django.contrib.sessions' ,
        ' django.contrib.messages' ,
        ' django.contrib.staticfiles' ,
        'rest_framework', # DRF
        'users.apps.UsersConfig', # 安装users应⽤, 演示基本使⽤
        'request_response.apps.RequestResponseConfig', # 演示请求和响应
        ' booktest.apps.BooktestConfig' , # 图书英雄管理应⽤
]

 


3.DRF初体验
    1.创建序列化器   booktest.serializers

from rest_framework import serializers
from .models import BookInfo
class BookInfoSerializer(serializers.ModelSerializer):
"""BookInfo模型类的序列化器"""
    class Meta:
        model = BookInfo
        fields = '__all__'

 


    2.编写视图逻辑
    

from rest_framework.viewsets import ModelViewSet
from .models import BookInfo
from . import serializers
class BookInfoViewSet(ModelViewSet):
"""使⽤DRF实现增删改查的后端API"""
    # 指定查询集
    queryset = BookInfo.objects.all()
    # 指定序列化器
    serializer_class = serializers.BookInfoSerializer

 


    3.定义路由

from django.conf.urls import url
from rest_framework.routers import DefaultRouter
from . import views
urlpatterns = [
# url(r'^books/$', views.BooksAPIView.as_view()),
# url(r'^books/(?P<pk>\d+)/$', views.BookAPIView.as_view()),
]
# 创建路由对象
router = DefaultRouter()
# 将视图集注册到路由
router.register(r'books', views.BookInfoViewSet)
# 视图集路由添加到urlpatterns
urlpatterns += router.urls

 



4.运⾏测试 GET http://127.0.0.1:8000/books/


Serializer序列化器
    1.序列化器的作⽤
        1. 进⾏数据的校验
        2. 对数据对象进⾏转换
    2.定义序列化器说明
        1.模型类

# 定义图书模型类BookInfo
class BookInfo(models.Model):
    btitle = models.CharField(max_length= 20, verbose_name= ' 名称' )
    bpub_date = models.DateField(verbose_name= ' 发布⽇期' )
    bread = models.IntegerField(default= 0 , verbose_name= ' 阅读量' )
    bcomment = models.IntegerField(default= 0 , verbose_name= ' 评论量' )
    is_delete = models.BooleanField(default= False, verbose_name= ' 逻辑删除' )
    image = models.ImageField(upload_to= 'book', verbose_name= ' 图书图⽚' , null= True)

 


        2.序列化器

class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
    id = serializers.IntegerField(label= 'ID', read_only= True)
    btitle = serializers.CharField(label= ' 名称' , max_length= 20, validators=[about_django])
    bpub_date = serializers.DateField(label= ' 发布⽇期' , required= False)
    bread = serializers.IntegerField(label= ' 阅读量' , required= False)
    bcomment = serializers.IntegerField(label= ' 评论量' , required= False)
    image = serializers.ImageField(label= ' 图⽚' , required= False)
    heroinfo_set = serializers.PrimaryKeyRelatedField(read_only= True, many= True)

 


    3.定义序列化器字段类型和选项
        1.字段类型 类似于模型字段类型
        2.选项参数
        3.通⽤选项、参数

    4.创建Serializer序列化器对象

        1.构造⽅法
            Serializer的构造⽅法为:
            Serializer(instance=None, data=empty, **kwarg)
        2.构造⽅法说明
            1.⽤于序列化时
                将模型类对象传⼊instance参数
                Serializer(book)
                序列化 == 模型数据—>python字典 (⽤于输出,返回数据给前端)
            2.⽤于反序列化时
                将要被反序列化的数据传⼊data参数
                Serializer(data=data)
                反序列化 == 前端发送的数据—>经过验证—>python字典—>save—>模型类对象(⽤于输⼊,接受前端数据)
                
Serializer序列化器之序列化操作
    1.序列化⼀个模型对象
        >>> from booktest.models import BookInfo
        >>> book = BookInfo.objects.get(id=1)
        >>> book
        <BookInfo: 射雕英雄传>
        >>> from booktest.serializers import BookInfoSerializer
        >>> s = BookInfoSerializer(book)
        >>> s.data
        {'id': 1, 'btitle': '射雕英雄传', 'bpub_date': '1980-05-01', 'bread': 12, 'bcomment': 34, 'image': None}
    2.序列化多个模型对象
        >>> qs = BookInfo.objects.all()
        >>> qs
        <QuerySet [<BookInfo: 射雕英雄传>, <BookInfo: 天⻰⼋部>, <BookInfo: 笑傲江湖>, <BookInfo: 雪⼭⻜狐>, <BookInfo: ⻄游记>]>
        >>> s = BookInfoSerializer(qs, many=True)
        >>> s.data
    3.关联对象嵌套序列化
        1.增加HeroInfo对应的序列化器

class HeroInfoSerializer(serializers.Serializer):
"""英雄数据序列化器"""
    GENDER_CHOICES = (
    (0 , 'male'),
    (1 , 'female')
    )
    id = serializers.IntegerField(label= 'ID', read_only= True) # 只会做序列化(输出)
    hname = serializers.CharField(label= ' 名字' , max_length= 20)
    hgender = serializers.ChoiceField(choices=GENDER_CHOICES, label= ' 性别' , required= False)
    hcomment = serializers.CharField(label= ' 描述信息' , max_length= 200, required= False, allow_null= True)
    # 在序列化器中定义外键关联字段
    # 必须:read_only=True(让前端⽆法对外键进⾏输⼊操作,只能输出)
    hbook = serializers.PrimaryKeyRelatedField(label= ' 图书' , read_only= True)

 


        2.序列化过程
            >>> from booktest.serializers import BookInfoSerializer, HeroInfoSerializer
            >>> from booktest.models import BookInfo, HeroInfo
            >>> hero = HeroInfo.objects.get(id=1)
            >>> hero
            <HeroInfo: 郭靖>
            >>> s = HeroInfoSerializer(hero)
            >>> s.data
            {'id': 1, 'hname': '郭靖', 'hgender': 1, 'hcomment': '降⻰⼗⼋掌', 'hbook': 1}
    4.many参数
        1.增加⼀查多的关系字段

class BookInfoSerializer(serializers.Serializer):
"""图书数据序列化器"""
    id = serializers.IntegerField(label= 'ID', read_only= True) # 只会做序列化(输出)
    btitle = serializers.CharField(label= ' 名称' , max_length= 20)
    bpub_date = serializers.DateField(label= ' 发布⽇期' , required= False)
    bread = serializers.IntegerField(label= ' 阅读量' , required= False)
    bcomment = serializers.IntegerField(label= ' 评论量' , required= False)
    image = serializers.ImageField(label= ' 图⽚' , required= False)
    # 定义⼀关联多的序列化器字段
    # many=True : 表示⼀对多
    heroinfo_set = serializers.PrimaryKeyRelatedField(read_only= True, many= True) # 新增

 


        2.序列化过程
            >>> from booktest.models import BookInfo, HeroInfo
            >>> from booktest.serializers import BookInfoSerializer
            >>> book = BookInfo.objects.get(id=1)
            >>> book
            <BookInfo: 射雕英雄传>
            >>> s = BookInfoSerializer(book)
            >>> s.data
            {'id': 1, 'btitle': '射雕英雄传', 'bpub_date': '1980-05-01', 'bread': 12, 'bcomment': 34, 'image': None, 'heroinfo_set': [1, 2, 3, 4, 5]}

相关源码连接:

github,技术交流,欢迎指教

转载于:https://www.cnblogs.com/x931890193/p/9330604.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值