用flask_migrate管理model,映射数据库
flask_script用脚本运行项目命令
目的是为了在远程访问环境下使项目脱离Pycharm等IDE运行,而能直接通过python manager.py db update形式的命令行命令进行操作数据库。方法是将flask_sqlalchemy完成的代码分解成app.py(模型),config.py(DB_URI等配置内容),db_script.py(要执行的函数),manager.py(入口文件)
config.py(包含了SQLALCHEMY访问数据库和其他参数配置)
# ---coding:utf-8----
# 文件名: config.py
# @Time:2020/4/27 15:20
MYSQL = 'mysql'
PYMYSQL = 'pymysql'
HOST = '120.24.*.*'
PORT = '3306'
DATABASE = 'school'
USERNAME = 'python'
PASSWORD = '*'
DB_URI = '{mysql}+{pymysql}://{username}:{password}@{host}:{port}/{database}?charset=utf8'.format(mysql=MYSQL,pymysql=PYMYSQL,username=USERNAME, password=PASSWORD,host=HOST, port=PORT,database=DATABASE)
SQLALCHEMY_DATABASE_URI = DB_URI
SQLALCHEMY_TRACK_MOFIFICATIONS = False
app.py(模型)
rom flask import Flask
from flask_sqlalchemy import SQLAlchemy
import config
app = Flask(__name__)
# 从config.py中读取SQLALCHEMY配置
app.config.from_object(config)
db = SQLAlchemy(app)
class BackendUser(db.Model):
__tablename__ = 'backend_user'
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(50), nullable=False)
email = db.Column(db.String(50),nullable=False)
def __repr__(self):
return self.username
#db_script.py(flask_script脚本)
from flask_script import Manager
db_manager = Manager()
@db_manager.command #使用命令装饰符,可以运行命令
def init():
print("初始化迁移目录")
@db_manager.command
def revision():
print("生成迁移脚本")
@db_manager.command
def upgrade():
print("脚本映射到数据库成功")
manager.py(入口文件)
from flask_script import Manager
from app import app
from db_script import db_manager
manager = Manager(app) #1.flask_script的Manager实例化,注册app
manager.add_command('db',db_manager) #2.增加命令:命令名称
if __name__ == "__main__":
manager.run()
可以在命令窗口运行:python manager.py db init会运行自定义的init函数,出现"初始化迁移目录"
- 如果直接在manager.py中增加命令,可以使用python manager.py greet来运行:
@manager.command
def greet():
print("hello,nihao!")
运行:python manager.py greet,会出现"hello,nihao!"
- 可以增加参数,实现增加数据 如python manager.py add_user -u zhangsan -e abc@sdf.com
@manager.option("-u","--username",dest="username") #使用装饰器传参(将参数通过命令行传给项目)
@manager.option("-e","--email",dest="email") #第二个参数
def add_user(username,email):
user = BackendUser(username=username,email=email)
db.session.add(user)
db.session.commit()
运行:python manager.py add_user -u zhangsan -e zhangsan@sa.com,会在数据库中增加记录
flask_migrate
在实际的开发环境中,经常会发生数据库修改的行为。一般我们修改数据库不会直接手动的去修改,而是去修改ORM对应的模型,然后再把模型映射到数据库中。这时候如果有一个工具能专门做这种事情,就显得非常有用了,而flask-migrate就是做这个事情的。flask-migrate是基于Alembic进行的一个封装,并集成到Flask中,而所有的迁移操作其实都是Alembic做的,他能跟踪模型的变化,并将变化映射到数据库中。
- config.py 配置
DB_HOST = '120.24.*'
DB_PORT = '3306'
DB_NAME = 'school'
DB_USERNAME = 'python'
DB_PASSWORD = '*'
DB_URI = 'mysql+pymysql://{username}:{password}@{host}:{port}/{db}?charset=utf8mb4'.format(username=DB_USERNAME,password=DB_PASSWORD,host=DB_HOST,port=DB_PORT,db=DB_NAME)
SQLALCHEMY_DATABASE_URI = DB_URI
SQLALCHEMY_TRACK_MODIFICATIONS = False
- exts.py 扩展用于创建db实例,用于models.py建表,用于app.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy() #db来自flask_sqlalchemy,用于操作数据库
- models.py 建表的模型,用db建表
from exts import db
class ClassMate(db.Model):
__tablename__ = 'classmate'
id = db.Column(db.Integer,primary_key=True,autoincrement=True)
username = db.Column(db.String(50),nullable=False)
age = db.Column(db.Integer)
- app.py
from flask import Flask
import config
from exts import db
app = Flask(__name__)
app.config.from_object(config) #读取配置
db.init_app(app) #db绑定app
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
- manager.py flask_migrate在本文件管理ORM
# ---coding:utf-8----
# 文件名: manager.py
# @Time:2020/4/27 18:59
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager
from models import ClassMate #要导入此类,否则不能生成classmates表
from app import app
from exts import db
manager = Manager(app) #创建了一个manager对象,以支持自定义命令的配置
Migrate(app,db) #创建一个Migrate对象并关联对应的应用程序类对象app和数据库管理类对象db
manager.add_command('db',MigrateCommand) #将MigrateCommand命令加入到manager对象中,这样就可以在命令行中进行数据库迁移的相关命令
if __name__ == "__main__":
manager.run()
完成后,用命令行进行创建一个待迁移的仓库
python test.py db init
=== 'db’是在manager.add_command(‘db’,MigrateComand)这句中我们声明的命令行对象名称,init是Migrate命令,表示初始化迁移仓库,运行完成之后,会在当前目录下创建一个migrations的文件夹,用于进行迁移的数据库脚本都放在这里.===
添加好之后,使用下面的命令自动添加迁移的脚本:
python test.py db migrate -m “inition migrate”
使用upgrade和downgrade命令分别向数据库更新数据和从数据库更新数据,使用upgrade命令将本次的改动更新到数据库中:
python test.py db upgrade
验证:查看数据库是否新生成一个classmates的表
需要修改模型(增删改)时,应该在init之后完成,修改模型后使用命令:
python test.py db migrate -m “inition migrate”
确定无误再进行upgrade. (未测试成功)
WTForms
这个库一般有两个作用。第一个就是做表单验证,把用户提交上来的数据进行验证是否合法。第二个就是做模版渲染。
- pip install wtforms
- forms.py (由wtforms进行表单元素的渲染与验证,不需要在模板html上定义表单元素和验证了)
# ---coding:utf-8----
# 文件名: forms.py
# @Time:2020/4/28 20:01
from wtforms import Form, StringField, SubmitField
from wtforms.validators import Length, EqualTo
# 通过定义一个类来定义表单元素,这个类继承自wtforms的Form类
class RegisterForm(Form):
username = StringField(validators=[Length(min=3,max=10,message="长度3-10")]) #生成一个文本框,名为username,用validators规定验证规则
password1 = StringField(validators=[Length(min=6,max=10,message="长度6-10")])
password2 = StringField(validators=[EqualTo("password1")]) #与password1完全相同
submit1 = SubmitField('提交') #提交按钮
- app.py
from flask import Flask, render_template, request
from forms import RegisterForm
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
@app.route('/register/',methods=['GET','POST'])
def register():
form = RegisterForm(request.form) #用wtforms定义的类生成实例对象form,该对象包含了提交请求内的form部分内容
if request.method == "GET":
return render_template("register.html",form=form) #响应请求,将form发送给页面
else:
if form.validate():
print(form.username.data) #本地打印form中username.data
print(form.password1.data)
return 'Successful!'
else:
print(form.errors)
return 'fail'
if __name__ == '__main__':
app.run()
- register.html 无需再用等表单元素,由wtforms提供的form进行渲染
<form action="" method="post">
用户名:{{form.username()}}<br/>
密码1:{{ form.password1() }}<br/>
密码2:{{ form.password2() }}<br/>
{{form.submit1()}}
</form>
- manage.py 入口文件
from flask_script import Manager
from app import app
manager = Manager(app)
if __name__ == "__main__":
manager.run()
运行:
python manage.py runserver -d -r