DRF Django 学习笔记

创建第一个测试项目

安装djanago

1
pip install Django==4.2.1

‍

创建项目

1
django-admin startproject [project_name]

可以看到项目已经创建

​image​

‍

然后在pycharm打开项目

​image​

‍

项目基本结构

​image​

  • wsgi.py - 配置WSGI兼容的Web服务站点
  • asgi.py - 配置ASGI兼容的Web服务站点
  • urls.py - 配置站点转发的路径
  • settings.py - Django项目的全局配置文件(重要)

‍

添加项目模块

1
python manage.py startapp [module_app]

‍

执行以下命令创建第一个模块

1
python manage.py startapp first_module

‍

可以看到第一个模块已经创建成功

​image​

‍

添加到settings.py

​image​

‍

模块文件结构

​image​

  • views.py - 视图层,相当于Web开发中的Controller。用于拦截请求,进行逻辑处理并返回数据
  • tests.py - 用于编写测试用例
  • models.py - 模型层,用于存放与数据库实体相对应的model
  • apps.py -
  • admin.py - 一般不用

‍

运行项目

1
python manage.py runserver [port]

‍

使用7000端口启动项目

1
python manage.py runserver 7000

‍

控制台

​image​

‍

输入URL访问 http://127.0.0.1:7000/

​image​

‍

‍

连接数据库

连接MySQL

先安装mysql客户端

1
pip3 install mysqlclient

‍

启动docker数据库

通过UI启动

​image​

或通过命令启动

​image​

‍

settings.py添加数据库信息

​image​

如果能正常启动则说明配置成功

1
python3 manage.py runserver 8000

‍

DRF实现登录功能

DRF概述

DRF(Django rest framework) 基于Django的封装,是Restful风格的开发框架

官方网站 https://www.django-rest-framework.org

‍

安装

1
pip3 install djangorestframework

‍

添加到settings.py

​image​

‍

创建user和item模块

1
2
python manage.py startapp user
python manage.py startapp item

‍

添加到settings.py

​image​

‍

数据表设计

User表

1
2
3
4
5
6
7
8
9
10
11
12
from django.db import models


# Create your models here.
class User(models.Model):
id = models.AutoField(primary_key=True, null=False, unique=True)
user_name = models.CharField(null=False, max_length=255, unique=True)
is_delete = models.IntegerField()
password = models.CharField(null=False, max_length=255, unique=False)
class Meta:
db_table = "user_tbl"

‍

Item表

1
2
3
4
5
6
7
create table `item_tbl`(
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`price` int NULL DEFAULT NULL,
`vendor_id` int NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
)ENGINE = InnoDB AUTO_INCREMENT = 4894 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

‍

User表 - 根据class自动在mysql db创建

1
2
python manage.py makemigrations
python manage.py migrate

‍

数据表已经创建

​image​

‍

Item表 - 在数据库创建表,并自动在项目里生成对应的model class

​image​

‍

运行命令生成class

  • 如果需要追加则把>​替换为>>​
1
python manage.py inspectdb --database default item_tbl > item/models.py

‍

对应的class自动生成

​image​

‍

在user_tbl插入一条记录作为第一个用户

1
insert into user_tbl(user_name, is_delete, password) VALUES('test1', 0, '123456');

‍

前端UI准备

前后端分离,使用Vue + axios + Bootstrap快速开发

UI source code https://github.com/nauvalazhar/bootstrap-4-login-page

index.html引入vue和axios

1
2
<script src="https://cdn.jsdelivr.net/npm/vue@3.4.21"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>

‍

修改django主页

settings.py

​image​

‍

添加路由和controller

urls.py

​image​

views.py

​image​

‍

启动效果

​image​

‍

添加后端数据查询接口

目的:连接到数据库查询用户表,并且校验用户密码

项目入口文件urls.py添加user路由

​image​

‍

User模块下添加序列化器

*文件名必须为serializers.py​

1
2
3
4
5
6
7
8
9
from user.models import User
from rest_framework import serializers


class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"

‍

User模块下views.py添加控制器逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from django.shortcuts import render
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin


from user.models import User
from user.serializers import UserSerializer


# Create your views here.
def home_page(request):
return render(request, "index.html")


# User controller
# post - 对应db操作insert
# get - query by id
# put - update by id
# delete - delete by id
class UserMixinAPIView(GenericAPIView,
CreateModelMixin,
RetrieveModelMixin):

queryset = User.objects
serializer_class = UserSerializer

# 添加用户
# 添加user方法测试
def post(self, request):
return self.create(request)

# 查询用户
def get(self, request, pk):
return self.retrieve(request, pk)

‍

User模块下urls.py添加路由拦截规则

​image​

‍

通过postman测试get接口, user id为1

可以看到正常返回了db里的用户信息

​image​

‍

目前可以看到访问api返回的是Json数据,而不是状态码

需要添加一个工具类,并且将返回结果进行封装

​image​

修改user/views.py

​image​

‍

​image​

登录改造

一般业务场景下,不会用user_id进行登录,而是使用账号和密码

views.py

​image​

‍

urls.py也要做相应的改动

​image​

可以看到同一个get url可以兼容不同的输入参数

​image​

‍

添加前端返回结果

