flask实战开发流程

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-sessionredis
添加这个扩展模块后,可以对flask里面配合redis对session进行操作,存储或清除字段
flask-blueprint
可以让Flask对象注册多个蓝图对象,相当于插入了blueprint的包装器,能够分割功能模块,能够更清晰的进行业务开发,而不是将所有的业务处理都写在一个views里
flask-sqlalchemypymysql
用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()
  • 定义表类时,让表类同时继承BaseModelSQLAlchemy.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下创建logsconfsrc文件
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
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值