Python+Flask后台交互

一、概况

Python Web框架有很多个,比如Django、Flask、Tornado等框架。这个三个框架在Web端是比较有影响力的,尤其是Django框架,在快速开发上占有一定的优势。但是Django框架属于重量级框架,它能想到的功能都会事先帮你想好。你只要按照它的模块要求写,一个网站就能很快速搭建出来。

Flask和Tornado框架就属于轻量级框架了,它只提供最核心的功能,其余的功能需要用自己手写或者用第三方来支持。那么到底是用Djnago还是用Flask。如果业务变化快,可以选用Flask,自己来搭建符合自己公司业务后端架构。如果业务基本不变,可以选用Django,开发起来速度比较快。Flask框架最为Python后端新生代的代表!

如果突然报错!

在这里插入图片描述

临时解决办法:

$ ps -fA | grep python
henry    127112   1181  0 12:07 ?        00:00:05 /usr/bin/python /usr/bin/x-terminal-emulator
henry    127201 124727  0 12:09 ?        00:00:01 python3 -u /home/henry/dev/myproject/flaskr/flaskr.py
henry    127252 127122  0 12:20 pts/4    00:00:00 grep --color=auto python

$ kill 127201

目前Flask的文档是1.0版本

英文文档  http://flask.pocoo.org/docs/1.0/
中文文档  http://docs.jinkan.org/docs/flask/index.html

三、环境搭建

首先安装虚拟环境,命令如下:

sudo pip3 install virtualenv

接下来还要安装虚拟环境扩展包,命令如下:

sudo pip3 install virtualenvwrapper

安装虚拟环境包装器的目的是使用更加简单的命令来管理虚拟环境。
修改用户家目录下的配置文件.bashrc,添加如下内容:

export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
source /usr/local/bin/virtualenvwrapper.sh

然后执行source .bashrc让配置生效。

创建一个名字为 flask_1.0的环境:

mkvirtualenv flask_1.0

安装Flask

pip install flask

创建Flask项目

首先打开pycharm 左上角new project

Python+Flask后台交互_第1张图片

配置目录名 和虚拟环境 点击create 创建

写一个最简单的代码呈现
Python+Flask后台交互_第2张图片
在这里插入图片描述

运行效果

Python+Flask后台交互_第3张图片

代码呈现:

from flask import Flask
"""
__name__ :表示当前模块名字
创建Flask对象,Flask会传入模块的位置当做家目录
"""
app = Flask(__name__)

@app.route('/') # 代表首页

def hello_world(): # 视图函数
    return 'Hello World!'

if __name__ == '__main__':
    app.run() # 运行程序
运行 python 你的当前py文件
按住CTRL 点击

在这里插入图片描述

会出现源码 这里面初始化了好多方法

Python+Flask后台交互_第4张图片

所以我们用,逗号间隔 书写我们要配置的参数

在这里插入图片描述

所以我们要在左侧的 static目录 创建一个html文件 里面书写一些文字

Python+Flask后台交互_第5张图片

仔细观察下路径

原路径

Python+Flask后台交互_第6张图片

自己设定的1807路径

Python+Flask后台交互_第7张图片

我们可以设置一个配置文件 config.cfg这个代表 配置debug 之后可以 自动检测运行服务器时的报错

Python+Flask后台交互_第8张图片

TEST 是我们随便起的变量 我们可以轻松利用

当我们运行当前文件时 会打印积极

Python+Flask后台交互_第9张图片
在这里插入图片描述

来调用在我们的视图函数里 并打印在命令横中

同时 我们在去 配置DEbug

在if name == ‘main’:前面 来配置

# 配置文件
app.config.from_pyfile('config.cfg')

还有几种不用写文件配置的方法 我推荐写文件方法

类方式配置

class Config(object):
    DEBUG = True


app.config.from_object(Config)
直接操作
app.config["DEBUG"] = True
对象上配置
app.debug = True
参数传入配置(只限debug参数)
app.run(debug=True)  # 运行程序

Python+Flask后台交互_第10张图片

重定向

首先导入我们需要的两个

在这里插入图片描述

当我们重定向 center函数时

