測試平台開發(三)Django實現登錄注冊功能


在Django中通常一個功能的開發順序為:創建應用 -> 數據庫表字段設計 -> 視圖函數編寫 -> 應用路由 -> 全局路由 -> 測試

Django的工作流程是:

 

一、創建用戶應用

打開 Tools > Run manage.py Task…,運行 startapp空格加應用名稱

startapp users  # startapp:創建應用的關鍵字,user:為應用的名字

生成應用后一定要記得將應用名加入到settings.py文件里名為INSTALLED_APPS的列表中,遵循規范加入到列表的最后,再添加應用也一樣

# settings.py
INSTALLED_APPS=[
  ……,
  'users',
]

應用目錄詳解

users
 ├── migrations  # 存放遷移數據表的歷史文件,內容自動生成
 │    └── __init__.py  # 一個空文件,告訴 Python 該目錄是一個 Python 包。
 ├── __init__.py  # 一個空文件,告訴 Python 該目錄是一個 Python 包。
 ├── admin.py  # 該應用的后台管理系統配置,這里用不到
 ├── apps.py    # 該應用的一些配置,這里用不到
 ├── models.py    # 數據模塊,用來定義數據表結構
 ├── tests.py    # Django提供的自動化測試功能,這里用不到
 └── views.py    # 視圖模塊,代碼邏輯處理的主要地點,項目中大部分代碼均在這里編寫

 

二、編寫數據模型

創建時間、修改時間和邏輯刪除這些字段會經常用到,每次都寫代碼會很冗余,解決辦法就是寫一個類繼承使用

1.在項目跟目錄下創建utils目錄,再在utils目錄下創建base_models.py文件

 1 # utils/base_models.py
 2 from django.db import models
 3 
 4 
 5 class BaseModel(models.Model):
 6     """
 7     數據庫表公共字段
 8     """
 9     create_time = models.DateTimeField(auto_now_add=True, verbose_name='創建時間', help_text='創建時間')
10     update_time = models.DateTimeField(auto_now=True, verbose_name='更新時間', help_text='更新時間')
11     is_delete = models.BooleanField(default=False, verbose_name='邏輯刪除', help_text='邏輯刪除')
12 
13     class Meta:
14         # abstract = True:為抽象模型類,用於其他模型類繼承,數據庫遷移時不會創建ModelBase表
15         abstract = True
16         verbose_name = '公共字段表'
17         db_table = 'BaseModel'

 

2.編寫用戶表的模型,繼承上面的類

 1 #users/models.py
 2 from django.db import models
 3 
 4 from utils.base_models import BaseModel
 5 
 6 
 7 class Users(BaseModel):
 8     id = models.AutoField(primary_key=True, verbose_name='id主鍵')
 9     username = models.CharField(max_length=50, unique=True, verbose_name='用戶名')
10     password = models.CharField(max_length=50, verbose_name='密碼')
11     email = models.EmailField(max_length=50, verbose_name='郵箱')
12 
13     def __str__(self):
14         return self.username
15 
16     class Meta:
17         db_table = 'lx_users'
18         verbose_name = '用戶數據'
19         verbose_name_plural = verbose_name

遷移數據庫,打開 Tools > Run manage.py Task…,依次行

makemigrations
migrate

 

三、編寫視圖函數

1.先把需要用的token認證機制寫出來,token 這里使用Python中的 pyjwt 庫

1.1 安裝 pip install pyjwt

pip install pyjwt

1.2 生成token,在users目錄下邊創建generate_token.py文件

 1 # users/generate_token.py
 2 from datetime import datetime, timedelta
 3 import jwt
 4 
 5 from django.conf import settings
 6 
 7 def generate_jwt_token(username):
 8     token = jwt.encode({
 9         'exp': datetime.utcnow() + timedelta(days=1),
10         'iat': datetime.utcnow(),
11         'data': {
12             'username': username
13         }
14     }, settings.SECRET_KEY, algorithm='HS256')
15     return token.decode('utf-8')

1.3 認證token的裝飾器,在utils目錄下創建jwt_permission_required.py文件

 1 # utils/jwt_permission_required.py
 2 import jwt
 3 from django.conf import settings
 4 from django.http import JsonResponse
 5 from users.models import Users
 6 
 7 
 8 def auth_permission_required(func):
 9     def decorator(view_func):
10         def _wrapped_view(request, *args, **kwargs):
11             try:
12                 if func == "func":
13                     auth = request.META.get('HTTP_AUTHORIZATION').split()
14                 else:
15                     auth = request.request.META['HTTP_AUTHORIZATION'].split()
16             except AttributeError:
17                 return JsonResponse({"status_code": 401, "message": "沒有權限"})
18             if auth[0].lower() == 'token':
19                 try:
20                     dict = jwt.decode(auth[1], settings.SECRET_KEY, algorithms=['HS256'])
21                     username = dict.get('data').get('username')
22                 except jwt.ExpiredSignatureError:
23                     return JsonResponse({"status_code": 401, "message": "token 已過期"})
24                 except jwt.InvalidTokenError:
25                     return JsonResponse({"status_code": 401, "message": "token 無效"})
26                 except Exception as e:
27                     return JsonResponse({"status_code": 401, "message": "無法獲取用戶對象"})
28                 try:
29                     Users.objects.get(username=username)
30                 except Users.DoesNotExist:
31                     return JsonResponse({"status_code": 401, "message": "用戶不存在"})
32             else:
33                 return JsonResponse({"status_code": 401, "message": "不支持身份驗證類型"})
34             return view_func(request, *args, **kwargs)
35         return _wrapped_view
36     return decorator

 

