源码繁琐,多说无益,耐心细读官方文档:数据库
https://www.django-rest-framework.org/django
我的总结:json
REST是一种软件架构设计风格,不是标准,也不是具体的技术实现,只是提供了一组设计原则和约束条件。api
DRF(Django RestFramework)是一套基于Django开发的、帮助咱们更好的设计符合REST规范的Web应用的一个Django App,因此,本质上,它是一个Django App。浏览器
安装: (肯定Django已经安装)服务器
>>> pip install djangorestframework
1 APIView cookie
首先须要了解django中views.View类及其相关流程,看以下关系图(最好看源码):session
DRF APIView请求流程:架构
DRF对django视图配置流程图(我的画)app
2 解析器组件 (用来解析数据的请求的组件)
Django并不能处理请求协议为application/json编码协议的数据
注意: DRF解析器会封装到View中的parsers内,在视图函数被调用时,会传入request,经过request.data拿到数据才进行解析 ,即解析器解析是在request对象传入后.
解析器组件流程图:
//解析器的使用方式: //1,导入模块 views.py from rest_framwork.views import APIView //2, 继承APIView class BookView(APIView): def get(self, request): pass //3, url.py from django.urls import path, include, re_path from classbasedview import views urlpatterns = [ re_path('login/$', views.LoginView.as_view()), ] //4, def post(self, request): origin_data = request.data ... return HttpResponse({})
试用工具: postman---经过postman来模拟用户请求,再也不须要使用浏览器来发送请求.(直接在官网下载便可)
3 序列化组件
序列化组件的使用:
--get接口设计:
{{ 实践代码 }}
--post接口设计
{{ 实践代码 }}
使数据自动插入并且更加简单:
class BookSerializer(serializers.ModelSerializer): class Meta: model = Book fields = ('title', 'price', 'publish', 'authors', 'author_list', 'publish_name', 'publish_city' ) extra_kwargs = { 'publish': {'write_only': True}, 'authors': {'write_only': True} } publish_name = serializers.CharField(max_length=32, read_only=True, source='publish.name') publish_city = serializers.CharField(max_length=32, read_only=True, source='publish.city') author_list = serializers.SerializerMethodField() def get_author_list(self, book_obj): # 拿到queryset开始循环 [{}, {}, {}, {}]
authors = list() for author in book_obj.authors.all(): authors.append(author.name) return authors
步骤以下:
继承ModelSerializer: 再也不继承Serializer
添加extra_kwargs类变量: extra_kwargs = { 'publish':{'write_only':True}}
4 视图组件
使用视图组件进行接口逻辑化
导入mixin
from rest_framework.mixinx import ( ListModelMix, CreateModelMixin, DestroyModelMixin, UpdateModelMixin, RetrieveModelMixin ) from rest_framework.generics import GenericAPIView
定义序列化类
Class BookSerializer(serializers.ModelSerializer): class Meta: Book fields = () extra_kwargs = {"field_name": {"write_only": True}}
导入序列化类
from .app_serializers import BookSerializer
定义视图类
class BookView(ListModelMix, CreateModelMixin, GenericAPIView): # queryset和serializer_class是固定的写法
queryset = Book.objects.all() serializer_class = BookSerializer def get(): return self.list() def post(): return self.create() class BookFilterView(RetrieveModelMixin, DestroyModelMixin, UpdateModelMixin, GenericAPIView): queryset = Book.objects.all() serializer_class = BookSerializer def get(): return self.retrieve() def delete(): return self.destroy() def put(): return self.update()
注意: 单条数据操做的url是这样的:re_path(r'books/(?P<pk>\d+)/$, views.BookFilterView.as_view())
使用视图组件的view进行接口逻辑优化
导入模块 from rest_framework import generics
写试图类
class BookView(generics.ListCreateAPIView) queryset = Book.objects.all() serializer_class = BookSerializer class BookFilterView(generics.RetrieveUpdateDestroyAPIView): queryset = Book.objects.all() serializer_class = BookSerializer
使用视图组件的viewset进行接口逻辑优化
导入模块 from rest_framework.viewset import ModelViewSet
设计url
re_path(r'books/$, views.BookView.as_view({
'get': 'list', 'post': 'create' })), re_path(r'books/(?P<pk>\d+)/$', views.BookView.as_view({ 'get': 'retrieve', 'delete': 'destroy', 'put': 'update' }))
设计视图类
class BookView(ModelViewSet): queryset = Book.objects.all() serializer_class = BookSerializer
5 认证组件
cookie和session两种方式能够保存用户信息,这两种方式不一样的是cookie保存在客户端浏览器中,而session保存在服务器中,他们各有优缺点,配合起来使用,可将重要的敏感的信息存储在session中,而在cookie中能够存储不太敏感的数据。
token称之为令牌。cookie、session和token都有其应用场景,没有谁好谁坏,不过开发数据接口类的Web应用,目前用token仍是比较多的。
token认证步骤:
用户登陆,服务器端获取密码,查询用户表,若是存在该用户且第一次登陆(或者token过时), 生成token,不然返回错误信息
若是用户不是第一次登陆,且token未过时,更新token值
建立俩个model,(token能够存储在user表中,建议存储在user表中):
from django.db import models # Create your models here.
class User(models.Model): username = models.CharField(max_length=32) password = models.CharField(max_length=32) user_type_entry = ( (1, 'Delux'), (2, 'SVIP'), (3, "VVIP") ) user_type = models.IntegerField(choices=user_type_entry) address = models.CharField(max_length=32) def __str__(self): return self.username class UserToken(models.Model): user = models.OneToOneField("User", on_delete=models.CASCADE) token = models.CharField(max_length=128)
由于涉及登陆认证,因此写post方法接口,登陆都是post请求:
from django.http import JsonResponse from rest_framework.views import APIView from .models import User, Book, UserToken from .utils import get_token class UserView(APIView): def post(self, request): response = dict() try: username = request.data['username'] password = request.data['password'] user_instance = User.objects.filter( user_name=username, password=password ).first() if user_instance: access_token = get_token.generater_token() UserToken.objects.update_or_create(user=user_instance, defaults={ "token": access_token }) response["status_code"] = 200 response["status_message"] = "登陆成功" response["access_token"] = access_token response["user_role"] = user_instance.get_user_type_display() else: response["status_code"] = 201 response["status_message"] = "登陆失败,用户名或密码错误"
except Exception as e: response["status_code"] = 202 response["status_message"] = str(e) return JsonResponse(response)
经过获取随机字符串的方法用来生成token值:
# -*- coding: utf-8 -*-
import uuid def generater_token(): random_str = ''.join(str(uuid.uuid4()).split('-')) return random_str
DRF认证组件的使用:
新建一个认证类,包含以后的认证逻辑:
class UserAuth(object): def authenticate_header(self, request): pass
def authenticate(self, request): user_post_token = request.query_params.get('token') token_object = UserToken.objects.filter(token=user_post_token).first() if token_object: return token_object.user.username, token_object.token else: raise APIException("认证失败")
实现方式看上去很是简单,到token表里面查看token是否存在,而后根据这个信息,返回对应信息便可,而后,在须要认证经过才能访问的数据接口里面注册认证类便可:
class BookView(ModelViewSet): authentication_classes = [UserAuth, UserAuth2] queryset = Book.objects.all() serializer_class = BookSerializer
多个认证类实现:
注意:若须要返回数据,请在最后一个认证类中返回,由于在前面返回,self.authentication()方法中会对返回值进行判断,若不为空,认证的过程就会终止. 多个认证类实现方式以下:
class UserAuth2(object): def authenticate(self, request): raise APIException("认证失败") class UserAuth(object): def authenticate_header(self, request): pass
def authenticate(self, request): user_post_token = request.query_params.get('token') token_object = UserToken.objects.filter(token=user_post_token).first() if token_object: return token_object.user.username, token_object.token else: raise APIException("认证失败") class BookView(ModelViewSet): authentication_classes = [UserAuth, UserAuth2]
简化authenticate_header方法,以下:(继承BaseAuthentication类便可)
from rest_framework.authentication import BaseAuthentication class UserAuth2(BaseAuthentication): def authenticate(self, request): raise APIException("认证失败") class UserAuth(BaseAuthentication): def authenticate(self, request): user_post_token = request.query_params.get('token') token_object = UserToken.objects.filter(token=user_post_token).first() if token_object: return token_object.user.user_name, token_object.token else: raise APIException("认证失败")
全局认证:
实现全部的数据接口都须要认证:
authentication_classes=api_settings.DEFAULT_AUTHENTICATION_CLASSES
若是认证类本身没有authentication_classes,就会到settings中去找,经过这个机制,咱们能够将认证类写入到settings文件中便可实现全局认证:
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'authenticator.utils.authentication.UserAuth', 'authenticator.utils.authentication.UserAuth2', ), }
6 权限组件
定义权限类:
class UserPerms(): message = "您没有权限访问该数据"
def has_permission(self, request, view): if request.user.user_type > 2: return True else: return False
一样的逻辑,一样的方式,只是执行权限的方法名与执行认证的方法名不同而已,名为has_permission,而且须要将当前的视图类传递给该方法。
视图类中加入permission_classes变量:
class BookView(ModelViewSet): authentication_classes = [UserAuth] permission_classes = [UserPerms2] queryset = Book.objects.all() serializer_class = BookSerializer
7 频率组件
8 url控制器组件
9 分页器组件
10 响应器组件