Python+Flask后台交互_第11张图片

代码如下

@app.route('/center')
def center():
    return 'center'

@app.route('/mycenter')
def mycenter():
    return redirect(url_for('center')) #函数名

当我们去请求mycenter时

Python+Flask后台交互_第12张图片

这时 他的路径会自动变成center

Python+Flask后台交互_第13张图片

如果想要路径不变 就要在绑定一个路由 所以一个视图可以绑定多个路由

Python+Flask后台交互_第14张图片

代码呈现

# 一个视图可以绑定多个路由
@app.route('/mycenter')
@app.route('/center')
def center():
    return 'center'

@app.route('/mycenter')
def mycenter():
    return redirect(url_for('center')) #函数名

这时我们在访问 mycenter 路径就在也不会变了

Python+Flask后台交互_第15张图片

上述都是通过get 来访问请求 我们也可以通过设置get post来访问

在这里插入图片描述

代码呈现

@app.route('/myorder',methods=['POST','GET'])
def order():
    return 'myorder'

当我们使用post 访问时 就要使用到postman 软件 来访问 得到我们想要的结果

Python+Flask后台交互_第16张图片

转换器

我们在访问页面时可以携带参数 一般我们携带的是str 字符串 以下还提供了三种类型 int 整数 float 小数 path 可以放带/的路径

Python+Flask后台交互_第17张图片

第一个运行结果

Python+Flask后台交互_第18张图片

第二个运行结果

Python+Flask后台交互_第19张图片

第三个运行结果

Python+Flask后台交互_第20张图片

设置自定义转换器匹配手机号

Python+Flask后台交互_第21张图片

# 自定义转换器 匹配手机号
from werkzeug.routing import BaseConverter
class MyConverter(BaseConverter):
    def __init__(self,map):
        super().__init__(map) # 调用父类 父类会初始化一些东西
        self.regex = r"1[3456789]\d{9}"

# 注册转化器
app.url_map.converters['rephone'] = MyConverter

@app.route("/register/")
def register(phone):
    # app.url_map 打印 所有视图的url配置
    print(app.url_map)
    print(phone)
    return '注册成功'
在上述代码中 类继承了BaseConverter方法 调用父类初始化的一些参数 然后重写正则匹配手机号 进行 转换器注册类 设置路由返回结果

这时我们要先看下源码BaseConverter在这当中初始化了两个方法 我们要继承map视图 和regex 匹配正则

Python+Flask后台交互_第22张图片

这里的converters 也是源码中的方法 让我们看下

点击converters进入 然后选中 ctrl+f进行搜索

Python+Flask后台交互_第23张图片

点击回车

Python+Flask后台交互_第24张图片

再点击回车

Python+Flask后台交互_第25张图片

我们看到这个方法被converters而接收 所以我们使用它

Python+Flask后台交互_第26张图片

通用自定义转换器

我们先看下大神写的流程

Python+Flask后台交互_第27张图片

上我们的代码

Python+Flask后台交互_第28张图片

from werkzeug.routing import BaseConverter
# 通用调用自定义转换器
class MyConverter1(BaseConverter):
    def __init__(self,map,re):
        super().__init__(map) # 调用父类 父类会初始化一些东西
        self.regex = re

    def to_python(self, value):
        return value
    def to_url(self, value):
        return '12388888888'

# 注册转化器
app.url_map.converters['re'] = MyConverter1



@app.route("/myregister/")
def myregister(uid):
    print(uid)
    return str(uid)

@app.route("/register/")
def register(phone):
    return redirect(url_for("myregister",uid=phone)) # 重定向才执行 to_url

代码流程

Python+Flask后台交互_第29张图片

按照流程发起请求

在这里插入图片描述

得到结果

Python+Flask后台交互_第30张图片

少输一位试试 请求不到

Python+Flask后台交互_第31张图片

Flask之模板初识

首先导入

在这里插入图片描述

代码如下

Python+Flask后台交互_第32张图片

from flask import render_template
@app.route('/templat')
def templat():
    ctx = {
        "name": '老王',
        "age": 12,
        "hobby": ["下棋", '电影'],
        "test": {"a": 1, "b": 2}
    }

    return render_template('templat.html', **ctx) # 一定要是关键字参数 **ctx 