2. 返回的參數格式需要統一規范,在utils目錄下創建common.py文件來放一些公共配置,寫一個result字典,所有返回格式都用這個

1 # utils/common.py
2 result = {
3     "message": None,
4     "success": False,
5     "details": None
6 }

 

3.表單校驗,在users目錄下創建forms.py文件,用來校驗用戶注冊時輸入的數據

 1 # users/forms.py
 2 import re
 3 
 4 from django import forms
 5 from django.core.exceptions import ValidationError
 6 
 7 from users.models import Users
 8 
 9 
10 class RegisterForm(forms.Form):
11     username = forms.CharField(
12         label="用戶名",
13         required=True,
14         max_length=50,
15         min_length=2,
16         error_messages={
17             "required": "用戶名不能為空",
18             "max_length": "用戶名最長不能超過50個字符",
19             "min_length": "用戶名最小長度為2"
20         })
21     password = forms.CharField(
22         label="密碼",
23         required=True,
24         max_length=50,
25         min_length=5,
26         error_messages={
27           "required": "密碼不能為空",
28           "max_length": "密碼最長不能超過50個字符",
29           "min_length": "密碼最小長度為5"
30         })
31     r_password = forms.CharField(
32         required=True,
33         max_length=50,
34         min_length=5,
35         label="確認密碼",
36         error_messages={
37             "required": "確認密碼不能為空",
38             "max_length": "確認密碼最長不能超過50個字符",
39             "min_length": "確認密碼最小長度為5"
40         })
41     email = forms.CharField(
42         min_length=5,
43         required=True,
44         label="郵箱",
45         error_messages={
46             "required": "郵箱不能為空",
47             "max_length": "郵箱最長不能超過50個字符",
48             "min_length": "郵箱最小長度為5"
49         }
50     )
51 
52     def clean_username(self):
53         val = self.cleaned_data.get("username")
54         ret = Users.objects.filter(username=val)
55         if not ret:
56             return val
57         else:
58             raise ValidationError("該用戶名已注冊!")
59 
60     def clean_email(self):
61         val = self.cleaned_data.get("email")
62         if re.match(r'^[0-9a-zA-Z_]{0,19}@[0-9a-zA-Z]{1,13}\.[com,cn,net]{1,3}$', val):
63             return val
64         else:
65             raise ValidationError("郵箱格式不正確!")
66 
67     # 走完所有的校驗才走clean
68     def clean(self):
69         pwd = self.cleaned_data.get("password")
70         r_pwd = self.cleaned_data.get("r_password")
71         if pwd and r_pwd:
72             if pwd != r_pwd:
73                 raise forms.ValidationError("兩次密碼不一致")
74         return self.cleaned_data

 

4.編寫用戶應用的視圖函數

 1 # users/views.py
 2 from django.http import JsonResponse
 3 from django.views import View
 4 
 5 from users.forms import RegisterForm
 6 from users.generate_token import generate_jwt_token
 7 from users.models import Users
 8 from utils.jwt_permission_required import auth_permission_required
 9 from utils.common import result
10 
11 
12 class LoginView(View):
13     def post(self, request):
14         result["message"] = "登錄失敗"
15         result["success"] = False
16         result["details"] = None
17         json_data = request.body.decode('utf-8')
18         if json_data:
19             python_data = eval(json_data)
20             username = python_data.get('username')
21             password = python_data.get('password')
22             data = Users.objects.filter(username=username, password=password).values("id", "username").first()
23             if data:
24                 token = generate_jwt_token(username)
25                 result["message"] = "登錄成功"
26                 result["success"] = True
27                 result["details"] = {"id": data["id"], "username": data["username"],"token": token}
28                 return JsonResponse(result, status=200)
29             result["details"] = "用戶名或密碼錯誤"
30             return JsonResponse(result, status=400)
31         return JsonResponse(result, status=500)
32 
33 
34 class RegisterView(View):
35     def post(self, request):
36         result["message"] = "注冊失敗"
37         result["success"] = False
38         result["details"] = None
39         json_data = request.body.decode('utf-8')
40         if json_data:
41             python_data = eval(json_data)
42             data = RegisterForm(python_data)
43             if data.is_valid():
44                 data.cleaned_data.pop("r_password")
45                 Users.objects.create(**data.cleaned_data)
46                 data.cleaned_data.pop("password")
47                 result["message"] = "注冊成功"
48                 result["success"] = True
49                 result["details"] = data.cleaned_data
50                 return JsonResponse(result, status=200)
51             else:
52                 result["details"] = data.errors
53                 return JsonResponse(result, status=400)
54         return JsonResponse(result, status=500)
55 
56 @auth_permission_required("func")
57 def demo(request):
58     if request.method == 'GET':
59         return JsonResponse({"state": 1, "message": "token有效"})
60     else:
61         return JsonResponse({"state": 0, "message": "token無效"})

 

四、編寫應用的路由

在users目錄下創建urls.py文件

 1 #users/urls.py
 2 from django.urls import path
 3 
 4 from users import views
 5 
 6 urlpatterns = [
 7     path('login', views.LoginView.as_view()),
 8     path('register', views.RegisterView.as_view()),
 9     path('demo', views.demo)
10 ]

 

五、定義全局路由

1 # testplatform/urls.py
2 from django.contrib import admin
3 from django.urls import path, include
4 
5 urlpatterns = [
6     path('admin/', admin.site.urls),
7     path('api/user/', include("users.urls")),
8 ]

 

六、測試

1.注冊接口

2.登錄接口

3.token驗證接口

  3.1 不帶token

  

  3.2 帶token

  

 

 

GitHub持續更新:地址https://github.com/debugf/testplatform

 

 轉載請注明出處,商用請征得作者本人同意,謝謝!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM