$ 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
英文文档 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
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文件
在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) # 运行程序
@app.route('/center')
def center():
return 'center'
@app.route('/mycenter')
def mycenter():
return redirect(url_for('center')) #函数名
# 一个视图可以绑定多个路由
@app.route('/mycenter')
@app.route('/center')
def center():
return 'center'
@app.route('/mycenter')
def mycenter():
return redirect(url_for('center')) #函数名
@app.route('/myorder',methods=['POST','GET'])
def order():
return 'myorder'
# 自定义转换器 匹配手机号
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 '注册成功'
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
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
<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>
<ul>
{% for r in hobby %}
<p>{{ r }}p>
{% endfor %}
ul>
长度过滤器:
{{ name|length }}<br>
默认过滤器,当后台没有返回sex的时候会执行:
{{ sex|default('男') }}<br>
反转过滤器:
{{ name|reverse }}<br>
# 自定义过滤器
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
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>
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)
# 上传图片
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)
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")) # 跳转登录页
<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>
<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>
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)
<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>
<body>
{% for i in b %}
{# <p><a href="/sa/{{ i.id }}">{{ i }}a>p><br>#}
<li>{{ i.name }}li>
{% endfor %}
body>
# 首先导入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')
<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>
<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>
1. 判断字段在不在form表单里
2. 取出来为不为空
3. 手机号是否合法
4. 两次密码是否一样
5. 密码位数是否正确
6. 昵称位数是否正确
7. 手机号是否已经注册
8. 性别是否合法
from flask import Flask, request, render_template, redirect, url_for
@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'))
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')
@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)
<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'))
@property
def dec_gender(self):
if self.gender == 0:
return '女'
else:
return '男'
在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() # 运行程序
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 文件名.py db migrate -m 'first create'
python app.py db upgrade
1.生成
python 文件名.py db migrate -m 'first create'
2.执行
python app.py db upgrade
里面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()