绘制模板 首先在templates里面创建一个 templat的html文件

Python+Flask后台交互_第33张图片


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
 名字: <span>{{ name }}span> <br>
年龄: <span>{{ age }}span> <br>
取列表第一个: <span>{{ hobby[0] }}span><br> 代表取列表第一个 取索引
取字典a对应的值:<span>{{ test.a }}span><br> 代表取列表第一个 取值


body>
html>

呈现效果

Python+Flask后台交互_第34张图片

标签遍历取值

Python+Flask后台交互_第35张图片

<ul>
    {%   for r in hobby %}
        <p>{{ r }}p>
    {%   endfor %}
ul>

Python+Flask后台交互_第36张图片

查询标签索引

Python+Flask后台交互_第37张图片

效果

Python+Flask后台交互_第38张图片

过滤器

Python+Flask后台交互_第39张图片

长度过滤器:
{{ name|length }}<br>

默认过滤器,当后台没有返回sex的时候会执行:
{{ sex|default('男') }}<br>

反转过滤器:
{{ name|reverse }}<br>

效果

在这里插入图片描述
Python+Flask后台交互_第40张图片

自定义过滤器

# 自定义过滤器

def handletime(time,*index):
    return time.strftime('%Y-%m-%d %H:%M')

def add(nums,nums1):
    return nums+5


app.jinja_env.filters['handletime'] = handletime  # 注册过滤器
app.jinja_env.filters['add'] = add

Python+Flask后台交互_第41张图片
在这里插入图片描述

GET 请求

首先访问register.html 页面 提交请求 并把值传给/rese/add 返回数据
from flask import Flask, request

@app.route('/rese')  # 代表首页
def index():  # 视图函数
    return render_template('register.html')

# get请求
@app.route('/rese/add')  # 代表个人中心页
def rese():  # 视图函数
    if request.method == 'GET':  # 请求方式是get
        name = request.args.get('name')  # args取get方式参数
        age = request.args.get('age')
        hobby = request.args.getlist('hobby')  # getlist取一键多值类型的参数
        return "姓名:%s 年龄:%s 爱好:%s" % (name, age, hobby)

页面源码

<form action="/center/add" method="get">
    用户名:<input type="text" name="name"><br>
    年龄:<input type="text" name="age"><br>
    爱好:吃<input type="checkbox" name="hobby" value=""><input type="checkbox" name="hobby" value=""><input type="checkbox" name="hobby" value=""><input type="checkbox" name="hobby" value=""><br>

    <input type="submit" value="提交">

form>

Python+Flask后台交互_第42张图片
Python+Flask后台交互_第43张图片
Python+Flask后台交互_第44张图片
Python+Flask后台交互_第45张图片

POST请求 get获取数据用args,post获取请求form 还有一个values 可以通用这两个参数

from flask import Flask, request

@app.route('/rese')  # 代表首页
def index():  # 视图函数
    return render_template('register.html')

# get请求
@app.route('/rese/add',methods=['GET','POST'])  # 代表个人中心页
def rese():  # 视图函数
    if request.method == 'GET':  # 请求方式是get
        name = request.args.get('name')  # args取get方式参数
        age = request.args.get('age')
        hobby = request.args.getlist('hobby')  # getlist取一键多值类型的参数
        return "姓名:%s 年龄:%s 爱好:%s" % (name, age, hobby)
    elif request.method == 'POST':  # 请求方式是get
        name = request.form.get('name')  # args取get方式参数
        age = request.form.get('age')
        hobby = request.form.getlist('hobby')  # getlist取一键多值类型的参数
        return "姓名:%s 年龄:%s 爱好:%s" % (name, age, hobby)

Python+Flask后台交互_第46张图片
Python+Flask后台交互_第47张图片

上传图片

# 上传图片

from flask import Flask, request, render_template, redirect, url_for
from werkzeug.utils import secure_filename
import os
from flask import send_from_directory
app.config['UPLOAD_FOLDER'] = app.config.get('UPLOAD_FOLDER')

