Using Flask to develop a simple interface (3)-introducing MySQL

Foreword

In the previous two articles, we have learned to develop GET and POST request interfaces through Flask, but have not implemented the operation database, so our purpose today is to learn how to apply MySQL database to the current interface project.

My environment: Python 3.7.0 , MySQL 5.7

2 ways Flask operates MySQL

In general, Flask operates MySQL in two common ways: SQLAlchemy操作and SQL操作. When operating through SQLAlchemy, because most of them are operated through database objects, there is no need to write many SQL statements, but in order to consolidate SQL knowledge by the way, in this article, we will use SQL operations to learn.

At present, most of the related articles on the Internet are SQLAlchemy operations. SQLAlchemy operations are relatively simple and easy to use, because SQLAlchemy establishes a mapping between Python and SQL. If you use it, you can greatly reduce the writing of SQL statements.

When using the SQL operation mode, we need to know how to use Python to operate the MySQL database. If you are not clear, you can refer to my previous article: Using Python to Operate the MySQL Database

Database Design

We create a database, name it flask_demo, and then create a new data table user, the statement is as follows:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(20) NOT NULL,
  `password` varchar(255) NOT NULL,
  `role` tinyint(1) NOT NULL,
  `sex` tinyint(1) DEFAULT NULL,
  `telephone` varchar(255) NOT NULL,
  `address` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone` (`telephone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

The corresponding meanings of the fields in the user table are as follows:

id:用户id号,自增长
username:用户名
password:密码
role:用户角色,0表示管理员用户,1表示普通用户
sex:性别,0表示男性,1表示女性,允许为空
telephone:手机号
address:联系地址,允许为空

After the user table is created, through DESC userto view the table structure.

mysql> DESC user;
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| username  | varchar(20)  | NO   |     | NULL    |                |
| password  | varchar(255) | NO   |     | NULL    |                |
| role      | tinyint(1)   | NO   |     | NULL    |                |
| sex       | tinyint(1)   | YES  |     | NULL    |                |
| telephone | varchar(255) | NO   | UNI | NULL    |                |
| address   | varchar(255) | YES  |     | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)

New configuration file

We create a new package under the root path of the project config, and store a configuration file under this package setting.py. This file is used to configure MySQL server address, port, user name and password, database name and other parameters.

# 服务端口配置
SERVER_PORT = 9999

# MySQL配置
MYSQL_HOST = "192.168.89.128"
MYSQL_PORT = 3306
MYSQL_USER = "root"
MYSQL_PASSWD = "123456"
MYSQL_DB = "flask_demo"

Python operation MySQL

We create a new package in the project root path common, a new file in the package mysql_operate.py, the package in this document Python MySQL operation code, by which the file will be follow-up calls dbto manipulate the database objects and methods.

import pymysql
from config.setting import MYSQL_HOST,MYSQL_PORT,MYSQL_USER,MYSQL_PASSWD,MYSQL_DB

class MysqlDb():

    def __init__(self, host, port, user, passwd, db):
        # 建立数据库连接
        self.conn = pymysql.connect(
            host=host,
            port=port,
            user=user,
            passwd=passwd,
            db=db
        )
        # 通过 cursor() 创建游标对象,并让查询结果以字典格式输出
        self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)

    def __del__(self): # 对象资源被释放时触发,在对象即将被删除时的最后操作
        # 关闭游标
        self.cur.close()
        # 关闭数据库连接
        self.conn.close()

    def select_db(self, sql):
        """查询"""
        # 使用 execute() 执行sql
        self.cur.execute(sql)
        # 使用 fetchall() 获取查询结果
        data = self.cur.fetchall()
        return data

    def execute_db(self, sql):
        """更新/新增/删除"""
        try:
            # 使用 execute() 执行sql
            self.cur.execute(sql)
            # 提交事务
            self.conn.commit()
        except Exception as e:
            print("操作出现错误:{}".format(e))
            # 回滚所有更改
            self.conn.rollback()

db = MysqlDb(MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWD, MYSQL_DB)

Improve GET and POST request interface

  • Get all user information (GET interface)
@app.route("/users", methods=["GET"])
def get_all_users():
    """获取所有用户信息"""
    sql = "SELECT * FROM user"
    data = db.select_db(sql)
    print("获取所有用户信息 == >> {}".format(data))
    return jsonify({"code": "0", "data": data, "msg": "查询成功"})
  • Get user information (GET interface)
@app.route("/users/<string:username>", methods=["GET"])
def get_user(username):
    """获取某个用户信息"""
    sql = "SELECT * FROM user WHERE username = '{}'".format(username)
    data = db.select_db(sql)
    print("获取 {} 用户信息 == >> {}".format(username, data))
    if data:
        return jsonify({"code": "0", "data": data, "msg": "查询成功"})
    return jsonify({"code": "1004", "msg": "查不到相关用户的信息"})
  • User registration interface (POST interface)