通过@click绑定点击事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<script src="https://cdn.jsdelivr.net/npm/vue@3.4.21"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
const app = Vue.createApp({
data() {
return {

}
},

// Method will be executed when the page initialize
created() {
// For testing
// this.loginTest();
},

// Mount your method to DOM element
mounted() {

},

// Static method
methods: {
loginTest() {
alert("Test vue.");
},

userLogin() {
var accountName = $('#account-name').val();
var accountPwd = $('#account-password').val();

var userLoginInfo = {};
userLoginInfo.accountName = accountName;
userLoginInfo.accountPwd = accountPwd;
axios.post('/user/', userLoginInfo)
.then(res => {
// debugger;
console.log(res.data);

if (res.data.status == 200) {
// TODO 登录成功,跳转到首页
alert('登录成功');
} else {
alert(res.data.msg);
}
});
}

}
})
app.mount('#loginApp')
</script>

‍

JWT认证

Web app的会话控制

  • Cookie -> 存储在浏览器(客户端)上的小文件,用于保存用户信息的key-value文件
  • Session -> 存储在服务端,用于保存用户会话所需的属性及配置信息。如果用户过多会导致占用的内存过大
  • Token -> 用户访问API资源所需的凭证,一般由身份标识、时间戳、用户必要信息等内容组成,是一串加密的字符串

‍

响应流程

‍

JWT:Json web token

官网:https://jwt.io

JWT格式

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

通过.​连接成的三段字符串

JWT组成

  • 第一段:header,指头信息包含算法,字符串是由头信息进行base64加密
  • 第二段:payload,指系统自定义存储的信息,如用户名、过期时间等,并进行base64加密
  • 第三段:verify signature,指需要系统定义 “salt”,或者称为密钥

​image​

‍

JWT服务端解密

获取token,例如

1
request.GET.get("token")

然后通过.​把字符串分割成三个部分

  • 第一步:用base64解密得到header​头部信息
  • 第二步:用base64解密得到系统中的info​用户数据
  • 第三步:判断 base64 (header + info + 系统密钥) 是否等于分割后的第三部分

*要注意保护好系统的密钥

‍

安装pyjwt

1
pip install pyjwt

‍

JWT工具类测试

Django在初始化项目的时候会自动生成一个key,可以使用这个作为密钥

也根据自定义算法生成随机字符串

​image​

‍

编写工具类生成token

设置token过期时间为5分钟

​image​

jwt_demo.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import datetime

import jwt

from djangoDRFDemo.settings import SECRET_KEY


def create_token():
headers = {
'alg': "HS256",
'typ': "jwt"
}

payload = {
'user_id': 1,
'username': "test_user",
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=1) # 定义超时时间
}

result = jwt.encode(headers=headers, payload=payload, key=SECRET_KEY, algorithm="HS256")
return result


def get_payload(token):
try:
return jwt.decode(token, SECRET_KEY,algorithms=["HS256"])
except jwt.exceptions.DecodeError:
print("token认证失败")
except jwt.exceptions.ExpiredSignatureError:
print("token已经失效了")
except jwt.exceptions.InvalidTokenError:
print("无效的token")


if __name__ == '__main__':

# 加密过程 - 生成token
token = create_token()
print("生成token:" + token)

payload = get_payload(token)
print("获取payload:" + str(payload))

# 使用旧的token测试验证过程
# 会抛出Signature has expired异常
expired_token = """eyJhbGciOiJIUzI1NiIsInR5cCI6Imp3dCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InRlc3RfdXNlciIsImV4cCI6MTcxODUzNTcyNH0.8miAzL3pG7yMRonfR68kBJdGnUM1JksyriomfdB-zFY"""
payload = get_payload(expired_token)

‍

运行结果

​image​

‍

JWT登录功能整合

首次登录时返回token

1.添加JWT工具类

​image​

‍

2.添加View方法

​image​

‍

3.添加路由

​image​

‍

4.测试接口

成功返回token

​image​

‍

针对非登录接口添加JWT验证

1.针对url中携带token进行验证

jwt工具类添加方法

​image​

‍

View中的方法也做相应的修改

​image​

‍

测试

1.先登录一次拿到token

​image​

‍

2.在参数中使用token,然后发送GET请求

​image​

‍

控制台也会打印出token的信息

​image​

‍

3.等待token过期后再次发起请求

​image​

控制台显示token失效

​image​

‍

针对请求header中携带token的验证方式

添加工具类

​image​

‍

View里做相应的修改

​image​

‍

测试接口,也是先拿到token

​image​

‍

‍

JWT全局配置

如果每一个类都添加JWT验证类,不方便维护

​image​

‍

在settings.py中添加全局配置

所有的url都会被拦截

​image​

‍

View里做相应的修改

注释掉类里的authentication

​image​

‍

需要验证的方法里面只需要添加如下代码即可

1
2
3
# 判断token状态
if not request.user.get("status"):
return ResponseMessage.UserResponse.failed("User token is invalid.")

‍

测试

​image​

‍

设置定时任务

安装APSchedule

1
pip install django_apscheduler

‍

settings.py添加

​image​

‍

执行如下命令完成DB的更改

1
2
python3 manage.py makemigrations
python3 manage.py migrate

​image​

‍

会在DB中创建APScheduler所需的表

​image​

‍

修改app folder中的urls.py

​image​

‍

启动APP即可看到效果

代码

1
2
3
4
5
6
7
8
9
from apscheduler.schedulers.background import BackgroundScheduler
from django_apscheduler.jobstores import DjangoJobStore,register_job

scheduler = BackgroundScheduler()
scheduler.add_jobstore(DjangoJobStore(), "default")

@register_job(scheduler, 'interval', seconds=5, name='auto_hello', replace_existing=True)
def test_schedule():
print("Hello schedule")
0%