需求:

设计一个登陆接口,返回一个json格式响应。

分析:

在视图层完成登陆请求的用户名和密码的数据库数据校验,然后返回对应的json格式结果。

结果可能性:

  • 第一:用户名重名-bug,需返回一个状态,数据库中存在两个重名的用户
  • 第二:用户名不存在,在数据库中查询不到
  • 第三:密码错误
  • 第四:都正确

定义json的格式:

  • "reason": "数据库中存在同名的用户","result": [],"error_code": 2000
  • "reason": "用户名不存在","result": [],"error_code": 2001
  • "reason": "密码错误","result": [],"error_code": 2002
  • "reason": "数据库服务错误","result": [],"error_code": 2003
{
        "reason": "登陆成功",
        "result": {
                            username:请求的用户名
                            password:登陆成功
},
"error_code": 0 / * 登陆成功* /
}

第一步:数据库创建和连接

以sqlite为例:https://blog.51cto.com/blogger/publish?old=1

创建以下数据库:库名my.db,建表userinfo,一条记录用户名:Test1234,密码:123456

(base) PS E:\learn\djangotest> sqlite3
SQLite version 3.36.0 2021-06-18 18:36:39
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open my.db 
sqlite> .tables
sqlite> create table userinfo(username varchar(10),password varchar(10));
sqlite> .tables                                                           
userinfo
sqlite> insert into userinfo values("Test1234","123456")
   ...> ;
sqlite> select * from userinfo; 
Test1234|123456
sqlite>

在模型层中创建一个模块连接sqlite数据库,并完成数据的读取操作:

# Conn_Sqlite.py
#该文件完成sqlite数据库中的数据读取操作,任何一个数据库操作其主要都是基于链接对象的创建
import sqlite3

from djangotest.settings import BASE_DIR


class ConnSqlite(object):
    def __init__(self):
        print("基本地址", BASE_DIR) # 基本地址 E:\learn\C10\InterfaceProgram
        self.conn = sqlite3.connect(BASE_DIR + "/Login/Model/my.db")
        self.cursor = self.conn.cursor()

    # 读取数据
    def read_data(self, str_sql):
        self.cursor.execute(str_sql)
        get_result = self.cursor.fetchall()
        return get_result


if __name__ == '__main__':
    print(BASE_DIR + "/Login/Model/my.db")
    conn = ConnSqlite()
    str_sql = "select password from userinfo where username='%s'" % 'Test1234'
    print(conn.read_data(str_sql))

第二步:获取请求中的用户名和密码

#Login_Check_Action.py
# 从页面上获取数据,并封装在一个方法中
def get_userinfo(self,method_obj):
        #与前端页面进行交互的,同样可以设定默认值,如果前端没有对应的属性时,则取默认值,如果有值则取前端所获取到属性所对应的值
        get_username=method_obj.get("username","wangwu")  #如果携带的参数不是username的话,则默认值是wangwu
        get_password=method_obj.get('password')
        return {"password":get_password,"username":get_username}


第三步:完成从请求数据与数据库中数据进行对比:

##Login_Check_Action.py

# 获取数据库连接对象
    def get_database(self, username):
        conn = ConnSqlite()
        str_sql = "select password from userinfo where username='%s'" % username
        return conn.read_data(str_sql)

    #实现比较,并设定返回指定内容的格式数据。
    def compare_data(self, method_obj):
        get_page_info = self.get_userinfo(method_obj)
        get_database_info = self.get_database(get_page_info["username"])
        print("获取的页面信息:", get_page_info)

        return_result = {"reason": [], "result": [], "error_code": []}
        if len(get_database_info) > 1:
            return_result["reason"] = "数据库中存在同名的用户"
            return_result["error_code"] = 2000  # return {"reason": "数据库中存在同名的用户","result": get_page_info,"error_code": 2000}
        elif len(get_database_info) == 0:
            return_result["reason"] = "用户名不存在"
            return_result["error_code"] = 2001  # return {"reason":"用户名不存在","result": get_page_info,"error_code": 2001}
        elif get_database_info[0][0] != get_page_info["password"]:
            return_result["reason"] = "密码错误"
            return_result["error_code"] = 2002  # return {"reason": "密码错误","result": get_page_info,"error_code": 2002}
        else:
            return_result["reason"] = "登陆成功"
            return_result["error_code"] = 0
            return_result["result"] = get_page_info  # return { "reason": "登陆成功","result":get_page_info,"error_code": 0 }
        return return_result


第四步:通过指定的请求方法将结果响应给客户端,

例如,声明get和post方法

#Login_Check_Action.py
def get(self,request):
        #return HttpResponse(self.get_userinfo(request.GET))
        return HttpResponse(json.dumps(self.compare_data(request.GET),ensure_ascii=False))


def post(self,request):
        return HttpResponse(json.dumps(self.compare_data(request.POST),ensure_ascii=False))


第五步:完成urls路由映射操作

from django.contrib import admin
from django.urls import path
from Login.View.Login_Check_Action import LoginCheckAction
urlpatterns = [
    path('admin/', admin.site.urls),
    path("loginAction",LoginCheckAction.as_view()),
]

第1-5步总结:Login_Check_Action.py

那么以上所有的代码就构成了视图层的整个业务逻辑处理实现,将上面的所有方法声明在一个类中即可

