1、pip install Flask
2、pip install Flask-Script
3、pip install Flask-blueprint
4、pip install Flask-Session
5、pip install Flask-SQLAlchemy
6、pip install Flask-Migrate
7、pip install Flask-Bootstrap
8、pip install Flask-DebugToolbar
9、pip install Flask-Cache
10、pip install Flask-RESTful
11、pip install Flask-Mail
虚拟环境的迁移:
pip freeze > requirements.txt #迁移脚本requirements.txt保存的位置为当前目录
pip install -r requirements.txt
虚拟环境
安装pip
CentOS yum install pip
Ubuntu apt install python-pip
记得前面添加sudo
注意:如果没有apt 那么解决办法 sudo apt update 更新源中的软件包包管理工具
apt update 更新源中的软件包
apt install xxx 安装指定的软件xxx
apt remove xxx 卸载软件(仅仅卸载软件)
apt autoremove xxx 卸载软件(会卸载软件和没有用的依赖包)
安装virtualenv
sudo apt install virtualenv
统一管理虚拟环境virtualenvwrapper
sudo pip install virtualenvwrapper
virtualenvwrapper.sh安装路径
/usr/local/bin/
修改环境变量
sudo vim ~/.bashrc
打开bashrc之后 编辑
#python
export WORKON_HOME = /home/xxx(用户名字)/.virtualenvs
注意需要创建.virtualenv的文件夹 mkdir .virtualenv
source xxx virtualenvwrapper.sh 激活路径
激活更新后的环境变量
source .bashrc
创建虚拟环境
mkvirtualenv ENV_NAME名字
退出虚拟环境
deactivate
进入虚拟环境
workon ENV_NAME
查看虚拟环境
workon
创建3.x的虚拟环境
mkvirtualenv xxx -p /usr/bin/python3
pip python专用的包管理工具
pip install xxx 安装某一个软件
pip uninstall xxx 卸载某一个软件
pip list 列出所有的依赖包
pip freeze 列出自己安装的所有的依赖包
虚拟环境迁移
pip freeze > requirements.txt #迁移脚本requirements.txt保存的位置为当前目录
pip install -r requirements.txt
重量级框架:为了方便业务程序的开发,提供了丰富的工具及其组件
轻量级框架:只提供web核心功能,自由灵活,高度定制
http://flask.pocoo.org/docs/0.12/
http://docs.jinkan.org/docs/flask/
flask依赖三个库
jinja2 模板引擎
Werkzeug WSGI 工具集
Itsdangerous 基于Django的签名模块
现在不仅仅是三个 但是依然前两个有用
安装时候会出现5个 看看就可以了
1 有非常齐全的官方文档,上手非常方便
2 有非常好的扩展机制和第三方扩展环境,工作中常见的软件都会有对应的扩展,自动动手实现扩展
也很容易
3 社区活跃度非常高 flask的热度已经超过django好几百了
4 微型框架的形式给了开发者更大的选择空间
"""
request:- 请求的所有信息
session:- 服务端会话技术的接口
config:
当前项目的配置信息
模板中可以直接使用
在python代码中
· current_app.config
当前运行的app
使用记得是在初始化完成之后
用在函数中
g:global、全局、可以帮助开发者实现跨函数传递数据、引入变量作用域
函数内部变量作用域:
局部变量
全局变量:g.变量名
线程中的变量:1、本地线程存储ThreadLocal 2、使用线程的名字作为key、变量值为value
"""
#views.py
from flask import g
@blue.route('/dage/')
def dage():
print(g.ip)
print('大哥大哥你好吗')
return '123'
@blue.before_request
def dasao():
#下面这个ip如何传到dage这个方法中 g.xxx代表全局变量
g.ip = request.remote_addr
print('大嫂大嫂你好吗')
static和templates默认是与app = Flask(name)在同一文件夹下查找:
#核心代码
#settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
#BASE_DIR=E:\python_django\Flask_Project\Debugtoolber_flask(也就是工程根目录)
#__init__.py
templates_folder = os.path.join(settings.BASE_DIR, 'templates')
static_folder = os.path.join(settings.BASE_DIR,'static')
app = Flask(__name__,template_folder=templates_folder,static_folder=static_folder)
衍生:
#在工程更目录中:E:\python_django\Flask_Project\Debugtoolber_flask:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
#BASE_DIR = E:\python_django\Flask_Project\Debugtoolber_flask
BASE_DIR = os.path.abspath(__file__)#变量所在的.py 文件路径 + .py文件
#BASE_DIR = E:\python_django\Flask_Project\Debugtoolber_flask\Apps\settings.py
BASE_DIR = os.path.dirname(__file__)#变量所在的.py 文件路径
#BASE_DIR = E:/python_django/Flask_Project/Debugtoolber_flask/Apps
一种软件设计架构风范:
Model:数据的封装,数据的抽象,用来操作数据的入口
View:视图,主要用来呈现给用户的
Controller:控制器,主要用来接收用户请求(输入),并且协调模型和视图
核心理念:解耦
实现结果:将数据操作,页面展示,逻辑处理进行了拆分
Models:封装数据操作、数据库的表和字段的定义
Template:模板、用来展示数据
Views:视图函数、相当于controller、接收请求,协调模型和模板
1. 宏伟蓝图(宏观规划)
2. 蓝图也是一种规划,主要用来规划urls(路由)
3. 蓝图基本使用
- 安装 pip install flask-blueprint
- 创建、初始化蓝图 blue = Blueprint('first',__name__)
- 调用蓝图进行路由注册 app.register_blueprint(blueprint=blue)
#views.py
from flask import Blueprint
blue=Blueprint('blue',__name__)
def init_blue(app):
app.register_blueprint(blueprint=blue)
@blue.route('/')
def index():
return '欢迎来到德莱联盟'
客户端请求、Flask根据用户请求自动创建的对象、request是一个内置对象
method :请求方法
base_url :去掉get参数的url
host_url :只有主机和端口号的url
url :完整的请求地址
remote_addr :请求的客户端地址
args :1. args
- get请求参数的包装,args是一个ImmutableMultiDict对象,类字典结构对象
- 数据存储也是key-value
- 外层是大列表,列表中的元素是元组,元组中左边是key,右边是value
form :
2. form
- 存储结构个args一致
- 默认是接收post参数
- 还可以接收 PUT,PATCH参数
files :文件上传
headers :请求头
path :路由中的路径
cookies :请求中的cookie
session :与request类似 也是一个内置对象 可以直接打印 print(session)
创建Response对象方式
返回字符串 :如果只有字符串,就是返回内容,数据、还有第二个返回,放的是状态码
render_template :渲染模板、将模板变成字符串
@blue.route('/rendertemplate/')
def render_temp():
resp = render_template('Response.html')
print(resp)
print(type(resp))
return resp,500
make_response :Response对象、返回内容、状态码
@blue.route('/makeresponse/')
def make_resp():
resp = make_response('xxxxxxxx
',502)
print(resp)
print(type(resp))
return resp
redirect :重定向 return redirect('/makeresponse/')
反向解析 return redirect(url_for('first.make_resp'))
abort
直接抛出 显示错误状态码 终止程序运行、abort(404)
@blue.route('/makeabort/')
def make_abort():
abort(404/502)
return '天还行'
捕获
@blue.errorhandler():- 异常捕获、可以根据状态或 Exception进行捕获、- 函数中要包含一个参数,参数用来接收异常信息
@blue.errorhandler(502)
def handler502(exception):
return '不能让你看到状态码'
客户端会话技术、所有数据存储在客户端、以key-value进行数据存储层、服务器不做任何存储cookie是服务器操作客户端的数据、通过Response进行操作
特性:
支持过期时间 :max_age expries
根据域名进行cookie存储
不能跨网站(域名)
不能跨浏览器
自动携带本网站的所有cookie
首先创建Response对象方式、才能操作cookie的创建以及删除,而获取cookie属于客户端请求,使用request
设置cookie Response.set_cookie('username',username)
获取cookie username = request.cookies.get('username','游客')
删除cookie Response.delete_cookie('username')
#核心代码
#views.py
"""
cookie的登录和登出逻辑,重点理解response(服务器)和request(客户端)的区别:
通过重定向创建response对象
通过response对象来设置cookis
返回response对象
"""
cookies = Blueprint('dage',__name__)
@cookies.route('/toLogin_C/')
def toLogin():
return render_template('login_C.html')
@cookies.route('/login_C/',methods=['post','get'])
def login():
name = request.form.get('name')
response = redirect(url_for('dage.index'))#通过重定向创建response对象
response.set_cookie('name',name)#通过response对象来设置cookis
return response
@cookies.route('/index_C/')
def index():
name = request.cookies.get('name','游客')
res = render_template('index_C.html',name = name)
return res
@cookies.route('/logout_C/')
def logout():
response = redirect(url_for('dage.index'))
response.delete_cookie('name')
return response
服务端会话技术、所有数据存储在服务器中、默认存在服务器的内存中- django默认做了数据持久化(存在了数据库中)、存储结构也是key-value形势,键值对、将数据的唯一标识存储在cookie中
设置session session['username'] = username
获取session session.get('username')
删除session Response.delete_cookie('session') / session.pop('username')
【注】单纯的使用session是会报错的,需要使用在init方法中配置app.config[‘SECRET_KEY’]=‘110’
#views.py(和cookie类似,但比cookie简单,无需创建重定向对象,直接使用session)
rediss=Blueprint('rediss',__name__)
@rediss.route('/ses/')
def ses():
session['user']='wangdana'
return '成功'
django中做了持久化,存储在数据库中,可以修改到redis中
flask中没有对默认session**(服务端会话技术)**进行任何处理、默认存在内存中、flask-session 可以实现session的数据持久化、Session需要持久化到Redis中、缓存在磁盘上的时候,管理磁盘文件使用lru, 最近最少使用
安装插件flask-session : pip install flask-session
--在国内源安装:pip install flask-sessin -i https://pipy.douban.com/simple
配置init中 : app.config['SESSION_TYPE'] = 'redis'
初始化 : 1 Session(app=app)
2 session = Session() session.init_app(app = app)
需要配置SECRET_KEY : app.config['SECRET_KEY'] = '123' # 解决秘钥问题
其他配置--视情况而定 : app.config['SESSION_KEY_PREFIX']='flask'
app.config['SESSION_COOKIE_SECURE']=True
"""核心代码"""
#ext.py
def init_ext(app):
# flask-Session的持久化利用redis
app.config['SESSION_TYPE'] = 'redis' # 将数据保存到哪个数据库
app.config['SECRET_KEY'] = '123' # 解决秘钥问题
Session(app=app) # 初始化、必须放在上面之后
#views.py
@blue.route("/session/", methods=["GET", "POST"])
def user():
if request.method == "GET":
# username = session.get("username",'游客')
return render_template("UserLogin.html")
else:
username = request.form.get("username")
session["username"] = username
return redirect(url_for('blue.user'))
@blue.route('/sessionout/')
def userout():
session.pop('username')
return redirect(url_for('blue.user'))
#UserLogin.html(在页面中直接地调用。无需传参)
欢迎您!{
{
session.get("username",'游客') }} <a href="{
{ url_for('blue.user') }}">退出</a>
windows中的redis安装与 启动:
(json_flask) E:\软件包\Redis-x64-3.2.100>redis-server.exe redis.windows.conf
1 2 3
在未将redis未加到windows的服务时,以上不能关闭。
(json_flask) E:\软件包\Redis-x64-3.2.100>redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
常用的redis服务命令
必须在虚拟环境下,安装此目录的地方执行以下方法,不然显示redis不是windows命令
卸载服务:redis-server --service-uninstall
开启服务:redis-server --service-start
停止服务:redis-server --service-stop
MVC中的View,MTV中的Template
主要用来做数据展示的、模板处理过程分为2个阶段(1 加载、2 渲染)
本质上是html
支持特定的模板语法
flask作者开发的 一个现代化设计和友好的python模板语言 模仿的django的模板引擎
优点
HTML设计和后端Python分离
减少Python复杂度
非常灵活,快速和安全
提供了控制,继承等高级功能
#base.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{
{ title }}title>
<script src="http://libs.baidu.com/jquery/1.9.1/jquery.min.js">script>
{% block extCSS %}
{% endblock %}
head>
<body>
{% block header %}
{% endblock %}
{% block content %}
{% endblock %}
{% block footer %}
{% endblock %}
{% block extJS %}
{% endblock %}
body>
html>
#base_main.html
{% extends 'base.html' %}
{% block extCSS %}
{#在Django中加载静态资源{% static '' %} url_for("static", filename=xxx) #}
{% endblock %}
{% block header %}
小伙子你又睡着了!
{% endblock %}
index.html
{% extends 'base_main.html' %}
{% block header %}
{
{ super() }}
销量已超200w,国产神车,哈佛H6!
{% endblock %}
{% block content %}
{% include 'index_content.html' %}
{% endblock %}
可以在模板中定义,调用函数、函数还是用来生成html的、外文件中的宏定义调用需要导入include
{#调用函数 同页面调用函数#}
{% macro create_item(goods_id, goods_name) %}
商品id{
{ goods_id }}
商品名字{
{ goods_name }}
{% endmacro %}
{% block content %}
{
{ create_item("110", "手铐") }}
{% endblock %}
{#外文件导入函数#}
{% macro create_user(name) %}
不小心创建了一个用户:{
{ name }}
{% endmacro %}
{% from 'mmm.html' import create_user %}
{
{ create_user("翠花") }}
形式:{ { var|xxx|yyy|zzz }}(五个数限制)
{# 字符串操作 #}
{# 当变量未定义时,显示默认字符串,可以缩写为d #}
{
{ name | default('No name', true) }}
{# 单词首字母大写 #}
{
{ 'hello' | capitalize }}
{# 单词全小写 #}
{
{ 'XML' | lower }}
{# 去除字符串前后的空白字符 #}
{
{ ' hello ' | trim }}
{# 字符串反转,返回"olleh" #}
{
{ 'hello' | reverse }}
{# 格式化输出,返回"Number is 2" #}
{
{ '%s is %d' | format("Number", 2) }}
{# 关闭HTML自动转义 #}
{
{ 'name' | safe }}
{% autoescape false %}
{# HTML转义,即使autoescape关了也转义,可以缩写为e #}
{
{ 'name' | escape }}
{% endautoescape %}
{# 数值操作 #}
{# 四舍五入取整,返回13.0 #}
{
{ 12.8888 | round }}
{# 向下截取到小数点后2位,返回12.88 #}
{
{ 12.8888 | round(2, 'floor') }}
{# 绝对值,返回12 #}
{
{ -12 | abs }}
{# 列表操作 #}
{# 取第一个元素 #}
{
{ [1,2,3,4,5] | first }}
{# 取最后一个元素 #}
{
{ [1,2,3,4,5] | last }}
{# 返回列表长度,可以写为count #}
{
{ [1,2,3,4,5] | length }}
{# 列表求和 #}
{
{ [1,2,3,4,5] | sum }}
{# 列表排序,默认为升序 #}
{
{ [3,2,1,5,4] | sort }}
{# 合并为字符串,返回"1 | 2 | 3 | 4 | 5" #}
{
{ [1,2,3,4,5] | join(' | ') }}
{# 列表中所有元素都全大写。这里可以用upper,lower,但capitalize无效 #}
{
{ ['tom','bob','ada'] | upper }}
{# 字典列表操作 #}
{% set users=[{'name':'Tom','gender':'M','age':20},
{'name':'John','gender':'M','age':18},
{'name':'Mary','gender':'F','age':24},
{'name':'Bob','gender':'M','age':31},
{'name':'Lisa','gender':'F','age':19}]
%}
{# 按指定字段排序,这里设reverse为true使其按降序排 #}
{% for user in users | sort(attribute='age', reverse=true) %}
- {
{ user.name }}, {
{ user.age }}
{% endfor %}
{# 列表分组,每组是一个子列表,组名就是分组项的值 #}
{% for group in users|groupby('gender') %}
- {
{ group.grouper }}
{% for user in group.list %}
- {
{ user.name }}
{% endfor %}
{% endfor %}
{# 取字典中的某一项组成列表,再将其连接起来 #}
{
{ users | map(attribute='name') | join(', ') }}
Flask提供了一个内置过滤器”tojson”,它的作用是将变量输出为JSON字符串。这个在配合Javascript使用时非常有用。我们延用上节字典列表操作中定义的”users”变量
注意,这里要避免HTML自动转义,所以加上safe过滤器。
Jinja2还可以对整块的语句使用过滤器。
{% filter upper %} This is a Flask Jinja2 introduction.{% endfilter %}
不过上述这种场景不经常用到。
内置的过滤器不满足需求怎么办?自己写呗。过滤器说白了就是一个函数嘛,我们马上就来写一个。回到Flask应用代码中:
def double_step_filter(l):
return l[::2]
我们定义了一个”double_step_filter”函数,返回输入列表的偶数位元素(第0位,第2位,…)。怎么把它加到模板中当过滤器用呢?Flask应用对象提供了”add_template_filter”方法来帮我们实现。我们加入下面的代码:
app.add_template_filter(double_step_filter, 'double_step')
函数的第一个参数是过滤器函数,第二个参数是过滤器名称。然后,我们就可以愉快地在模板中使用这个叫”double_step”的过滤器了:
{# 返回[1,3,5] #}
{
{ [1,2,3,4,5] | double_step }}
Flask还提供了添加过滤器的装饰器”template_filter”,使用起来更简单。下面的代码就添加了一个取子列表的过滤器。装饰器的参数定义了该过滤器的名称”sub”。
@app.template_filter('sub')
def sub(l, start, end):
return l[start:end]
我们在模板中可以这样使用它:
{# 返回[2,3,4] #}
{
{ [1,2,3,4,5] | sub(1,4) }}
Flask添加过滤器的方法实际上是封装了对Jinja2环境变量的操作。上述添加”sub”过滤器的方法,等同于下面的代码。
app.jinja_env.filters['sub'] = sub
我们在Flask应用中,不建议直接访问Jinja2的环境变量。如果离开Flask环境直接使用Jinja2的话,就可以通过”jinja2.Environment”来获取环境变量,并添加过滤器。
Flask默认并没有提供任何数据库操作的API,Flask中可以自己的选择数据,用原生语句实现功能:
原生SQL缺点
代码利用率低,条件复杂代码语句越过长,有很多相似语句
一些SQL是在业务逻辑中拼出来的,修改需要了解业务逻辑
直接写SQL容易忽视SQL问题
Flask中并没有提供默认ORM,可以选择第三方扩展库,ORM(ORM 对象关系映射,通过操作对象对数据的操作)
SQLAlchemy
MongoEngine
将对对象的操作转换为原生SQL
优点
易用性,可以有效减少重复SQL
性能损耗少
设计灵活,可以轻松实现复杂查询
移植性好
安装sqlalchemy:pip install flask-sqlalchemy
使用 app创建SQLALCHEMY对象:(一般选第二种)
直接传入app:db=SQLAlchemy(app=app)
先创建对象,在使用的时候再进行init_app:
db=SQLAlchemy() 上面这句话一般会放到models中 因为需要db来调用属性 db.init_app(app=app)
config 配置SQLALCHEMY_DATABASE_URI形式:app.config[‘SQLALCHEMY_DATABASE_URI’]=
(1)pymysql:
mysql+pymysql://uname:pad@host:port/database-数据库+驱动://用户:密码@主机:端口/数据库
(2)sqlite:
sqlite:///xxxx(sqlite3.db)
config 配置SQLALCHEMY_TRAKE_MODIFICATIONS,防止未来遇见未知的错误发生:
app.config[‘SQLALCHEMY_TRAKE_MODIFICATIONS’]=False
手动models操作数据库:
views中创建路由执行:db.create_all()将models中模型加载到数据库
@blue.route("/createdb/")
def create_db():
db.create_all()
return "创建成功"
views中创建路由执行:db.drop_all()将删除数据库中models中的模型对应的表
@blue.route("/dropdb/")
def drop_db():
db.drop_all()
return "删除成功"
自动加载models模型使用migrtae第三方库,详情请参考flask-migrate
#models.py
from flask_sqlalchemy import SQLAlchemy
db=SQLAlchemy()#创建models.db对象
class User_info(db.Model):
pass
#init.py
# 选择开发环境以及数据库的选择和配置
app.config.from_object(settings.env.get(ENV_NAME))
# 第三方库的整合
init_ext(app=app)
#setting.py()
"""
开发分为四套环境,对应的数据库也会有差别,分别为
开发环境
测试环境
演示环境-类似线上环境也叫做预生产环境
线上环境 也叫做 生产环境
Flask轻量级框架,在一个setting.py中实现所有功能
"""
def get_db_uri(DATABASE):
dialect=DATABASE.get('dialect') or 'mysql'
mysql=DATABASE.get('mysql') or 'pymysql'
username=DATABASE.get('username') or 'root'
password=DATABASE.get('password') or '123456'
host=DATABASE.get('host') or 'localhost'
port=DATABASE.get('port') or '3306'
db=DATABASE.get('db') or 'Fengzhuang'
return '{}+{}://{}:{}@{}:{}/{}'.format(dialect,mysql,username,password,host,port,db)
class Config():
TEST = False
SQLALCHEMY_TRACK_MODIFICATIONS=False
class DevelopeConfig(Config):
DEBUG = True
DATABASE = {
'dialect': 'mysql',
'mysql': 'pymysql',
'username': 'root',
'password': '123456',
'host': 'localhost',
'port': '3306',
'db': 'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI = get_db_uri(DATABASE)
class TestConfig(Config):
TEST=True
DATABASE={
'dialect':'mysql',
'mysql':'pymysql',
'username':'root',
'password':'123456',
'host':'localhost',
'port':'3306',
'db':'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI=get_db_uri(DATABASE)
class ShowConfig(Config):
DEBUG = True
DATABASE = {
'dialect': 'mysql',
'mysql': 'pymysql',
'username': 'root',
'password': '123456',
'host': 'localhost',
'port': '3306',
'db': 'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI = get_db_uri(DATABASE)
class ProductConfig(Config):
DEBUG = True
DATABASE = {
'dialect': 'mysql',
'mysql': 'pymysql',
'username': 'root',
'password': '123456',
'host': 'localhost',
'port': '3306',
'db': 'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI = get_db_uri(DATABASE)
env={
'develop':DevelopeConfig,
'test':TestConfig,
'show':ShowConfig,
'product':ProductConfig,
}
#ext.py
# 数据模型的初始化(放在最后)
db.init_app(app=app)
#views.py
@blue.route("/addstudent/")
def add_student():#添加数据
s = Student()
s.s_name = "小明%d" % random.randrange(1000)
s.s_age = random.randrange(70)
# 数据操作
db.session.add(s)#添加对象
db.session.commit()#提交数据
return "添加成功"
@blue.route("/getstudents/")#查询数据并显示到界面
def get_students():
students = Student.query.all()
return render_template("StudentList.html", students=students)
#StudentList.html页面显示数据
{
% for student in students %}
<li>{
{
student.s_name }}</li>
{
% endfor %}
可以在命令行中将models和数据库进行映射,操作分为初始化、加载、升级、降级
安装 :pip install flask-migrate
初始化:
创建migrate对象:migrate = Migrate()
需要在ext.py中使用app和db初始化:migrate.init_app(app=app, db=db)
懒加载初始化,结合flask-script使用
在manager,py中:manager.add_command("db", MigrateCommand)
python manager.py db xxx(命令行操作):
python manager.py db init #第一次使用,初始化
python manager.py db migrate #生成迁移文件
python manager.py db upgrade #将模型映射到数据库表(也就是建表以及完成映射过程)
python manager.py db downgrade #删除数据库中与models映射的模型对应的表
#python manager.py db migrate 无法生成迁移文件有一下两种情况:
模型定义完成从未调用(在视图文件中调用)
数据库已经有模型记录(数据库存在表,尤其是迁移产生的非映射表)
创建用户文件:python manager.py db migrate --message ‘创建用户’
#ext.py(创建migtare对象,由于没有其他地方调用,所以放在函数内部,在db初始化的上面)
def init_ext(app):
# 创建迁移对象以及迁移数据的初始化
migrate=Migrate()
migrate.init_app(app=app,db=db)
#manager.py
manager.add_command("db", MigrateCommand)
插件安装:pip install flask-bootstrap
ext中初始化:Bootstrap(app=app)
给我们内置了基模板,模板中提前挖好了block bootstrap中的base.html
head
head
metas
style
head
body
body_attribs
body
navbar 导航
content 内容
scripts js
body
body
填坑 index.html
#ext.py
Bootstrap(app=app)
#htmlye页面继承
{
% extends 'bootstrap/base.html' %}
#然后填补基模板的坑
bootstrap中文网
反色导航栏:反色inverse
巨幕
辅助调试插件
安装:pip install flask-debugtoolbar
初始化 ext:
debugtoolbar = DebugToolBarExtension()
debugtoolbar.init_app(app=app)
只需要初始化就ok了
解释:
在所有模板中会自动加载、就是在页面的body上动态插入监测模块,可监测功能:
flask版本
路由器
性能
数据库
项目配置信息
#ext.py(初始化)
debugtoolbar = DebugToolbarExtension()
debugtoolbar.init_app(app=app)
然后访问网页就会在右侧出现选项栏,查查看各种数据
缓存目的:缓存优化加载,减少数据库的IO操作
实现方案:数据库、文件、内存、内存中的数据库 Redis
实现流程:
从路由函数进入程序
路由函数到视图函数
视图函数去缓存中查找
缓存中找到,直接进行数据返回
如果没找到,去数据库中查找
查找到之后,添加到缓存中
返回到页面上
安装 :pip install flask-cache
初始化:
cache = Cache(config={
'CACHE_TYPE':默认是simple})#指定使用的缓存方案
使用 在路由的下面添加@cache.cached(timeout=30)
要配置config:TYPE、还可以配置各种缓存的配置信息
cache=Cache(config={
'CACHE_KEY_PREFIX':'python'})
用法
装饰器:@cache.cached(timeout=xxx)
原生实现缓存目的
@blue.route("/user/")
def user():
addr = request.remote_addr
key = addr + "user"
print("从全局变量中获取", g.id)#g是的id在部分中是全局的变量
# current_app
print(current_app.config)
result = cache.get(key)
if result:
print(addr, "从缓存中加载数据")
return result
result = render_template("User.html")
print(addr, "从数据库加载数据")
cache.set(key, result, timeout=30)
return result
#ext.py
from flask_cache import Cache
# 创建缓存对象
cache=Cache(config={
'CACHE_TYPE':'simple'})
def init_ext(app):
# 缓存的初始化
cache.init_app(app=app)
"""
当运行服务器的时候 会报错from flask.ext.cache import make_template_fragment_key
ImportError: No module named 'flask.ext'
解决方法 修改(External Libraries)-(flask_json)-(site-packages)-( flask-cache ) -jinja2ext.py中的flaks.ext.cache为flask_cache
"""
#views.py
from Apps.ext import cache
@blue.route('/index/')
@cache.cached(timeout=30)#装饰器,30秒内都是通过缓存,超过30秒将会执行路由指定的函数
def index():
print("加载完成")
return render_template('index.html')
"""
主要实现思想是:当用户访问请求后,将获取访问请求主机的IP,通过拼接key= request.remote_addr + 'user',value=访问次数,然后将保存在缓存中,设置缓存有效时间,当用户再次来访问时,将更新value的数值,当在缓存有效时间内,访问次数达到设定的值(在缓存有效时间内最大访问的次数),将禁止该ip用户的访问。
"""
@blue.route('/getcache/')
def getcache():
#获取请求的主机 也就是ip
key = request.remote_addr + 'user'
#查看缓存中有没有ip
value = cache.get(key)
if value:
return '先别访问了 我大哥来了'
cache.set(key,'呵呵大',timeout=20)
return '欢迎再来'
介绍:
在Restful之前的操作:
saveUser
http://127.0.0.1/user/query/1 GET 根据用户id查询用户数据
http://127.0.0.1/user/save POST 新增用户
http://127.0.0.1/user/update POST 修改用户信息
http://127.0.0.1/user/delete GET/POST 删除用户信息
RESTful用法:根据请求提交方式的不同 然后执行对应的方法
http://127.0.0.1/user/1 GET 根据用户id查询用户数据
http://127.0.0.1/user POST 新增用户
http://127.0.0.1/user PUT 修改用户信息
http://127.0.0.1/user DELETE 删除用户信息
if request.method == 'get':
User.query.first()
else request.method == 'post':
之前的操作是没有问题的,大神认为是有问题的,有什么问题呢?
你每次请求的接口或者地址,都在做描述,例如查询的时候用了query,
新增的时候用了save,其实完全没有这个必要,我使用了get请求,就是查询.
使用post请求,就是新增的请求,我的意图很明显,完全没有必要做描述,
这就是为什么有了restful.
ajax其实质利用浏览器内置ajax对象(xmlhttprequest xhr)
异步的向服务器发送请求
提交的是部分数据
利用返回的数据更新当前页面
整个过程中
页面无刷新
不打断用户的操作
#视图函数中的借助蓝图,用原生代码实现前后端分离的思想
@blue.route('/user/',methods=['GET','POST','PUT','DELETE'])
def user():
if request.method == 'GET':
#一般返回的变量的名字都是data
data = {
'message':'ok',
'status':'200',
}
return jsonify(data)
elif request.method == 'POST':
data = {
'message': 'ok',
'status': '200',
}
return jsonify(data),500
elif request.method == 'PUT':
data = {
'message': 'ok',
'status': '200',
}
return jsonify(data)
elif request.method == 'DELETE':
data = {
'message': 'ok',
'status': '200',
}
return jsonify(data)
else:
abort(405)
'''
思路大致:就是判断不同的请求方式,实现请求方法、高内聚,低耦合、高内聚、相同的数据操作封装在一起、低耦合、MVC 没有模板--前后端分离、jsonify(json序列化)
添加到数据库
get
{
'msg':'ok',
'status':'200'
'user':users
}
'''
@blue.route('/user1/',methods=['GET','POST','PUT','DELETE','PATCH'])
def user1():
#坑点 直接返回一个对象或者一个列表是不可以序列化的 所以为们需要自己构造
#在模型中添加一个todict方法 然后让每一个对象都变成字典格式
if request.method == 'GET':
page = int(request.args.get('page',1))
per_page = int(request.args.get('per_page',3))
users = User.query.paginate(page=page,per_page=per_page,error_out=False).items
users_dict = []
for user in users:
user_dict = user.to_dict()
users_dict.append(user_dict)
data = {
'msg':'ok',
'status':'200',
'users':users_dict,
}
return jsonify(data)
elif request.method == 'POST':
name = request.form.get('name')
password = request.form.get('password')
#1 有没有空格 2 是不是空
name = name.strip()
data = {
'msg':'ok',
'status':'200',
}
if not name or not password:
data['status'] = 422
return jsonify(data)
#注意密码长度问题
password = generate_password(password)
print(password)
user = User()
user.name = name
user.password = password
try:
db.session.add(user)
db.session.commit()
except Exception as e:
data['msg'] = str(e)
return jsonify(data)
return jsonify(data)
elif request.method == 'DELETE':
data = {
'msg': 'delete success',
'status': '204'
}
#从请求资源路径中获取id
id = request.args.get('id')
#查询id对应的user对象
user = User.query.get(id)
if user:
db.session.delete(user)
db.session.commit()
return jsonify(data)
else:
data['msg'] = '没有这个对象 你不能删除'
return jsonify(data)
elif request.method == 'PUT':
data = {
'msg': 'update success',
'status': '201'
}
name = request.form.get('name')
password = request.form.get('password')
id = request.args.get('id')
# 查询id对应的user对象
user = User.query.get(id)
user.name = name
user.password = generate_password(password)
db.session.add(user)
db.session.commit()
return jsonify(data)
elif request.method == 'PATCH':
data = {
'msg': 'update success',
'status': '201'
}
name = request.form.get('name')
id = request.args.get('id')
# 查询id对应的user对象
user = User.query.get(id)
user.name = name
db.session.add(user)
db.session.commit()
return jsonify(data)
#实现对于密码的加密,MD5,密码不可逆,只能使用网页MD5解密(准确称之为爆破)
def generate_password(password):
hash = hashlib.md5()
hash.update(password.encode("utf-8"))
return hash.hexdigest()
#models.py模型里的方法
def to_dict(self):
return {
"u_name": self.u_name, 'u_password': self.u_password}
整合网络和软件的一种架构模式、
理解:
Representtational:表现层
State Transfer:状态转换
表现层状态转换:资源(Resource)
每一个URI代表一类资源:对整个数据的操作、增删改查
RESTful中更推荐使用HTTP的请求谓词(动词)来作为动作标识(GET、POST、PUT、PATCH、DELETE)
状态码:
服务器向用户返回的状态码和提示信息,常见的有以下一些地方
200 OK - [GET]:服务器成功返回用户请求的数据
201 CREATED -[POST/PUT/PATCH]:用户新建或修改数据成功
202 Accepted - [*] :表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:表示数据删除成功
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误
401 Unauthorized - [*] :表示用户没有权限(令牌,用户名,密码错误)
403 Forbidden - [*]:表示用户得到授权,但是访问是被禁止的
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录
406 Not Acceptable - [*]:用户请求格式不可得
410 Gone - [GET] :用户请求的资源被永久移除,且不会再得到的
422 Unprocesable entity -[POST/PUT/PATCH]:当创建一个对象时,发生一个验证错误,登陆的时候 如果没有获取到用户名 或者 密码
500 INTERNAL SERVER EROR - [*] :服务器内部发生错误
推荐使用json数据传输
设计原则:
http(s)协议
应该有自己专属域名:在应用上添加一个api前缀
都是名词,复数形式
可以将版本号设计进去:增量操作
/collection/id/:? id=xxx
#安装 pip install flask-restful
#初始化:urls---在init中调用init_urls(也就是第三方库初始化和关联,在ext.py中)
api = Api()
api.add_resource(Hello1, "/hello2/")#Hello1是一个类的名字 hello2是路由
api.init_app(app=app)
#在apis.py中编写类hello1:
class Hello(Resource):#继承自Resource
def get(self):#实现请求方法对应函数GET==get,一一对应
return {
"msg": "ok"}
def post(self):
return {
"msg": "create success"}
#ext.py的方法中
api = Api()
#第一个参数是我们要操作的类
#为什么为把Hello1写在了api中呢?因为增删该查都是在api中执行的
api.add_resource(Hellos, '/hellos/')
api.init_app(app=app)
#apis.py(通过不同请求实现区别)
from flask.json import jsonify
from flask_restful import Resource
from App.models import Hello
class Hellos(Resource):
def get(self):
data={
'msg' : '我是get',
}
json=jsonify(data)
return json
就是在得到客户请求之后,对数据库操作之后得到的对象无法满足返回数据的要求,所以要对返回数据的形式做了规定,如下面的cat_fields 做出的规定只能有三个键,分别为 “msg”、“status”、 “data”,如果还有其他的键,他的键值将不会在客户端显示数据,只会显示 “msg”、“status”、 “data”。而 “msg”、“status”、 "data"其对应的值只能为字符串类型,其他类型将返回字符串默认值。
其他类型:String、Integer、Nested、List(前两种用的比较多)
类型括号中还允许添加约束:
attribute:指定连接对应名字:attribute=名字
default:设置默认值(default=404),参数不满足其约束时,将返回默认值
cat_fields = {
"msg": fields.String,
"status": fields.String
"data": fields.String
}
class CatResource(Resource):
@marshal_with(cat_fields) #重点,装饰器
def get(self):
data={
"msg": "呵呵呵",
"data": "没有数据",
"language": "En",
"private_data": "表中的字段内容"
}
return data
处理数据库返回对象:
#处理返回单条数据的对象
c_fields = {
'id':fields.Integer,
'name':fields.String,
'age':fields.Integer
}
cats_fields = {
'msg':fields.String,
'status':fields.String,
'cat':fields.Nested(c_fields)#Nested:嵌套的意思
}
class Cats(Resource):
#获取所有的猫 查询的是单个对象
@marshal_with(cats_fields)
def get(self):
cat = Cat.query.first()
data = {
'msg':'ok',
'status':'200',
'cat':cat,
}
#如果已经是json数据格式了 那么就不需要jsonify方法了
return data
#处理返回多条返回数据的对象
c_fields = {
'id':fields.Integer,
'name':fields.String,
'age':fields.Integer
}
cats_fields = {
'msg':fields.String,
'status':fields.String,
'cat':fields.list(filter.Nested(c_fields))
}
class Cats(Resource):
#获取所有的猫 查询的是单个对象
@marshal_with(cats_fields)
def get(self):
catss = Cat.query.all()
data = {
'msg':'ok',
'status':'200',
'cat':catss,
}
#如果已经是json数据格式了 那么就不需要jsonify方法了
return data
在对象中添加字段:parser.add_argument(‘id’,type=int,required=True,help=‘id你必须写一下’)
有以下约束条件:
add_argument中通过指定参数名、参数类型、参数获取方式来获取参数对象并支持做合法性校验
第一个参数是需要获取的参数的名称
参数type: 参数指的类型, 如果参数中可能包含中文需要使用six.text_type. 或直接不指定type
参数location: 获取参数的方式,可选的有args(url中获取)、json(json类型的)、form(表单方式提交)
参数required:是否必要,默认非必要提供
参数help:针对必要的参数,如果请求时没有提供,则会返回help中相应的信息
action:action=append、c_name=tom&c_name=zs
如果你要接受一个键有多个值的话,你可以传入 action='append'
parser.add_argument('name', type=str, action='append')
这将让你做出这样的查询
curl http://api.example.com -d "Name=bob" -d "Name=sue" -d "Name=joe"
你的参数将会像这样
args = parser.parse_args()
args['name'] # ['bob', 'sue', 'joe']
#apis.py
#获取一个parser对象
parser = reqparse.RequestParser()
#将参数存储到parser对象上 parser对象中包含了所有的请求参数
parser.add_argument('id',type=int,required=True,help='id你必须写一下')
parser.add_argument('name',type=str)
#将所有的参数都方到了parse对象上
class CatThree(Resource):
@marshal_with(cats_fields)
def get(self):
parse = parser.parse_args()
id = parse.get('id')
cat = Cat.query.get(id)
data = {
'msg':'ok',
'status':'200',
'cat':cat
}
return data
继承:
copy
可以对已有字段进行删除和更新
继承解析
在整个项目中,通用字段可以创建一个基parser
复用已有的部分参数转换数据结构
继承解析
往往你会为你编写的每个资源编写不同的解析器。这样做的问题就是如果解析器具有共同的参数。不是重写,你可以编写一个包含所有共享参数的父解析器接着使用 copy() 扩充它。你也可以使用 replace_argument() 覆盖父级的任何参数,或者使用 remove_argument() 完全删除参数。 例如:
from flask.ext.restful import RequestParser
parser = RequestParser()
parser.add_argument('foo', type=int)
parser_copy = parser.copy()
parser_copy.add_argument('bar', type=int)
# parser_copy has both 'foo' and 'bar'
#parser_copy.replace_argument("")#覆盖父级的任何参数
parser_copy.replace_argument('foo', type=str, required=True, location='json')
# 'foo' is now a required str located in json, not an int as defined
# by original parser
parser_copy.remove_argument('foo')#完全删除name="foo"这个参数
# parser_copy no longer has 'foo' argument
before_first_request:在对应用程序实例的第一个请求之前注册要运行的函数, 只会执行一次
before_request:在每个请求之前注册一个要运行的函数, 每一次请求都会执行
after_request:在每个请求之后注册一个要运行的函数, 每次请求都会执行. 需要接收一个 Response 类的对象 作为参数 并返回一个新的Response 对象 或者 直接返回接受到的Response 对象
teardown_request:注册一个函数在每个请求的末尾运行,不管是否有异常, 每次请求的最后都会执行.
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wXQNyYLA-1592465098991)(C:\Users\Administrator\Desktop\python第四阶段\images\钩子执行顺序.png)]
#__init__.py(在封装中可以这么使用)
#views.py中的init_blue()函数中使用
#两个作用范围是所有的蓝图之前或者之后
# 钩子函数 before_first_request
@app.before_first_request
def before_first():
print("app.before_first")
# 钩子函数 before_request
@app.before_request
def before():
print("app.before")
# 钩子函数 after_request
@app.after_request
def after(response):
print("app.after")
return response
# 钩子函数 teardown_request
@app.teardown_request
def teardown(e):
print("app.teardown")
#在视图函数中通过蓝图对象实现以上功能
# 钩子函数 before_app_first_request(只执行第一次请求,以后的请求不再执行)
@blue.before_app_first_request
def before_first2():
print("app.before_app_first_request")
# 钩子函数 before_app_request
@blue.before_app_request
def before_first1():
print("app.before_app_request")
# 钩子函数 after_app_request
@blue.after_app_request
def before_first3(response):
print("app.after_app_request")
#response=redirect(url_for('blue.dage'))
return response
# 钩子函数 teardown_app_request
@blue.teardown_app_request
def before_first4(e):
print("app.teardown_app_request")
"""
实现现在当其他蓝图对象的路由接收到用户请求时候,不会执行钩子
只有blue蓝图对象的路由接收到用户请求时候,执行钩子
"""
# 钩子函数 before_first_request
@blue.before_request
def before_first1():
print("app.before_app_request")
# 钩子函数 before_first_request
@blue.after_request
def before_first3(response):
print("app.after_app_request")
#response=redirect(url_for('blue.dage'))
return response
# 钩子函数 teardown_request
@blue.teardown_request
def before_first4(e):
print("app.teardown_request")
安装 :pip install flask-mail
初始化:
创建mail对象:mail = Mail()
需要在ext.py中使用app初始化:main.init_app(app=app)
邮箱密码设置
163客户端授权密码 设置 pop3 点击 设置POP3/SMTP/IMAP: 选中多选框
配置信息API 进行配置:
MAIL_SERVER='smtp.163.com'
MAIL_USERNAME="你的邮箱163"
MAIN_PASSWORD="客户端授权密码"
#ext.py
mail=Mail()
def init_ext(app):
#邮件信息初始化
mail.init_app(app)
#163客户端授权密码 设置 pop3 点击 设置POP3/SMTP/IMAP: 选中多选框
#settings.py
MAIL_SERVER = 'smtp.163.com'
MAIL_USERNAME = '[email protected]'
MAIL_PASSWORD = 'yuheng19950619'#客户端授权密码
#mailApi.py
class MailResource(Resource):
def get(self):
msg = Message(subject='激活',sender="[email protected]",recipients=["[email protected]"])
#msg.body = ' i an yuheng'
indexHtml=render_template('index.html',name='游客',url='www.baidu.com')
msg.html = indexHtml
mail.send(msg)
return 'ok'
#index.html(全部代码)
<body>
<h3>尊敬的用户:{
{
name }}</h3>
<p>
<span>欢迎您注册本网站,请点击链接实现用户激活,可以享受更多权益!</span>
</p>
<a href={
{
url }}>激活</a>
<p>如果上面链接不可点击,请复制下面的内容到浏览器中激活</p>
<p>{
{
url }}</p>
</body>
微信转账
钱包 减钱 等待2小时 账户 加钱
减钱是一个请求 然后我们收到了响应(2小时候内到账)
跨行转账
抢票
使用步骤
1 安装 pip install celery
2 导入 from celery import Celery
3 初始化 app = Celery('文件名',broker=‘redis://localhost:6379’)
4 @app.task 注意 没有()
5 :def add(a, b):
6 调用方法的时候需要使用方法的名字。delay(参数)
eg:add.delay(3,5)
7 celery -A 文件名 worker --loglevel = info
8 运行
HelloCelery.py
#在虚拟环境中执行celery -A HelloCelery worker --loglevel = info
#然后单独执行daHelloCelery.py,会产生效果
import time
from celery import Celery
app=Celery('HelloCelery',broker='redis://127.0.0.1:6379')
@app.task
def add(a):
time.sleep(14)
print(a)
if __name__=='__main__':
a=add.delay(4,4)
print("程序完成")
配合flask使用,当添加celery -A HelloCelery worker --loglevel = info以后,可直接运行,做些操作,类似于转账行为:
from flask import Flask
from HelloCelery import add
app = Flask(__name__)
@app.route('/')
def hello():
add.delay('[email protected]')
return '邮件2小时发送给您'
if __name__ == '__main__':
app.run(port=8001)
https://blog.csdn.net/qq_30242609/article/details/79047660
使用步骤
1 安装 pip install celery、pip install eventlet
2 导入 from celery import Celery
3 初始化 app = Celery('文件名',broker=‘redis://localhost:6379’)
4 @app.task 注意 没有()
5 :def add(a, b):
6 调用方法的时候需要使用方法的名字。delay(参数)
eg:add.delay(3,5)
7 celery -A 文件名 worker --loglevel = info
8 运行
HelloCelery.py
#在虚拟环境中执行celery -A HelloCelery worker -l info -P eventlet
#然后单独执行HelloCelery.py,会产生效果
import time
from celery import Celery
app=Celery('HelloCelery',broker='redis://127.0.0.1:6379')
@app.task
def add(a):
time.sleep(14)
print(a)
if __name__=='__main__':
a=add.delay(4,4)
print("程序完成")
配合flask使用,当添加celery -A HelloCelery worker -l info -P eventlet以后,可直接运行,做些操作,类似于转账行为:
from flask import Flask
from HelloCelery import add
app = Flask(__name__)
@app.route('/')
def hello():
add.delay('[email protected]')
return '邮件2小时发送给您'
if __name__ == '__main__':
app.run(port=8001)
目录样式
USER(项目名)
——static
——template
——app.py
app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "Hello"
app.run()
#在启动的时候可以添加参数 在run()中
debug:-d 是否开启调试模式,开启后修改过python代码自动重启
host:-h 主机,默认是127.0.0.1 指定为0.0.0.0代表本机ip
port0:-p 指定服务器端口号
threaded:-t 是否开启多线程
================================================================================================================================================================================================================================================================================================================================================================================================================
TemplateFlask
--Apps :
----static :存放静态文件,例如js\css\images
----template :存放模板文件以及html页面
----__init__ :创建Flask对象、加载settings文件、调用init_ext方法、调用init_blue方法
----models.py :定义模型
----ext.py :用来初始化第三方的各种插件、Sqlalchemy对象初始化 数据库、Session初始化
----setting.py :App运行的环境配置、运行环境
----views.py :蓝图、创建、注册到app上
--manager.py :程序入口、app的创建、Manager (flask-script管理对象)、可以接收命令行参数
from flask_migrate import MigrateCommand
from flask_script import Manager
from Apps import create_apps
app = create_apps('develop')
manager=Manager(app=app)
manager.add_command("db", MigrateCommand)
if __name__ == '__main__':
manager.run()
from Apps.views import init_blue
def create_apps(ENV_NAME):
# 创建app对象
app=Flask(__name__)
# 初始化蓝图
init_blue(app=app)
# 选择开发环境以及数据库的选择和配置
app.config.from_object(settings.env.get(ENV_NAME))
# 第三方库的整合
init_ext(app=app)
return app
from flask_migrate import Migrate
from flask_session import Session
from Apps.models import db
def init_ext(app):
# flask-Session的持久化利用redis
Session(app=app) #初始化
app.config['SESSION_TYPE'] = 'redis' # 将数据保存到哪个数据库
app.config['SECRET_KEY'] = '123' # 解决秘钥问题
# 数据模型的初始化
db.init_app(app=app)
# 创建迁移对象以及迁移数据的初始化
migrate=Migrate()
migrate.init_app(app=app,db=db)
from flask_sqlalchemy import SQLAlchemy
db=SQLAlchemy()
class User_info(db.Model):
__tablename__ = "UserInfo" #重命名
id=db.Column(db.Integer,primary_key=True,autoincrement=True)
name=db.Column(db.String(16))
age=db.Column(db.Integer)
telephone=db.Column(db.String(11))
def get_db_uri(DATABASE):
dialect=DATABASE.get('dialect') or 'mysql'
mysql=DATABASE.get('mysql') or 'pymysql'
username=DATABASE.get('username') or 'root'
password=DATABASE.get('password') or '123456'
host=DATABASE.get('host') or 'localhost'
port=DATABASE.get('port') or '3306'
db=DATABASE.get('db') or 'Fengzhuang'
return '{}+{}://{}:{}@{}:{}/{}'.format(dialect,mysql,username,password,host,port,db)
class Config():
TEST = False
SQLALCHEMY_TRACK_MODIFICATIONS=False
class DevelopeConfig(Config):
DEBUG = True
DATABASE = {
'dialect': 'mysql',
'mysql': 'pymysql',
'username': 'root',
'password': '123456',
'host': 'localhost',
'port': '3306',
'db': 'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI = get_db_uri(DATABASE)
class TestConfig(Config):
TEST=True
DATABASE={
'dialect':'mysql',
'mysql':'pymysql',
'username':'root',
'password':'123456',
'host':'localhost',
'port':'3306',
'db':'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI=get_db_uri(DATABASE)
class ShowConfig(Config):
DEBUG = True
DATABASE = {
'dialect': 'mysql',
'mysql': 'pymysql',
'username': 'root',
'password': '123456',
'host': 'localhost',
'port': '3306',
'db': 'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI = get_db_uri(DATABASE)
class ProductConfig(Config):
DEBUG = True
DATABASE = {
'dialect': 'mysql',
'mysql': 'pymysql',
'username': 'root',
'password': '123456',
'host': 'localhost',
'port': '3306',
'db': 'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI = get_db_uri(DATABASE)
env={
'develop':DevelopeConfig,
'test':TestConfig,
'show':ShowConfig,
'product':ProductConfig,
}
from flask import Blueprint
blue=Blueprint('blue',__name__)#创建蓝图对象,在括号中的‘blue’是蓝图的名字,可以和对象不同。
def init_blue(app):#将蓝图和app进行关联
app.register_blueprint(blueprint=blue)
@blue.route('/')
def index():
return '欢迎来到德莱联盟'
================================================================================================================================================================================================================================================================================================================================================================================================================
TemplateFlask
--Apps :
----static :存放静态文件,例如js\css\images
----template :存放模板文件以及html页面
----__init__ :创建Flask对象、加载settings文件、调用init_ext方法、调用init_blue方法
----models.py :定义模型
----ext.py :用来初始化第三方的各种插件、Sqlalchemy对象初始化 数据库、Session初始化
----setting.py :App运行的环境配置、运行环境、以及数据库相关配置
----apis.py :前后端分离思想实现,用过不同请求方式决定执行对应操作
--manager.py :程序入口、app的创建、Manager (flask-script管理对象)、可以接收命令行参数
from flask_migrate import MigrateCommand
from flask_script import Manager
from Apps import create_apps
app = create_apps('develop')
manager=Manager(app=app)
manager.add_command("db", MigrateCommand)
if __name__ == '__main__':
manager.run()
from Apps.views import init_blue
def create_apps(ENV_NAME):
# 创建app对象
app=Flask(__name__)
# 初始化蓝图
init_blue(app=app)
# 选择开发环境以及数据库的选择和配置
app.config.from_object(settings.env.get(ENV_NAME))
# 第三方库的整合
init_ext(app=app)
return app
from flask_migrate import Migrate
from flask_session import Session
from Apps.models import db
def init_ext(app):
# flask-Session的持久化利用redis
Session(app=app) #初始化
app.config['SESSION_TYPE'] = 'redis' # 将数据保存到哪个数据库
app.config['SECRET_KEY'] = '123' # 解决秘钥问题
# 数据模型的初始化
db.init_app(app=app)
# 创建迁移对象以及迁移数据的初始化
migrate=Migrate()
migrate.init_app(app=app,db=db)
from flask_sqlalchemy import SQLAlchemy
db=SQLAlchemy()
class User_info(db.Model):
__tablename__ = "UserInfo" #重命名
id=db.Column(db.Integer,primary_key=True,autoincrement=True)
name=db.Column(db.String(16))
age=db.Column(db.Integer)
telephone=db.Column(db.String(11))
def get_db_uri(DATABASE):
dialect=DATABASE.get('dialect') or 'mysql'
mysql=DATABASE.get('mysql') or 'pymysql'
username=DATABASE.get('username') or 'root'
password=DATABASE.get('password') or '123456'
host=DATABASE.get('host') or 'localhost'
port=DATABASE.get('port') or '3306'
db=DATABASE.get('db') or 'Fengzhuang'
return '{}+{}://{}:{}@{}:{}/{}'.format(dialect,mysql,username,password,host,port,db)
class Config():
TEST = False
SQLALCHEMY_TRACK_MODIFICATIONS=False
class DevelopeConfig(Config):
DEBUG = True
DATABASE = {
'dialect': 'mysql',
'mysql': 'pymysql',
'username': 'root',
'password': '123456',
'host': 'localhost',
'port': '3306',
'db': 'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI = get_db_uri(DATABASE)
class TestConfig(Config):
TEST=True
DATABASE={
'dialect':'mysql',
'mysql':'pymysql',
'username':'root',
'password':'123456',
'host':'localhost',
'port':'3306',
'db':'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI=get_db_uri(DATABASE)
class ShowConfig(Config):
DEBUG = True
DATABASE = {
'dialect': 'mysql',
'mysql': 'pymysql',
'username': 'root',
'password': '123456',
'host': 'localhost',
'port': '3306',
'db': 'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI = get_db_uri(DATABASE)
class ProductConfig(Config):
DEBUG = True
DATABASE = {
'dialect': 'mysql',
'mysql': 'pymysql',
'username': 'root',
'password': '123456',
'host': 'localhost',
'port': '3306',
'db': 'Fengzhuang',
}
SQLALCHEMY_DATABASE_URI = get_db_uri(DATABASE)
env={
'develop':DevelopeConfig,
'test':TestConfig,
'show':ShowConfig,
'product':ProductConfig,
}
from flask import Blueprint
blue=Blueprint('blue',__name__)#创建蓝图对象,在括号中的‘blue’是蓝图的名字,可以和对象不同。
def init_blue(app):#将蓝图和app进行关联
app.register_blueprint(blueprint=blue)
@blue.route('/')
def index():
return '欢迎来到德莱联盟'
================================================================================================================================================================================================================================================================================================================================================================================================================
步骤:创建对象、放到数据连接的session进行commit
**db.session.add:**单个添加
@blue.route("/addperson/")
def add_person():
p = Person()
p.p_name = "小明"
p.p_age = 15
db.session.add(p)
db.session.commit()
return "添加成功"
**db.session.add_all:**添加多个
@blue.route("/addpersons/")
def app_persons():
persons = []
for i in range(5):
p = Person()
p.p_name = "猴子请来的救兵%d" % random.randrange(100)
p.p_age = random.randrange(70)
persons.append(p)
db.session.add_all(persons)
db.session.commit()
return "添加成功"
通过过滤器进行查询
**获取结果集:**返回为数据的数据类型为结果集(多条数据)
@blue.route("/getpersons/")
def get_persons():
# persons = Person.query.all()
# persons = Person.query.filter(Person.p_age < 18)
# persons = Person.query.filter(Person.p_age.__le__(15))
# persons = Person.query.filter(Person.p_name.startswith("小"))
# persons = Person.query.filter(Person.p_name.endswith("1"))
# persons = Person.query.filter(Person.p_name.contains("1"))
persons = Person.query.filter(Person.p_age.in_([15, 11]))
# persons = Person.query.filter_by(p_age=15)
print(persons)
print(type(persons))
return render_template("PersonList.html", persons=persons)
获取单个数据
@blue.route("/selectperson/")
def delete_person():
# person = Person.query.first()
person = Person.query.get(3)# 主键 id
return render_template("PersonList.html", persons=persons)
数据筛选
@blue.route("/selectperson/")
def delete_person():
persons = Person.query.order_by("-p_age")#排序
persons = Person.query.limit(5)#取数据前5条
persons = Person.query.offset(5)#取数据丢弃前5条数据后的所有数据
#offset和limit不区分顺序,offset先生效
persons = Person.query.order_by("-id").limit(5).offset(5)
persons = Person.query.order_by("-id").limit(5)
persons = Person.query.order_by("-id").offset(17).limit(5)
#order_by 需要先调用执行,否则会报错
persons = Person.query.order_by("-id").offset(17).limit(5)
return render_template("PersonList.html", persons=persons)
逻辑运算
与and_ :filter(and_(条件))
或or_ :filter(or_(条件))
User.query.filter(or_(User.sex==True,User.age<20),User.id.in_([1,2,3]))
非not_ :filter(not_(条件)) 注意条件只能有一个
User.query.filter(not_(User.sex==True))
in:User.query.filter(User.id.in_([1,2,3]))
@blue.route("/deleteperson/")
def delete_person():
# 查询操作
person = Person.query.get(3)
db.session.delete(person)
db.session.commit()
return "删除成功
@blue.route("/addperson/")
def add_person():
p = Person()
p.p_name = "小明"
p.p_age = 15
db.session.add(p)
db.session.commit()
return "添加成功"
BaseQuery.paginate(page,per_page,False)(不常用)
page:当前页数
per_page:每页多少条数据
error_out=False
pagination = Movie.query.paginate(page,per_page,False)
#属性
page:当前页数
per_page:每页多少条数据
error_out=False
#方法
items:pagination对象转化为可迭代对象
pages:获取总页数
prev_num:上一页的页码
has_prev:是否有上一页
next_num:下一个页码
has_next:是否有下一页
iter_pages:
"""
创建分页函数对象pagination,传递pagination,使用pagination对象其中分页函数、参数实现分页操作
"""
#views.py
@blue.route('/index/')
def index():
#page是要查询的页码 问题?page从哪里获得
page = int(request.args.get('page',1))
#思考该方法的返回值类型 然后观察该类有什么方法
pagination = Movie.query.paginate(page,5,False)
return render_template('index.html',pagination=pagination)
#index.html
{% extends 'bootstrap/base.html' %}
#继承的模板是自带的模板是External Linbreries-json_flask-site-packages-flask_bootstrap
{% block navbar %}
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<div class="navbar-header">