1. 创建虚拟环境,安装必要插件
ihome_like/>$ virtualenv --no-site-packages iHome_env
ihome_like/>$ source ./iHome_env/bin/activate
(iHome_env)ihome_like/>$ pip3 install -r packages.txt
说明:packages.txt是一个写了所需插件名字的文档,可以一次性安装所需的插件
packages.txt
pymysql
redis
flask
flask-script # 使用Manager
flask-session
flask-blueprint
flask-sqlalchemy
flask-script
使用flask-script模块里面的Manager创建对象,就是可以在python xxxxx.py 这个语句后面可以加入添加语句进行运行
flask-session
和redis
添加这个扩展模块后,可以对flask里面配合redis对session进行操作,存储或清除字段
flask-blueprint
可以让Flask对象注册多个蓝图对象,相当于插入了blueprint的包装器,能够分割功能模块,能够更清晰的进行业务开发,而不是将所有的业务处理都写在一个views里
flask-sqlalchemy
和pymysql
用Flask对象初始化SQLAlchemy,可以在flask项目中使用MTV模式进行各种对数据库的操作
2. 创建flask项目文件
创建方法:
通过终端指令创建或者使用pycharm创建flask项目创建manage.py文件
此文件为项目程序入口,在本地测试时可通过在python环境中输入命令来启动项目
python manage.py
如果使用flask-script扩展模块则可以添加配置语句
python manage.py runserver -h 地址 -p 端口号 -d
创建DOCS.md
所有接口文档的总文档,可通过总文档查看接口文档内容创建static、templates、docs、requirements、utils、app文件夹
- static:放置js文件、css文件和图片文件等
- templates:放置前端展示页面html
- docs:放置接口文档
- requirements:放置package.txt等安装需求环境的文件
- utils:放置App.py、settings.py、functions.py、config.py、status_code.py等配置文件
- App.py 创建Flask对象,注册蓝图,初始化功能模块
- settings.py 配置基础数据,如基础文件路径,数据库连接配置信息等
- functions.py 封装一些高复用的函数,便于更改和分割功能
- config.py 配置redis的使用数据
- status_code.py 封装请求响应的通用数据
- App:放置models.py、views.py等处理业务逻辑相关的文件
- models.py 创建表类对应数据库中的表,通过ORM对数据库进行增删改查
- views.py 处理请求响应,数据库操作,页面跳转等一系列业务功能
3. 配置flask环境
settings.py
import os
from .functions import get_database_config
# flask项目路径
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 静态文件夹路径
STATIC_DIR = os.path.join(BASE_DIR, 'static')
# 前端网页文件夹路径
TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates')
DATABASE = {
'database': 'mysql',
'driver': 'pymysql',
'host': '127.0.0.1',
'port': '3306',
'user': '用户名',
'password': '密码',
'name': '数据库名',
}
SQLALCHEMY_DATABASE_URI = get_database_config(DATABASE)
# 上传文件夹路径
UPLOAD_DIRS = os.path.join(STATIC_DIR, 'upload')
UPLOAD_AVATAR_DIRS = os.path.join(UPLOAD_DIRS, 'user')
UPLOAD_HOUSE_IMAGE_DIRS = os.path.join(UPLOAD_DIRS, 'house')
functions.py
from flask import session, redirect
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
session = Session()
def init_ext(app):
db.init_app(app)
session.init_app(app)
def get_database_config(database_conf):
database = database_conf['database']
driver = database_conf['driver']
host = database_conf['host']
port = database_conf['port']
user = database_conf['user']
password = database_conf['password']
name = database_conf['name']
return '{}+{}://{}:{}@{}:{}/{}'.format(database, driver, user, password, host, port, name)
# 登录验证
import functools
def login_check(run_func):
@functools.wraps(run_func)
def decorator():
try:
# 验证用户是否登录
if 'user_id' in session:
return run_func()
else:
return redirect('/user/login/')
except Exception as e:
return redirect('/user/login/')
return decorator
App.py
from flask import Flask
from utils.settings import STATIC_DIR, TEMPLATES_DIR
from .User.views import user_blue, index_blue
from .House.views import house_blue
from .Order.views import order_blue
from utils.config import Config
from utils.functions import init_ext
def create_app():
app = Flask(__name__, static_folder=STATIC_DIR, template_folder=TEMPLATES_DIR)
app.register_blueprint(blueprint=user_blue, url_prefix='/user')
app.register_blueprint(blueprint=index_blue, url_prefix='')
app.register_blueprint(blueprint=house_blue, url_prefix='/house')
app.register_blueprint(blueprint=order_blue, url_prefix='/order')
app.config.from_object(Config)
init_ext(app)
return app
manage.py
from flask_script import Manager
from App import create_app
app = create_app()
manage = Manager(app=app)
if __name__ == '__main__':
manage.run()
4. 创建表类
- 首先定义一个
BaseModel
类,将大多数表类需要使用的属性和方法定义好:
from datetime import datetime
from utils.functions import db
class BaseModel(object):
# 定义基础的模型
create_time = db.Column(db.DATETIME, default=datetime.now())
update_time = db.Column(db.DATETIME, default=datetime.now(), onupdate=datetime.now())
def add_update(self):
db.session.add(self)
db.session.commit()
def delete(self):
db.session.delete(self)
db.session.commit()
- 定义表类时,让表类同时继承
BaseModel
和SQLAlchemy.Model
,就可以使用父类的属性和方法
from werkzeug.security import generate_password_hash, check_password_hash
class User(BaseModel, db.Model):
# 数据库中表的表名
__tablename__ = 'tb_ihome_user'
# 数据库中表的字段名和字段数据类型
id = db.Column(db.INTEGER, primary_key=True)
phone = db.Column(db.String(11), unique=True)
passwd_hash = db.Column(db.String(200))
name = db.Column(db.String(30), unique=True)
avatar = db.Column(db.String(100)) # 头像
id_name = db.Column(db.String(30)) # 实名认证姓名
id_card = db.Column(db.String(18), unique=True) # 实名认证身份证
houses = db.relationship('House', backref='user')
orders = db.relationship('Order', backref='user')
#读
@property
def password(self):
return ''
# 写
@password.setter
def password(self, pwd):
self.passwd_hash = generate_password_hash(pwd)
# 对比匹配
def check_pwd(self, pwd):
return check_password_hash(self.passwd_hash, pwd)
def to_basic_dict(self):
return {
'id': self.id,
'avatar': self.avatar if self.avatar else '',
'name': self.name,
'phone': self.phone
}
建表时的关联关系设置
- 一对多
class User(BaseModel, db.Model):
__tablename__ = 'tb_ihome_user'
id = db.Column(db.INTEGER, primary_key=True)
houses = db.relationship('House', backref='user')
class House(BaseModel, db.Model):
id = db.Column(db.INTEGER, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('tb_ihome_user.id'), nullable=False)
- 多对多
ihome_house_facility = db.Table(
'tb_ihome_house_facility',
db.Column('house_id', db.Integer, db.ForeignKey('tb_ihome_house.id'), primary_key=True),
db.Column('facility', db.Integer, db.ForeignKey('tb_ihome_facility.id'), primary_key=True)
)
class House(BaseModel, db.Model):
__tablename__ = 'tb_ihome_house'
id = db.Column(db.Integer, primary_key=True)
facities = db.relationship('Facility', secondary=ihome_house_facility)
class Facility(BaseModel, db.Model):
__tablename__ = 'tb_ihome_facility'
id = db.Column(db.Integer, primary_key=True)
- 一对一
class User(BaseModel, db.Model):
__tablename__ = 'tb_ihome_user'
id = db.Column(db.INTEGER, primary_key=True)
house = db.relationship('House',backref='user', uselist=False)
class House(BaseModel, db.Model):
id = db.Column(db.INTEGER, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('tb_ihome_user.id'), nullable=False)
5. 设置路由
views.py
from flask import Blurprint
# 创建蓝图
blue = Blueprint('someStr', __name__)
# 在route里面设置相应的字符串,再与注册蓝图时的url_prefix的字符串拼接为路由路径
@blue.route('/abc123/') # 路由路径:host:port/(url_prefix)/abc123/
def index():
pass
- 设定请求与响应方式
通过在route()
包装器中设定关键字参数methods可以限制访问路由的方式,如果访问方式不匹配则找不到数据
render_template()
方法可以返回一个页面数据
jsonify()
方法则返回一个json格式的响应数据
@blue.route('/', methods=['GET', 'POST', 'PUT', 'PATCH'])
def index():
return render_template('index.html')
@blue.route(/login/, methods=['POST'])
def login():
return jsonify({'code': 200, 'msg': '登录成功'})
return jsonify(code=200, msg='登录成功')
- 登录验证
在functions.py文件中编写登录验证的包装器方法
# 登录验证
import functools
def login_check(run_func):
@functools.wraps(run_func)
def decorator(*args, **kwargs):
try:
# 验证用户是否登录
if 'user_id' in session:
return run_func(*args, **kwargs)
else:
return redirect('/user/login/')
except Exception as e:
return redirect('/user/login/')
return decorator
说明 @functools.wraps()的作用是在将函数作为参数传入包装器函数时,避免包装器函数对被包装函数产生不必要的影响,导致不可预期的错误
- 在需要使用登录检测的方法上加入
@login_check
就可以在运行函数时先进行登录检测,再判断是否需要运行函数
@blue.route('/')
@login_check
def index():
pass
6. 查询&过滤数据
使用SQLAlchemy的查询语句query
all()
方法查询一个表中的所有数据
db = SQLAlchemy()
class User(db.Model)
__tablename__ = 'tb_user'
pass
# 查询tb_user表下所有数据
User.query.all()
filter()
过滤方法查询表中符合指定条件的数据,查询结果可以为空
# 在filter中输入查询条件来查找符合条件的数据
User.query.filter(User.name=='xxx')
# 使用first()可以获取查询结果的第一条数据
User.query.filter().first()
# Order_by()排序
User.query.filter().order_by(User.create_time)
# limit()获取指定的条数
User.query.filter().limit()
# 在filter中,查询条件可以写多个,表示同时满足多个条件的表数据
User.query.filter(User.name=='xxx', User.create_time>='xxxx-xx-xx', ...)
filter中组合查询条件的方法
# and_ 与条件查询,效果和在filter()写多个查询条件效果类似
User.query.filter(and_(User.name=='xxx', User.create_time=='xxxx-xx-xx'))
# or_ 或条件查询,有一个条件满足就能查询到
User.query.filter(or_(User.name=='xxx', User.create_time=='xxxx-xx-xx'))
# not_ 非条件查询, 不满足条件则能查询到
User.query.filter(not_(User.name=='xxx'))
# in_, notin_ 对同一个表字段的多个结果进行匹配,返回查询结果
userid_list = ['1', '2', '5']
User.query.filter(User.id.in_(userid_list)) # 查询与列表id匹配的所有结果
User.query.filter(User.id.notin_(userid_list)) # 查询与列表id不匹配的所有结果
7. 项目部署到服务器
服务器环境配置
- 更新ubantu的源
sudo apt-get update
- 安装mysql
sudo apt-get install mysql-server mysql-client
说明:安装完成后会在窗口弹出页面提示输入密码两次,可以直接回车表示不输入密码,但是建议输入密码
- 设置mysql远程访问的配置
首先进入mysql.conf.d文件夹中打开mysqld.conf
注释bind_address后保存退出
cd /etc/mysql/mysql.conf.d/
vim mysqld.conf
- 启动mysql,加入外部访问权限
mysql -u root -p
- 启动mysql后输入数据库指令
use mysql
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '你的数据库密码' WITH GRANT OPTION;
flush privileges;
说明
flush privileges
命令本质上的作用是将当前user和privilige表中的用户信息/权限设置从mysql库(MySQL数据库的内置库)中提取到内存里。
MySQL用户数据和权限有修改后,希望在”不重启MySQL服务”的情况下直接生效,那么就需要执行这个命令
- 重启mysql
有时flush privileges
并不一定能生效,所以手动重启一次mysql
service mysql restart
创建项目数据库,从本地迁移数据
使用navicat创建服务器数据库连接
点击连接>mysql...
填写自己数据库的信息
如果没有密码则不填写密码行
创建一个新的数据库
将本地数据库的数据迁移到服务器新建数据库里
服务器安装nginx和uWSGI
sudo apt-get install nginx
sudo apt-get install uwsgi
检查nginx是否安装完成:用浏览器打开服务器地址看是否有页面
nginx页面所在位置 /var/www/html/
安装pip3&安装python的uwsgi模块
apt install python3-pip
pip3 install uwsgi
配置nginx文件
vim /etc/nginx/nginx.conf
- 将自己配置的nginx.conf路径写入保存
nginx.conf
http{
...
##
# Virtual Host Configs
##
include /etc[表情]inx/conf.d/*.conf;
include /etc[表情]inx/sites-enabled/*;
# 在此处添加自己的conf文件路径
include /home/app/iHome/conf/ihome.conf;
}
创建项目目录
- 在/home/app/下创建
iHome
文件夹,并在iHome下创建logs
、conf
、src
文件
cd /home/app/
mkdir iHome
cd iHome/
mkdir logs conf src
将项目上传服务器
1.可以用ftp软件(xshell/fileZilla)从本地上传到服务器
2.也可以通过上传git再从git clone到服务器创建配置文件
nginx.conf
nginx.conf
server {
listen 80;
server_name 服务器外网地址 localhost;
access_log /home/app/iHome/logs/access.log
error_log /home/app/iHome/logs/error.log
location / {
include uwsgi_params;
uwsgi_pass 127.0.0.1:8888;
uwsgi_param UWSGI_CHDIR /home/app/iHome/src/ihome_like;
uwsgi_param UWSGI_SCRIPT manage:app;
}
}
app
是manage中的Flask对象
- 配置文件
uwsgi.ini
uwsgi.ini
[uwsgi]
socket=127.0.0.1:8888
pythonpath=/home/app/iHome/src/ihome_like;
callable=app;
logto=/home/app/ihome/logs/uwsgi.log;
- 启动uwsgi.ini
启动后即可在网页上访问flask项目
uwsgi --ini uwsgi.ini