# 该模块完成数据库的校验,从页面上传入的登陆数据实现后台数据库中的数据进行比较校验,如果存在且一致则表示登陆成功,否则登陆失败
from django.views import View
from django.http import HttpResponse
from Login7.Model.Conn_Sqlite import ConnSqlite
import json
#from TestOrm.models import UserInfo


class LoginCheckAction(View):
    # 根据页面传入的用户名与数据库中的数据进行比较密码、检测用户是否存在

    # 第一步:先获取到请求中的用户名和密码数据
    # 先获取到请求中的用户名和密码数据,从页面上获取数据,并封装在一个方法中
    def get_userinfo(self, method_obj):
        # 与前端页面进行交互的,同样可以设定默认值,如果前端没有对应的属性时,则取默认值,如果有值则取前端所获取到属性所对应的值
        get_username = method_obj.get("username", "wangwu")
        get_password = method_obj.get('password')
        return {"password": get_password, "username": get_username}

    # 第三步:(1)获取数据库中数据,此处以django自带的sqlite的数据库为实例:,为了获取数据库连接对象
    def get_database(self, username):
        conn = ConnSqlite()
        str_sql = "select password from userinfo where username='%s'" % username
        return conn.read_data(
            str_sql)  # 真正完成页面数据与数据库中数据进行比较的操作  # 分析:第一:用户名重名,这是个bug需要返回一个状态,数据库中存在两个重名的用户  # 第二:用户名不存在,在数据库中查询不到  # 第三:密码错误  # 第三:都正确  # 定义json的格式:"reason": "数据库中存在同名的用户","result": [],"error_code": 2000  # "reason": "用户名不存在","result": [],"error_code": 2001  # "reason": "密码错误","result": [],"error_code": 2002  # "reason": "数据库服务错误","result": [],"error_code": 2003  # {  #     "reason": "登陆成功",  #     "result": {  #                username:  #                 password:  # },  # "error_code": 0 / * 发送成功 * /  # }  # 第三步:(2)完成从请求中获取的数据与数据库中数据进行对比,


    def compare_data(self, method_obj):
        get_page_info = self.get_userinfo(method_obj)
        get_database_info = self.get_database(get_page_info["username"])
        print("获取的页面信息:", get_page_info)
        return_result = {"reason": [], "result": [], "error_code": []}
        if len(get_database_info) > 1:
            return_result["reason"] = "数据库中存在同名的用户"
            return_result[
                "error_code"] = 2000  # return {"reason": "数据库中存在同名的用户","result": get_page_info,"error_code": 2000}
        elif len(get_database_info) == 0:
            return_result["reason"] = "用户名不存在"
            return_result["error_code"] = 2001  # return {"reason":"用户名不存在","result": get_page_info,"error_code": 2001}
        elif get_database_info[0][0] != get_page_info["password"]:
            return_result["reason"] = "密码错误"
            return_result["error_code"] = 2002  # return {"reason": "密码错误","result": get_page_info,"error_code": 2002}
        else:
            return_result["reason"] = "登陆成功"
            return_result["error_code"] = 0
            return_result["result"] = get_page_info  # return { "reason": "登陆成功","result":get_page_info,"error_code": 0 }
        return return_result

        # 第四步:通过指定的请求方法将结果响应给客户端,例如,声明get和post方法


    def get(self, request):
        # return HttpResponse(self.get_userinfo(request.GET))
        return HttpResponse(json.dumps(self.compare_data(request.GET), ensure_ascii=False))


    def post(self, request):
        return HttpResponse(json.dumps(self.compare_data(request.POST), ensure_ascii=False))

解决错误1

执行报错: D:\Anaconda3\python.exe E:\learn\testProject\Login\Modle\Conn_Sqlite.py Traceback (most recent call last): File "E:\learn\testProject\Login\Modle\Conn_Sqlite.py", line 22, in print(BASE_DIR + "Login/Modle/my.db") TypeError: unsupported operand type(s) for +: 'WindowsPath' and 'str'

解决:修改settings.py

"Login",

#BASE_DIR = Path(__file__).resolve().parent.parent
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

        #"DIRS": [BASE_DIR / 'Login/Template'],
        "DIRS":[os.path.join(BASE_DIR,'/Template')],
        
        # "NAME": BASE_DIR / "db.sqlite3",
        "NAME": os.path.join(BASE_DIR, "/my.db"),

解决错误2

执行报错:post请求,在请求过程中出现403forbidden的话,

解决:修改django中的设置,如下图:

python接口测试:1.7 Django实现GET、POST接口实战_sqlite

因为CSRF 表示django全局发送post请求均需要字符串验证

功能:防止跨站请求伪造的功能

工作原理:客户端访问服务器端,在服务器端正常返回给客户端数据的时候,而外返回给客户端一段字符串,等到客户端下次访问服务器端时,服务器端会到客户端查找先前返回的字符串,如果找到则继续,找不到就拒绝。

如果就是不想注释的话,可以通过修改header,在views打印cookie可以得到csrftoken

def index(request):
    print("cookie",request.COOKIES)
    #cookie {
    # 'csrftoken': 'AB9v1MGTbdpSGg3FaGCIiUxrKVR8zKSqgdGFDn5E0ADsJ2ST7N2zgW6KboQ8G31x',
    # 'sessionid': 'eexw5p38vky9qo38nf372dz5lj1br6xf'
    # }
    #cookie 是浏览器给的,
    return HttpResponse("index")