加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

drf框架

发布时间:2020-12-20 10:15:15 所属栏目:Python 来源:网络整理
导读:一:drf drf的全称 : django rest framework 用处 : 用来前后端分离的项目: 结合前段的vue框架,数据库mysql 二: 安装 在命令行中输入: pip3 install djangorestframework 三: 配置 INSTALLED_APPS = [ ‘ app01.apps.App01Config ‘ , # App的注册,一般命名:a

一:drf

  drf的全称: django rest framework

  用处: 用来前后端分离的项目: 结合前段的vue框架,数据库mysql

二: 安装

  在命令行中输入: pip3 install djangorestframework

三: 配置

INSTALLED_APPS = [
    app01.apps.App01Config,# App的注册,一般命名:api
    # 注册: 在setting中配置,rest_framework实质上是一个app,需要注册才可以使用
    # 但是我不注册,照样能使用
    rest_framework,]

四: 接口

  1)? 什么是接口?

  大白话解释: 两个东西通过一个东西进行连接、通信等, 一个东西就叫做接口

  wed程序中的接口:连接前后台页面尽心数据交互的媒介

  2) restful规范:

    为什么要有restful规范: 因为后台的语言有多种,这样接口就会有多种,所以要统一规范

    1. api表示url接口,

    2. 使用https协议,数据更加安全

    3. 一个接口有多个版本,需要在url连接中表示,v1表示版本

      如: api. xiaohuar.com/v1/...

    4. 接口操作的数据源称之为资源,资源在url连接中一般采用复数

      如: api. xiaohuar.com/books/...

    5. 请求的方式有多种,用一个url处理,为了保证不混乱,通过请求方式标识操作资源的方式

      get(pk)? ? ? ? ?获取所有(获取一个)

      post? ? ? ? ? ? ?增加一个或多个

      delete? ? ? ? ? 删除一个或多个(数据不会真正的删除,只会用一个字段标识)

      put/patch? ? ?整体更新/局部更新

    6. 资源往往涉及数据的各种操作:? ? 过滤,排序,限制

      如:? api.xiaohuar.com/book/?search=西&ordering=-price&limit=3

      查找书本中有西的,价格从小到大,找出三本

    7. 返回状态码:? 前台和后台约定好的

{
"status": 0  # 操作资源成功
"msg": "登录成功"   # 文字提示信息
"results": 需要返回前段的数据
}  
{"status": 1}  # 操作资源失败
{"status": 2}  # 操作资源成功,但是没有与之匹配的数据

    8. 不能直接还回的资源,如视频,图片,等,

      需要还回url连接

五: 基于restful的原生路由

  总路由:?

from django.urls import url,include
from contrib importadmin

urlpatterns = [
     url(r^admin/,admin.site.urls),url(r^api/,include(api.urls))        
]

  子路由:

from django.urls import url

urlpatterns = [
   url(r‘^book/$‘,views.Book.as_view()),# 查看有的数据
  url(r‘^book/(?P<pk>.*)/$‘,view.Book.as_view()),# 查看某一个数据 ]

  models.py

from django.db.models import F
# 快熟导入模块alt + enter键

class BaseModel(models.Model):
    is_delete = models.BooleanField(default=False)
    create_time = models.DateTimeField(auto_now_add=True)

    class Meta:
        abstract = True  # 其它模型类继承该类,该类不创建表

class Book(BaseModel):
    name = models.CharField(max_length=64)
    price = models.DecimalField(max_digits=6,decimal_places=2)
    img = models.ImageField(upload_to=icon,default=icon/default.jpg)
    publish = models.ForeignKey(
        to=Publish,db_constraint=False,related_name=books,on_delete=models.DO_NOTHING
    )
    authors = models.ManyToManyField(
        to=Author,related_name=books
    )

    @property
    def publish_name(self):
        return self.publish.name


    @property
    def author_list(self):
        return self.authors.values(name,age,mobile = F(detail__mobile)).all()

    class Meta:
        db_table = book
        verbose_name_plural = 书籍

    def __str__(self):
        return self.name


class Publish(BaseModel):
    name = models.CharField(max_length=64)
    address = models.CharField(max_length=64)

    class Meta:
        db_table = publish
        verbose_name_plural = 出版社

    def __str__(self):
        return self.name


class Author(BaseModel):
    name = models.CharField(max_length=32)
    age = models.IntegerField()

    class Meta:
        db_table = author
        verbose_name_plural = 作者

    def __str__(self):
        return self.name


class AuthorDetail(BaseModel):
    mobile = models.CharField(max_length=11)
    # 外键字段建在作者详情中: 因为不经常被查询,建在作者那是被经常查,走数据库
    author = models.OneToOneField(
        # 和那张表建立连接,也可以不写
        to=Author,# 与连接的表断开连接
        db_constraint=False,# 通过detail进行连表查询
        related_name= detail,# 正向按字段,反向查询按detail
        # 级联
        on_delete= models.CASCADE,# on_delete= models.DO_NOTHING,

        # null=True,
        # on_delete=models.SET_NULL,

        # default= 0,
        # on_delete=models.SET_DEFAULT
    )

    class Meta:
        db_table = author_detail
        verbose_name_plural = 作者详情

    def __str__(self):
        return %s的详情 % self.author.name
View Code

?  数据库迁移命令:

python manage.py makemigrations  # 数据库迁移记录
python manage.py migrate   # 创建数据库

# 创建管理有用户,对创建的表进行操作
createsuperman

  admin.py

from django.contrib import admin
from . import models

# Register your models here.
# admin.site.register(models.Books)
# admin.site.register(models.User)

# 只有在admin.py中注册之后,才能在浏览器的admin的身份尽心操作
admin.site.register(models.Book)
admin.site.register(models.Author)
admin.site.register(models.Publish)
admin.site.register(models.AuthorDetail)
View Code

  views.py

from rest_framework.views import APIView
from . import models
from rest_framework.response import Response
from . import serializers


class Book(APIView):
    # 单查 全查
    def get(self,request,*args,**kwargs):
        pk = kwargs.get(pk)
        # 单查
        if pk:
            try:
                # 查找没有被删除的书籍 is_delete = False
                book_obj = models.Book.objects.get(pk=pk,is_delete=False)
                book_ser = serializers.BookModelSerializer(book_obj)
            except:
                return Response({
                    status: 1,msg: 数据不存在
                })
        # 群查
        else:
            # 查找没有被删除的书籍 is_delete = False
            book_obj = models.Book.objects.filter(is_delete=False).all()
            book_ser = serializers.BookModelSerializer(book_obj,many=True)
        return Response({
            status: 0,msg: ok,results: book_ser.data
        })
    # 单增 群增
    def post(self,**kwargs):
        # 前台出过来的数据在request.data里面
        request_data = request.data
        # 单增
        if isinstance(request_data,dict):
            many = False
        # 群增
        elif isinstance(request_data,list):
            many = True
        # 发送的数据格式不对
        else:
            return Response({
                status: 1,msg: 传入的数据有误,只能传{},or [{},{}]
            })
        # 数据交给序列化校验                      # 点data查看many
        book_ser = serializers.BookModelSerializer(data=request_data,many=many)
        # 当校验失败,raise_exception=True马上终止当前视图方法,报异常返回给前台
        book_ser.is_valid(raise_exception=True)
        # 校验成功保存数据
        book_obj = book_ser.save()
        return Response({
            status: 0,msg: OK,results: serializers.BookModelSerializer(book_obj,many=many).data
        })

    # 单删 群删
    def delete(self,**kwargs):
        # print(kwargs.get(‘pk‘),66666666666666)
        # print(request.data.get(‘pks‘),7777777777)
        pk = kwargs.get(pk)  # 一个pk走的是在url路径中拼接
        if pk:
            pks = [pk]
        else:
            pks = request.data.get(pks)  # 多个pk的数据在request.data中
        # 只能删除一次,不是真正意义上的删除,只是把is_delete=True,所以用的是update方法
        if models.Book.objects.filter(pk__in=pks,is_delete=False).update(is_delete=True):
            return Response({
                status: 0,msg: ok
            })
        return Response({
            status: 1,msg0: 已经被删除过
        })
View Code

六: postman接口工具

  安装: 官网直接下载,点击安装即可

  1) get请求: 携带参数采用Params

    数据在request.query_params中

  2) post请求:? 提交数据的三种方式: form_data,urlencode,json

    数据在request.data中

  注意: 所有的请求都可以携带请求头

七: drf的请求生命周期

  1)? 路由匹配走APIView的as_view函数

  2)? 在as_view函数中调用父类的as_view(原生django的as_view),增加了禁用csrf认证

  3)? 在父类的as_view中dispatch方法请求走的是APIView的dispatch

  5)? 完成任务方法交给视图类处理,得到请求的响应结果,返回给前台

八: 视图家族

  1.? views.py 视图>>APIView: 主要是设置

    1).??drf提供的渲染类,?解析模块规定数据的格式(form_data,urlencoded,json),异常模块的配置

REST_FRAMEWORK = {
    # drf提供的渲染类
    DEFAULT_RENDERER_CLASSES: [
        rest_framework.renderers.JSONRenderer,rest_framework.renderers.BrowsableAPIRenderer,],# 解析模块  数据格式
    # as_view>dispatch>self.initialize_request>self.get_parsers()>parser_classes
    DEFAULT_PARSER_CLASSES: [
        rest_framework.parsers.JSONParser,rest_framework.parsers.FormParser,rest_framework.parsers.MultiPartParser
    ],# 全局配置异常模块
    EXCEPTION_HANDLER: app01.exception.exception_handler,}

    2) urls.py

urlpatterns = [
    # 不能缺少book/  "/",在postman中的路径必须有"/"
    url(r^v1/books/$,url(r^v1/books/(?P<pk>.*)/$,]

    3) views.py

 
 
from rest_framework.views import APIView
from . import models
from rest_framework.response import Response
from . import serializers

class
Book(APIView): # 单查 全查 def get(self,results: book_ser.data }) # 单增 群增 def post(self,many=many).data }) # 单删 群删 def delete(self,msg0: 已经被删除过 }) # 单整体修改,对books(pk)传入的数据与models模型类中的字段对应,是字典,字段为选填 def put(self,**kwargs): # 根据pk获取要修改的对象 pk = kwargs.get(pk) old_book_obj = models.Book.objects.filter(pk=pk).first() # 获取要修改的数据 request_data = request.data # 把数据传入序列化,进行校验,partial=默认False表示,所有字段必填,partial=True: 表示字段为选填 book_ser = serializers.BookModelSerializer(instance=old_book_obj,data=request_data,partial=True) # 判断校验的数据是否有误,raise_exception=True表示校验的数据有误,直接返回 book_ser.is_valid(raise_exception=True) # 校验完成的数据进行更新update,操作数据库 book_obj = book_ser.save() # 返回前段请求响应的数据 return Response({ status: 0,msg: 更新完成,results: serializers.BookModelSerializer(book_obj).data }) # 坑: "detail": "Unsupported media type "text/plain" in request." # 原因: 传入的数据没有设置成json格式 # 局部修改,对books(pk)传入的数据是与models的模型类对应的字典啊 # 群改和单改何为一个方式,其中字段为可选字段,partial=True # 规定前段出入的数据格式: [{},{},{}] 或者 {} def patch(self,**kwargs): # 获取数据 request_data = request.data # 获取要修改的对象,先获取id pk = kwargs.get(pk) # 首先判断数据的格式: 字典还是list # 进步思想: 把单改变为群改,就是把pk变为多个,把字典变为多个就是列表 # 单改 if pk and isinstance(request_data,dict): pks = [pk,] request_data = [request_data,] # 群改 elif not pk and isinstance(request_data,list): # [{"pk": 1,"name": "json"},{"pk": 3,"price": 99.8},{"pk": 5,"author": 2}] # 取的一个个id,id在字典里面 pks = [] for dic in request_data: # 应该把pk从字典中取出, # pop()取pk的时候,如果pk不存在,报错,所以设置默认值None pk = dic.pop(pk,None) # 保证字典中的是数据,必须有一个字段(除pk外) if dic: # 判断pk是fou存在 if pk: pks.append(pk) else: # 保证了每个字典都有pk # 感觉有问题,如果列表中第一个字典pk值为空,其余字典的pk有值,结束程序的运行 return Response({ status: 1,msg: 传入的数据有误 }) else: return Response({ status: 1,msg: 传入的数据有误 }) # 上面只保证了,pk必须有值,没有保证其他字段必须有一个值 # 前段发送的数据有误 else: return Response({ status: 1,msg: 传入的数据有误 }) # pks中的数据进行筛选,把没有pk的request_data中的数据去除 # 取出每个pk进行判断,判断该pk的数据是否存在, # 定义一个对象列表,存放pk数据存在的 book_objs = [] # 定义一个列表存放,pk对应的数据存在的,其余数据 new_request_data = [] for index,pk in enumerate(pks): # 从数据库中查,判断是否有该pk对应的数据 try: # 该pk对应的数据是否存在,是否被删除 old_obj = models.Book.objects.get(pk=pk,is_delete=False) book_objs.append(old_obj) # 对应索引的数据就需要保存下来 new_request_data.append(request_data[index]) except: # 重点: 反面教材,如pk对应的数据有误,将对应索引的中request_data中的数据移除 # index = pks.index(pk) # request_data.pop(index) continue # 遇到不符合要求的数据,继续进行for循环,直到循环结束为止 # context = {‘request‘: request} book_ser = serializers.BookModelSerializer(instance=book_objs,data=new_request_data,many=True,partial=True) book_ser.is_valid(raise_exception=True) book_obj = book_ser.save() # 不能实现群改,需要重写update方法,在serializers.py文件中书写 return Response({ status: 0,msg: 修改成功,many=True).data })

  2. generics.py工具视图>> GenericAPIView

    1)? 完全继承APIView

    2) 继承之后的操作

      get_queryset(): 从类属性queryset中获取model的queryset数据

      get_object(): 从类属性queryset中获取model的queryset数据,在通过有名分组pk确定唯一对象

      get_serializer(): 从类属性serializer_class中获取的serializer的序列化类

    3) urls.py