# 判断上传文件是否允许后缀
def allowed_file(filename):
    # 让 文件名分割.后面的名字 并且取.的倒数第一个分割一次 变为小写 并包含config文件里的参数
    return "." in filename and filename.rsplit('.', 1)[1].lower() in app.config.get('ALLOWED_EXTENSIONS')

@app.route('/pic',methods=['GET', 'POST'])  # 代表首页
def pic():  # 视图函数
    if request.method == 'GET':
        return render_template('pic.html')
    else:
        if "file" not in request.files:
            return redirect(request.url)

        file = request.files.get('file')  # 获取文件

        if file.filename == '':
            return redirect(request.url)

        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)  # 用这个函数确定文件名称是否是安全 (注意:中文不能识别)
            # 将文件名进行路径拼接
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))  # 保存文件
            return redirect(url_for('show',filename=filename))

@app.route('/show/')
def show(filename):
    # send_from_directory可以从目录加载文件
    return send_from_directory(app.config['UPLOAD_FOLDER'],filename)

secure_filename含义

Python+Flask后台交互_第48张图片

Python+Flask后台交互_第49张图片
在这里插入图片描述
Python+Flask后台交互_第50张图片

Session 状态保持小demo

我自己的方法
Python+Flask后台交互_第51张图片

from flask import Flask,current_app,session
from flask import redirect,url_for
from flask_session import Session
import redis
# 初始化Session对象
f_session = Session()

"""
__name__ :表示当前模块名字
创建Flask对象,Flask会传入模块的位置当做家目录
"""
app = Flask(__name__,static_url_path='/1807')

app.config['SECRET_KEY'] = 'laowangaigebi'  # 加密的密钥
app.config['SESSION_USE_SIGNER'] = True  # 是否对发送到浏览器上session的cookie值进行加密
app.config['SESSION_TYPE'] = 'redis'  # session类型为redis
app.config['SESSION_KEY_PREFIX'] = 'session:'  # 保存到session中的值的前缀
app.config['PERMANENT_SESSION_LIFETIME'] = 7200  # 失效时间 秒
app.config['SESSION_REDIS'] = redis.Redis(host='127.0.0.1', port='6379', db=4)  # redis数据库连接

# 绑定flask的对象
f_session.init_app(app)


@app.route('/') # 代表首页

def hello_world(): # 视图函数
    return "hello"
#----------------------------------------------------------
# session状态保持
@app.route('/login')  # 负责输入账号密码
def login():
    return render_template('login.html')

@app.route('/login/add',methods=['POST'])  # 负责匹配账号密码 获取数据存为session 
def loginh():  # 视图函数
    if request.method == 'POST':
        name = request.form.get('name')
        password = request.form.get('password')
        if name == '123456' and password == '123456':
            session['xingming'] = name
            session['password'] = password
            return redirect(url_for("loginb")) # 转换到def loginb()执行
        else:
            return "密码账号错误"

@app.route('/rrrr')  # 代表首页
def loginb():
    token = session.get('password')
    if token:
        username = session.get('xingming')
        return render_template('rrrr.html',username=username)
    else:
        return render_template('rrrr.html')

@app.route('/logout')  # 代表清除session 退出登录
def logout():

    session.clear()
    return redirect(url_for("loginb")) # 跳转登录页

login.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录title>
head>
<body>
     <form action="/login/add" method="post">
    用户名:<input type="text" name="name"><br>
    密码:<input type="text" name="password"><br>


    <input type="submit" value="登录">

    form>

body>
html>
rrrr.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
head>
<body>
    {% if username %}
        用户为{{ username }}
        <a href="/logout">退出a>
    {% else %}
        <a href="/login">登录a>
    {% endif %}

body>
html>

#### 效果
Python+Flask后台交互_第52张图片
Python+Flask后台交互_第53张图片
Python+Flask后台交互_第54张图片
Python+Flask后台交互_第55张图片

大神的方法

Python+Flask后台交互_第56张图片
Python+Flask后台交互_第57张图片

王者荣耀小案例:

from flask_sqlalchemy import SQLAlchemy
import pymysql

pymysql.install_as_MySQLdb()