@app.route("/register", methods=['POST'])
def user_register():
    username = request.json.get("username").strip()  # 用户名
    password = request.json.get("password").strip()  # 密码
    sex = request.json.get("sex", "0").strip()  # 性别,默认为0(男性)
    telephone = request.json.get("telephone", "").strip()  # 手机号,默认为空串
    address = request.json.get("address", "").strip()  # 地址,默认为空串
    if username and password and telephone:
        sql1 = "SELECT username FROM user WHERE username = '{}'".format(username)
        res1 = db.select_db(sql1)
        print("查询到用户名 ==>> {}".format(res1))
        sql2 = "SELECT telephone FROM user WHERE telephone = '{}'".format(telephone)
        res2 = db.select_db(sql2)
        print("查询到手机号 ==>> {}".format(res2))
        if res1:
            return jsonify({"code": 2002, "msg": "用户名已存在,注册失败!!!"})
        elif not (sex == "0" or sex == "1"):
            return jsonify({"code": 2003, "msg": "输入的性别只能是 0(男) 或 1(女)!!!"})
        elif not (len(telephone) == 11 and re.match("^1[3,5,7,8]\d{9}$", telephone)):
            return jsonify({"code": 2004, "msg": "手机号格式不正确!!!"})
        elif res2:
            return jsonify({"code": 2005, "msg": "手机号已被注册!!!"})
        else:
            sql3 = "INSERT INTO user(username, password, role, sex, telephone, address) " \
                  "VALUES('{}', '{}', '1', '{}', '{}', '{}')".format(username, password, sex, telephone, address)
            db.execute_db(sql3)
            print("新增用户信息 ==>> {}".format(sql3))
            return jsonify({"code": 0, "msg": "恭喜,注册成功!"})
    else:
        return jsonify({"code": 2001, "msg": "用户名/密码/手机号不能为空,请检查!!!"})

Here, when we realize user registration, registration can only set rolethe field value 1of ordinary users, the administrator does not allow direct registered users. The related interface return codes and request scenarios are as follows:

Interface return code Request scenario
0 Request parameters are correct, registration is successful
2001 In the request parameters, user name / password / mobile phone number, any parameter is empty
2002 In the request parameters, the user name has been registered for use by others
2003 In the request parameters, the sex field value is not 0 or 1
2004 In the request parameters, the format of the mobile phone number is incorrect
2005 In the request parameters, the mobile phone number has been registered for use by others
  • User login interface (POST interface)
@app.route("/login", methods=['POST'])
def user_login():
    username = request.values.get("username").strip()
    password = request.values.get("password").strip()
    if username and password:
        sql1 = "SELECT username FROM user WHERE username = '{}'".format(username)
        res1 = db.select_db(sql1)
        print("查询到用户名 ==>> {}".format(res1))
        if not res1:
            return jsonify({"code": 1003, "msg": "用户名不存在!!!"})
        sql2 = "SELECT * FROM user WHERE username = '{}' and password = '{}'".format(username, password)
        res2 = db.select_db(sql2)
        print("获取 {} 用户信息 == >> {}".format(username, res2))
        if res2:
            return jsonify({"code": 0, "msg": "恭喜,登录成功!"})
        return jsonify({"code": 1002, "msg": "用户名或密码错误!!!"})
    else:
        return jsonify({"code": 1001, "msg": "用户名或密码不能为空!!!"})

The related interface return codes and request scenarios are as follows:

Interface return code Request scenario
0 Username and password are correct, login is successful
1001 In the request parameters, the username or password is empty
1002 In the request parameters, the user name is correct and the password is incorrect
1003 In the request parameters, an unregistered username is used

Deploy the project on the server

  • app.run () configuration parameters when starting the application

With Flask, we passed app.run() when starting the application, you can configure some parameters, such as can be configured as follows:

from config.setting import SERVER_PORT
if __name__ == '__main__':
    # host为主机ip地址,port指定访问端口号,debug=True设置调试模式打开
    app.run(host="0.0.0.0", port=SERVER_PORT, debug=True)

The above code, host to be set 0.0.0.0, in order to access the external network, such as we have in Linux deployment project, if you want to request access in Windows, then you need to 0.0.0.0.

  • Add project root path to environment variables

We put the project under the root path app.pyas application startup entry file of the project, we need to root the project temporarily added to the environment variable or you may be prompted to find the relevant module when starting the application, the specific configuration is as follows:

import os, sys
from config.setting import SERVER_PORT
from api.user import app

# 项目根路径
BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, BASE_PATH)  # 将项目根路径临时加入环境变量,程序退出后失效

if __name__ == '__main__':
    # host为主机ip地址,port指定访问端口号,debug=True设置调试模式打开
    app.run(host="0.0.0.0", port=SERVER_PORT, debug=True)
  • Start the application from the command line

The start of our project can be done with only one line of commands. Taking Linux running in the background as an example, the command is as follows:

# /root/flaskDemo/app.py表示项目根路径下的app.py启动入口文件路径
# /root/flaskDemo/flaskDemo.log表示输出的日志文件路径
nohup python3 /root/flaskDemo/app.py >/root/flaskDemo/flaskDemo.log 2>&1 &

Start the project under Linux

OK, through the above content, we have successfully introduced MySQL into our interface project and can successfully make interface requests. The relevant code has been uploaded to GitHub. If you are interested, you can perform simple deployment and interface testing based on this.

GitHub source address: https://github.com/wintests/flaskDemo

Guess you like

Origin www.cnblogs.com/wintest/p/12741772.html