urlpatterns = [

    url(r^v2/books/$,views.BooKGenericAPIView.as_view()),url(r^v2/books/(?P<pk>.*)/$,]

    4) views.py

?

from rest_framework.generics import GenericAPIView
from . import serializers
from . import models
from utils.response import APIResponse

# 见名知导入的文件
class BooKGenericAPIView(GenericAPIView):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer
    # 自定义有名分组的名字
    lookup_field = pk  # 默认
    # 群取
    def get(self,**kwargs):
        book_query = self.get_queryset()
        book_ser = self.get_serializer(book_query,many=True)
        book_data = book_ser.data
        return APIResponse(results=book_data)

    # 单增
    # def get(self,**kwargs):
    #     book_obj = self.get_object()
    #     book_ser = self.get_serializer(book_obj)
    #     book_data = book_ser.data
    #     return APIResponse(results=book_data)

?

  3. mixins.py

    1) mixins视图工具集

"""
mixins视图工具集: 用来辅助GenericAPIView
    1) mixins有五个工具类文件,一共提供了五个工具类,六个工具方法: 
          单增,单删,群查,单查,单整体改,单局部改
    2) 继承工具类可以简化请求函数的实现体,但是必须继承GenericAPIView,需要GenericAPIView类提供的几个类属性和方法
    3) 工具类的工具方法返回值都是Response类型对象,如果要格式化数据,返回给前台,可以通过request.data 拿到工具方法返回的Response类型的响应数据
"""

    2) urls.py

urlpatterns = [

    url(r^v3/books/$,views.BookMixinsGenericAPIView.as_view()),url(r^v3/books/(?P<pk>.*)/$,]

    3) views.py

from rest_framework.mixins import ListModelMixin,RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin
from . import serializers
from . import models
from utils.response import APIResponse


class BookMixinsGenericAPIView(GenericAPIView,ListModelMixin,DestroyModelMixin):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer
    lookup_field = pk
    # 坑: TypeError: Object of type ‘Response‘ is not JSON serializable
    # 解决: response.data
    def get(self,**kwargs):
        # 单查,群查
        if "pk" in kwargs:
            response = self.retrieve(request,**kwargs)
        else:
            response = self.list(request,**kwargs)
        return APIResponse(results=response.data)

    def post(self,**kwargs):
        response = self.create(request,**kwargs)
        return APIResponse(results=response.data)

    def put(self,**kwargs):
        response = self.update(request,**kwargs)
        return APIResponse(results=response.data)

    def patch(self,**kwargs):
        response = self.partial_update(request,**kwargs)
        return APIResponse(results=response.data)

  4. viewsets.py视图集

    1)??

    2) urls.py

urlpatterns = [

    url(r^v6/books/$,views.BookModelViewSet.as_view({get: list,post: create})),# post 单增
    url(r^v6/books/(?P<pk>.*)/$,views.BookModelViewSet.as_view({
        get: retrieve,put: update,patch: partial_update,delete: destroy
    })),]

    3) views.py

from rest_framework.viewsets import ModelViewSet
class BookModelViewSet(ModelViewSet):
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BookModelSerializer
    def destroy(self,**kwargs):
        instance = self.get_object() # type  models.Book对象
        # 传入的参数不对
        if not instance:
            return APIResponse(1,删除失败)  # 实际操作在此之前就完成了
        instance.is_delete = True
        instance.save()
        return APIResponse(0,删除成功)

    """ 群增,群删,群局部改,群整体改???????????"""

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读