# 设置连接数据库的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/db_flask'

# 数据库和模型类同步修改
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True

db = SQLAlchemy(app)

# 类型
class Type(db.Model):
    # 表名
    __tablename__ = 'tbl_types'

    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    name = db.Column(db.String(32), unique=True)  # 名字

    # 数据库中不存在的字段,只是为了查找和反向查找。
    # backref:在关系的另一模型中添加反向引用
    heros = db.relationship("Hero", backref='type')

    def __repr__(self):
        return self.name
#
# # 英雄
class Hero(db.Model):
    # 表名
    __tablename__ = 'tbl_heros'
    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    name = db.Column(db.String(64), unique=True)  # 名字
    gender = db.Column(db.String(64))  # 性别

    def __repr__(self):
        return self.name

    # 外键 一个射手对应很多英雄
    type_id = db.Column(db.Integer, db.ForeignKey("tbl_types.id"))


@app.route('/sj')  # 代表首页
def sj():  # 视图函数
    a=Type.query.all()


    return render_template('sj.html',a=a)
#
@app.route('/sa/')  # 代表首页
def sa(id):  # 视图函数

    a=Type.query.get(id)
    # b = Hero.query.get(id)
    b = a.heros
    # b = Hero.query.get(a)

    return render_template('sa.html',b=b)

sj.html

<body>
	<ul>
        {% for i in a %}
    {#      <p><a href="/sa/{{ i.id }}">{{ i }}a>p><br>#}
            <li><a href="/sa/{{ i.id }}">{{ i }}a>li>

        {% endfor %}
    ul>
body>

sa.html

<body>
    {% for i in b %}
    {#        <p><a href="/sa/{{ i.id }}">{{ i }}a>p><br>#}
            <li>{{ i.name }}li>

    {% endfor %}

body>

Python+Flask后台交互_第58张图片
Python+Flask后台交互_第59张图片
Python+Flask后台交互_第60张图片

相亲系统小案例:

# 首先导入flask 插件SQLAlchemy 可以认为是django的orm
from flask_sqlalchemy import SQLAlchemy
# 在导入pyMySQL 链接数据库
import pymysql

# 设置数据库的一些配置
# 设置连接数据库的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/db_flask'

# 数据库和模型类同步修改
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True

db = SQLAlchemy(app)

# 导入时间
from datetime import datetime

# 我们开始创建模型
class Regist(db.Model):
    # 表名 数据库里面的表名为 tbl_regist
    __tablename__ = 'tbl_regist'

    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    name = db.Column(db.String(1000),nullable=False)  # 名字
    numphone = db.Column(db.String(100),nullable=False, unique=True)  # 手机 号 在我们开发过程中手机号可以设置成唯一 这样对以后制作功能有好处
    password = db.Column(db.String(100),nullable=False) # 密码
    gender = db.Column(db.SmallInteger(),nullable=False,default=1) # 性别

# 表的创建时间
    createtime = db.Column(db.DATETIME,default=datetime.now())
    # 表的更新时间
    updatetime = db.Column(db.DATETIME, default=datetime.now(),onupdate=datetime.now())

然后我们创建表

if __name__ == '__main__':
   
 	db.create_all() # 创建所有表

创建我们需要的路由

# 负责注册
@app.route('/regist')
def wery():
   return render_template('regist.html')

# 注册页的请求
@app.route('/regist/add',methods=['get','POST'])
def registadd():
   return redirect(url_for('logi'))


# 登录页
@app.route('/logi')
def logi():
   return render_template('logi.html')

# 登录页的请求
@app.route('/logi/add',methods=['get','POST'])
def logiadd():
   pass

# 展示页
@app.route('/show')
def show1():
   return render_template('show.html')

python 文件.py名 运行

等等 我们还要配置模板里面的内容

注册页:regist.html

<body>
   <form action="/regist/add" method="post">
       用户名:<input type="text" name="name" maxlength="10" minlength="6"  ><br>
       手机号:<input type="text" name="numphone" maxlength="11" minlength="6"><br>
       密码:<input type="password" name="password" maxlength="12"><br>
       性别:男<input type="radio" name="gender" value="1"><input type="radio" name="gender" value="0"><br>
       // maxlength最大长度
   
       <input type="submit" value="注册">
       <a href="/logi">已有账号请登录!a>
   
   form>


body>

登录页:logi.html

<body>
   <a href="/regist">注册a>
   <br>
   <form action="/logi/add" method="post">
   手机号:<input type="text" name="name" maxlength="11"><br>
   密码:<input type="password" name="password" maxlength="12" minlength="6"><br>


   <input type="submit" value="登录">

   form>

body>

运行下 看看页面效果

Python+Flask后台交互_第61张图片

用户名是手机号

Python+Flask后台交互_第62张图片

开始写我们的注册逻辑

1. 判断字段在不在form表单里
2.  取出来为不为空
3. 手机号是否合法
4. 两次密码是否一样
5. 密码位数是否正确
6. 昵称位数是否正确
7. 手机号是否已经注册
8. 性别是否合法

然后导入

from flask import Flask, request, render_template, redirect, url_for

在注册regist/add 写功能:

@app.route('/regist/add',methods=['GET','POST'])
def registadd():
   if request.method == 'GET':
       return render_template('regist.html')

   #  判断输入的值在 form表单里吗?
   if 'numphone' not in request.form or \
           'password' not in  request.form  or \
           'password1' not in  request.form or \
           'name' not in request.form or \
           'gender' not in request.form:
       return redirect(url_for('wery'))

   numphone = request.form.get('numphone')
   password = request.form.get('password')
   password1 = request.form.get('password1')
   name = request.form.get('name')
   gender = request.form.get('gender')

   #  判断 取的值如果为空
   if not numphone or not password or not password1 or not name or not gender:
       print('不能为空')
       return redirect(url_for('wery'))
   # 判断手机号不合法
   if not re_phone(numphone):
       print('手机不合法')
       return redirect(url_for('wery'))
   # # 判断性别
   if gender not in ['0','1']:
       print('性别不合法')
       return redirect(url_for('wery'))
   #
   # # 判断重复密码
   if password != password1:
       print('密码不一致')
       return redirect(url_for('wery'))
   #
   # # 判断密码长度
   if len(password) < 6 or len(password) > 12:
       print('密码长度不对')
       return redirect(url_for('wery'))
   #
   # # 判断名字长度
   if len(name) < 6 or len(name) > 10:
       print('名字过长')
       return redirect(url_for('wery'))

   # #查手机号是否注册
   user = Regist.query.filter_by(numphone=numphone).first()
   if user:
       print('用户已存在')
       return redirect(url_for('wery'))
   # 加密过的密码
   bpwd = a_pwd(password)
   # 存储用户
   user = Regist()
   user.numphone = numphone
   user.password = bpwd
   user.name = name
   user.gender = gender

   db.session.add(user)
   db.session.commit()
   return redirect(url_for('logi'))

Python+Flask后台交互_第63张图片
Python+Flask后台交互_第64张图片
Python+Flask后台交互_第65张图片

Python+Flask后台交互_第66张图片

在logi/add 写登录功能

from flask import Flask,current_app,session
from flask import redirect,url_for
from flask_session import Session
import redis
# 初始化Session对象
f_session = Session()

"""
__name__ :表示当前模块名字
创建Flask对象,Flask会传入模块的位置当做家目录
"""
app = Flask(__name__,static_url_path='/1807')

app.config['SECRET_KEY'] = 'laowangaigebi'  # 加密的密钥
app.config['SESSION_USE_SIGNER'] = True  # 是否对发送到浏览器上session的cookie值进行加密
app.config['SESSION_TYPE'] = 'redis'  # session类型为redis
app.config['SESSION_KEY_PREFIX'] = 'session:'  # 保存到session中的值的前缀
app.config['PERMANENT_SESSION_LIFETIME'] = 7200  # 失效时间 秒
app.config['SESSION_REDIS'] = redis.Redis(host='127.0.0.1', port='6379', db=4)  # redis数据库连接


# 绑定flask的对象
f_session.init_app(app)
@app.route('/logi/add',methods=['GET','POST'])
def logiadd():
    if request.method == 'GET':
        return render_template('logi.html')
    #  判断输入的值在 form表单里吗?
    if 'numphone' not in request.form or \
            'password' not in request.form:
        return redirect(url_for('logi'))

    numphone = request.form.get('numphone')
    password = request.form.get('password')


    #  判断 取的值如果为空
    if not numphone or not password:
        print('不能为空')
        return redirect(url_for('logi'))
    # 判断手机号不合法
    if not re_phone(numphone):
        print('手机不合法')
        return redirect(url_for('logi'))
    # 加密过的密码
    bpwd = a_pwd(password)
    user = Regist.query.filter_by(numphone=numphone).first()
    if not user:
        print('用户已存在')
        return redirect(url_for('logi'))
    if user.password != bpwd:
        print('密码不正确')
        return redirect(url_for('logi'))
    session['uid'] = user.id
    session['name'] = user.name

    return redirect(url_for('show1'))
@app.route('/show')
def show1():
    return render_template('show.html')

输入错误密码

Python+Flask后台交互_第67张图片

展示页功能

@app.route('/show')
def show1():
    uid = session.get('uid')
    if not uid:
        return render_template('show.html')
    user = Regist.query.get(uid)
    if not user:
        return render_template('show.html')
    user_list = Regist.query.filter(Regist.gender != user.gender).all()

    ctx = {
        'name':user.name,
        'user_list':user_list
    }
    return render_template('show.html',**ctx)

show.html

<body>
    {% if name %}
        欢迎您:{{ name }}<br>
        <a href="/out">注销</a>
        <ul>
            {% for user in user_list %}
                <li>{{ user.name }}--{{ user.gender }}</li>
            {% endfor %}

        </ul>
    {% else %}
        <a href="/logi">登录</a>
    {% endif %}


</body>

状态保持注销

@app.route('/out')
def exitout():
    session.clear()
    return redirect(url_for('show1'))

效果

Python+Flask后台交互_第68张图片

如果想把 ssss–0这个性别0改为 汉字就要在模型底下写

@property
    def dec_gender(self):
        if self.gender == 0:
            return '女'
        else:
            return '男'

Python+Flask后台交互_第69张图片
Python+Flask后台交互_第70张图片

扩展与迁移

一、概况

在Django框架开发过程中,我们对数据库字段添加或删除,直接修改模型类,然后进行迁移可以了,非常方便。我们也想让Flask框架支持这样的操作,就需要使用Flask-Migrate扩展,来实现数据迁移。并且集成到Flask-Script中,所有操作通过命令就能完成。

二、安装

为了导出数据库迁移命令,Flask-Migrate提供了一个MigrateCommand类,可以附加到flask-script的manager对象上。
先安装下面两个扩展:

pip install Flask-Script

pip install flask-migrate
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
app = Flask(__name__)
manager = Manager(app) # 让Manager管理
if __name__ == '__main__':
    manager.run() # 运行程序

Python+Flask后台交互_第71张图片

生成迁移

点击 ctrl 按住Migrate
在这里插入图片描述
继承app,db

Python+Flask后台交互_第72张图片

Migrate(app,db)
manager.add_command('db',MigrateCommand)

创建个简单的模型

class egist(db.Model):
    # 表名
    __tablename__ = 'egist'

    # 数据库真正存在的字段
    id = db.Column(db.Integer, primary_key=True)  # 主键
    name = db.Column(db.String(1000),nullable=False)  # 名字

初始化文件名

python 文件.py db init

Python+Flask后台交互_第73张图片

生成这样一个文件

Python+Flask后台交互_第74张图片

生成文件

python 文件名.py db migrate -m 'first create'

在这里插入图片描述
Python+Flask后台交互_第75张图片

执行文件

python app.py db upgrade

在这里插入图片描述
Python+Flask后台交互_第76张图片

如果增加一个字段就要

1.生成
python 文件名.py db migrate -m 'first create'

2.执行
python app.py db upgrade

Python+Flask后台交互_第77张图片
里面base指的是原始版本。例如我们发现我们刚才添加的字段并没有什么作用,我们就可以回退到原始版本。

python flask_migrate_db.py db downgrade base

博客小案例

建表:

from flask_sqlalchemy import SQLAlchemy
import pymysql

pymysql.install_as_MySQLdb()

# 设置连接数据库的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:[email protected]:3306/WORK'

# 数据库和模型类同步修改
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True

db = SQLAlchemy(app)

# 创建数据库迁移对象
Migrate(app, db)

# 向脚步管理添加数据库迁移命令 db指命令的别名
manager.add_command('db', MigrateCommand)













# -------------------------------------------------------------------------------
# 继承类 实现代码的复用 让每个表里都有 id isdelete create_time update_time
class BaseModel(object):
    id = db.Column(db.Integer,primary_key=True) # id
    isdelete = db.Column(db.BOOLEAN,default=False) # 非物理删除 布尔类型 默认不删除
    create_time = db.Column(db.DATETIME,default=datetime.now()) # 创建时间 默认现在的时间
    update_time = db.Column(db.DATETIME,default=datetime.now(),onupdate=datetime.now()) # 更新时间

# -------------------------------------------------------------------------------
# 辅助表 多个标签 对应 多个文章的辅助表 两个外键相互对应
# 其中tbl_tags创建的表名 从tbl_tag.id 取的tag_id命名的外键id名| 从tbl_article.id 取的 article_id命名的外键id名
tbl_tags = db.Table('tbl_tags',
                    db.Column('tag_id',db.Integer,db.ForeignKey('tbl_tag.id')),
                    db.Column('article_id',db.Integer,db.ForeignKey('tbl_article.id')))

# -------------------------------------------------------------------------------
# 文章表 继承BaseModel 使用id isdelete create_time update_time 字段
class Article(BaseModel,db.Model):
    __tablename__ = 'tbl_article'

    title = db.Column(db.String(32),default='') # 标题 字符类型
    content = db.Column(db.TEXT,default='') # 内容 TEXT类型

    # 外键关系 类型为Integer 外键是tbl_category对应的id
    category_id = db.Column(db.Integer,db.ForeignKey('tbl_category.id'))

    # 在article中  反向查找 Tag类里的 tbl_tags 辅助表
    tags = db.relationship('Tag',secondary=tbl_tags,backref='article')

    def __repr__(self):
        return self.title # title 显示中文

# -------------------------------------------------------------------------------
#一个分类 对应 多个文章
# 分类表  继承BaseModel 使用id isdelete create_time update_time 字段
class Category(BaseModel,db.Model):
    __tablename__ = 'tbl_category'
    name = db.Column(db.String(32),default='') # 分类名字
    #  在category中  反向查找 Article类里的数据
    articles = db.relationship('Article',backref='category')

    def __repr__(self):
        return self.name  # name显示中文
# -------------------------------------------------------------------------------
#多个标签 对应 多个文章
# 标签表 继承BaseModel 使用id isdelete create_time update_time 字段
class Tag(BaseModel,db.Model):
    __tablename__ = 'tbl_tag'
    name = db.Column(db.String(32),default='') # 标签名字

    def __repr__(self):
        return self.name  # name显示中文

插数据

if __name__ == '__main__':
    #manager.run() # 运行程序

    # 分类
    category1 = Category(name='程序人生')
    category2 = Category(name='技术杂谈')

    db.session.add_all([category1,category2])

    # 标签
    tag1 = Tag(name='程序员')
    tag2 = Tag(name='生活')
    tag3 = Tag(name='Python')

    db.session.add_all([tag1,tag2,tag3])

    # 链接文章 数据Article表
    article = Article()
    # 文章标题
    article.title = '不想当程序员'
    # 文章内容
    article.content = '学不懂了学不懂了'
    # 文章分类
    article.category = category1
    # 添加标签tag1
    article.tags.append(tag1)
    # 添加标签tag2
    article.tags.append(tag2)

    # 再链接数据表 添加一条数据
    article1 = Article()
    article1.title = 'Python入门'
    article1.content = 'print(hello)'
    article1.category = category2
    article1.tags.append(tag3)

    db.session.add_all([article,article1])
    db.session.commit()

你可能感兴趣的:(Flask)