Flask个人笔记

零、加载的第三方库

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

二、flask简介

1、基于python的web (微) 框架

重量级框架:为了方便业务程序的开发,提供了丰富的工具及其组件
轻量级框架:只提供web核心功能,自由灵活,高度定制

2、官方文档

http://flask.pocoo.org/docs/0.12/
http://docs.jinkan.org/docs/flask/

3、flask依赖库

flask依赖三个库
    jinja2 模板引擎
    Werkzeug  WSGI 工具集
    Itsdangerous 基于Django的签名模块
    现在不仅仅是三个  但是依然前两个有用
    安装时候会出现5个 看看就可以了

4、flask流行的主要原因

 1 有非常齐全的官方文档,上手非常方便
 2 有非常好的扩展机制和第三方扩展环境,工作中常见的软件都会有对应的扩展,自动动手实现扩展
 也很容易
 3 社区活跃度非常高    flask的热度已经超过django好几百了
 4 微型框架的形式给了开发者更大的选择空间

5、四大内置对象

"""
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('大嫂大嫂你好吗')

6、配置static和templates路径

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

三、MVC和MTV

1、MVC

一种软件设计架构风范:
Model:数据的封装,数据的抽象,用来操作数据的入口
View:视图,主要用来呈现给用户的
Controller:控制器,主要用来接收用户请求(输入),并且协调模型和视图

核心理念:解耦
实现结果:将数据操作,页面展示,逻辑处理进行了拆分

2、MTV

Models:封装数据操作、数据库的表和字段的定义
Template:模板、用来展示数据
Views:视图函数、相当于controller、接收请求,协调模型和模板

四、第三方库详解

1、flask-Blueprint蓝图

1. 宏伟蓝图(宏观规划)
2. 蓝图也是一种规划,主要用来规划urls(路由)
3. 蓝图基本使用
  	- 安装  pip install flask-blueprint
    - 创建、初始化蓝图   blue = Blueprint('first',__name__)
    - 调用蓝图进行路由注册  app.register_blueprint(blueprint=blue)    

1.1核心代码

#views.py
from flask import Blueprint

blue=Blueprint('blue',__name__)

def init_blue(app):
    app.register_blueprint(blueprint=blue)
    
@blue.route('/')
def index():
    return '欢迎来到德莱联盟'

2、Request/Response/会话

2.1Request

客户端请求、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)

2.2Response

创建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('<h2>xxxxxxxx</h2>',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 '不能让你看到状态码'

2.3Cookie

客户端会话技术、所有数据存储在客户端、以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


2.4session

服务端会话技术、所有数据存储在服务器中、默认存在服务器的内存中- 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 '成功'

3、flask-session

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

4、Template(jinjia2)

MVC中的View,MTV中的Template

主要用来做数据展示的、模板处理过程分为2个阶段(1 加载、2 渲染)

4.1jinja2模板引擎

本质上是html

支持特定的模板语法

flask作者开发的   一个现代化设计和友好的python模板语言  模仿的django的模板引擎

优点

	HTML设计和后端Python分离
	减少Python复杂度
	非常灵活,快速和安全
	提供了控制,继承等高级功能

4.2结构标签

#base.html

<!DOCTYPE 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>

4.3extends继承

#base_main.html

{% extends 'base.html' %}

{% block extCSS %}
{#在Django中加载静态资源{% static '' %}   url_for("static", filename=xxx) #}
    <link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
{% endblock %}

{% block header %}
    <h3>小伙子你又睡着了!</h3>
{% endblock %}

4.4include加载

index.html

{% extends 'base_main.html' %}

{% block header %}
    {{ super() }}
    <h6>销量已超200w,国产神车,哈佛H6!</h6>
{% endblock %}

{% block content %}
    {% include 'index_content.html' %}
{% endblock %}

4.5宏定义

可以在模板中定义,调用函数、函数还是用来生成html的、外文件中的宏定义调用需要导入include

{#调用函数 同页面调用函数#}
{% macro create_item(goods_id, goods_name) %}
    <h3>商品id{{ goods_id }}</h3>
    <h4>商品名字{{ goods_name }}</h4>
{% endmacro %}

{% block content %}
    {{ create_item("110", "手铐") }}
{% endblock %}


{#外文件导入函数#}
{% macro create_user(name) %}
    <h3>不小心创建了一个用户:{{ name }}</h3>
{% endmacro %}

{% from 'mmm.html' import create_user %}
    {{ create_user("翠花") }}

4.6过滤器

形式:{{ var|xxx|yyy|zzz }}(五个数限制)

{# 字符串操作 #}
{# 当变量未定义时,显示默认字符串,可以缩写为d #}
<p>{{ name | default('No name', true) }}</p>
 
{# 单词首字母大写 #}
<p>{{ 'hello' | capitalize }}</p>
 
{# 单词全小写 #}
<p>{{ 'XML' | lower }}</p>
 
{# 去除字符串前后的空白字符 #}
<p>{{ '  hello  ' | trim }}</p>
 
{# 字符串反转,返回"olleh" #}
<p>{{ 'hello' | reverse }}</p>
 
{# 格式化输出,返回"Number is 2" #}
<p>{{ '%s is %d' | format("Number", 2) }}</p>
 
{# 关闭HTML自动转义 #}
<p>{{ '<em>name</em>' | safe }}</p>
 
{% autoescape false %}
{# HTML转义,即使autoescape关了也转义,可以缩写为e #}
<p>{{ '<em>name</em>' | escape }}</p>
{% endautoescape %}


{# 数值操作 #}
{# 四舍五入取整,返回13.0 #}
<p>{{ 12.8888 | round }}</p>
 
{# 向下截取到小数点后2位,返回12.88 #}
<p>{{ 12.8888 | round(2, 'floor') }}</p>
 
{# 绝对值,返回12 #}
<p>{{ -12 | abs }}</p>


{# 列表操作 #}
{# 取第一个元素 #}
<p>{{ [1,2,3,4,5] | first }}</p>
 
{# 取最后一个元素 #}
<p>{{ [1,2,3,4,5] | last }}</p>
 
{# 返回列表长度,可以写为count #}
<p>{{ [1,2,3,4,5] | length }}</p>
 
{# 列表求和 #}
<p>{{ [1,2,3,4,5] | sum }}</p>
 
{# 列表排序,默认为升序 #}
<p>{{ [3,2,1,5,4] | sort }}</p>
 
{# 合并为字符串,返回"1 | 2 | 3 | 4 | 5" #}
<p>{{ [1,2,3,4,5] | join(' | ') }}</p>
 
{# 列表中所有元素都全大写。这里可以用upper,lower,但capitalize无效 #}
<p>{{ ['tom','bob','ada'] | upper }}</p>


{# 字典列表操作 #}
{% 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使其按降序排 #}
<ul>
{% for user in users | sort(attribute='age', reverse=true) %}
     <li>{{ user.name }}, {{ user.age }}</li>
{% endfor %}
</ul>
 
{# 列表分组,每组是一个子列表,组名就是分组项的值 #}
<ul>
{% for group in users|groupby('gender') %}
    <li>{{ group.grouper }}<ul>
    {% for user in group.list %}
        <li>{{ user.name }}</li>
    {% endfor %}</ul></li>
{% endfor %}
</ul>
 
{# 取字典中的某一项组成列表,再将其连接起来 #}
<p>{{ users | map(attribute='name') | join(', ') }}</p>

4.7Flask内置过滤器

Flask提供了一个内置过滤器”tojson”,它的作用是将变量输出为JSON字符串。这个在配合Javascript使用时非常有用。我们延用上节字典列表操作中定义的”users”变量

<script type="text/javascript">
var users = {{ users | tojson | safe }};console.log(users[0].name);
</script>

注意,这里要避免HTML自动转义,所以加上safe过滤器。

4.8语句块过滤

Jinja2还可以对整块的语句使用过滤器。

{% filter upper %}    This is a Flask Jinja2 introduction.{% endfilter %}

不过上述这种场景不经常用到。

4.9自定义过滤器

内置的过滤器不满足需求怎么办?自己写呗。过滤器说白了就是一个函数嘛,我们马上就来写一个。回到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] #}
<p>{{ [1,2,3,4,5] | double_step }}</p>

Flask还提供了添加过滤器的装饰器”template_filter”,使用起来更简单。下面的代码就添加了一个取子列表的过滤器。装饰器的参数定义了该过滤器的名称”sub”。

@app.template_filter('sub')
def sub(l, start, end):    
	return l[start:end]

我们在模板中可以这样使用它:

{# 返回[2,3,4] #}
<p>{{ [1,2,3,4,5] | sub(1,4) }}</p>

Flask添加过滤器的方法实际上是封装了对Jinja2环境变量的操作。上述添加”sub”过滤器的方法,等同于下面的代码。

app.jinja_env.filters['sub'] = sub

我们在Flask应用中,不建议直接访问Jinja2的环境变量。如果离开Flask环境直接使用Jinja2的话,就可以通过”jinja2.Environment”来获取环境变量,并添加过滤器。

5、flask-SQLAlachemy

Flask默认并没有提供任何数据库操作的API,Flask中可以自己的选择数据,用原生语句实现功能

原生SQL缺点
    代码利用率低,条件复杂代码语句越过长,有很多相似语句
    一些SQL是在业务逻辑中拼出来的,修改需要了解业务逻辑
    直接写SQL容易忽视SQL问题

Flask中并没有提供默认ORM,可以选择第三方扩展库,ORM(ORM 对象关系映射,通过操作对象对数据的操作)

SQLAlchemy
	MongoEngine
	将对对象的操作转换为原生SQL
	优点
	易用性,可以有效减少重复SQL
		性能损耗少
		设计灵活,可以轻松实现复杂查询
		移植性好

5.1安装以及配置

安装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

5.2核心代码

#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 %}

6、flask-migrate

可以在命令行中将models和数据库进行映射,操作分为初始化、加载、升级、降级

6.1安装以及配置

安装 :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 ‘创建用户’

6.2核心代码

#ext.py(创建migtare对象,由于没有其他地方调用,所以放在函数内部,在db初始化的上面)
def init_ext(app):
    # 创建迁移对象以及迁移数据的初始化
    migrate=Migrate()
    migrate.init_app(app=app,db=db)
    
#manager.py
manager.add_command("db", MigrateCommand)

7、flask-Bootstrap

7.1安装以及配置

插件安装: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

7.2核心代码

#ext.py
Bootstrap(app=app)

#htmlye页面继承
{% extends 'bootstrap/base.html' %}
#然后填补基模板的坑
	bootstrap中文网
    	反色导航栏:反色inverse	
    	巨幕

8、flask-debugtoolbar

辅助调试插件

8.1安装以及配置

安装:pip install flask-debugtoolbar
初始化  ext:
	debugtoolbar = DebugToolBarExtension()
	debugtoolbar.init_app(app=app)
只需要初始化就ok了
解释:
在所有模板中会自动加载、就是在页面的body上动态插入监测模块,可监测功能:
	flask版本
	路由器
	性能
	数据库
	项目配置信息

8.2核心代码

#ext.py(初始化)
debugtoolbar = DebugToolbarExtension()
debugtoolbar.init_app(app=app)

然后访问网页就会在右侧出现选项栏,查查看各种数据

9、flask-Cache

缓存目的:缓存优化加载,减少数据库的IO操作
实现方案:数据库、文件、内存、内存中的数据库 Redis
实现流程:
	从路由函数进入程序
	路由函数到视图函数
	视图函数去缓存中查找
	缓存中找到,直接进行数据返回
	如果没找到,去数据库中查找
	查找到之后,添加到缓存中
	返回到页面上

9.1安装以及配置

安装 :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

9.2核心代码

#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')

9.3缓存反爬虫实现

"""
主要实现思想是:当用户访问请求后,将获取访问请求主机的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 '欢迎再来'

10、flask-restful

介绍:

在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) 
异步的向服务器发送请求  
提交的是部分数据
利用返回的数据更新当前页面  
整个过程中 
页面无刷新  
不打断用户的操作

10.1前后端分离思想

#视图函数中的借助蓝图,用原生代码实现前后端分离的思想
@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)

10.2前后端分离实现

'''
思路大致:就是判断不同的请求方式,实现请求方法、高内聚,低耦合、高内聚、相同的数据操作封装在一起、低耦合、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}

10.3restful简介

整合网络和软件的一种架构模式、
理解:
    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

10.4安装以及配置

#安装 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"}

10.5核心代码实现

#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

10.6数据格式化输出

就是在得到客户请求之后,对数据库操作之后得到的对象无法满足返回数据的要求,所以要对返回数据的形式做了规定,如下面的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

10.7数据验证(请求参数)

在对象中添加字段: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

11、flask钩子

11.1钩子介绍

before_first_request:在对应用程序实例的第一个请求之前注册要运行的函数, 只会执行一次

before_request:在每个请求之前注册一个要运行的函数, 每一次请求都会执行

after_request:在每个请求之后注册一个要运行的函数, 每次请求都会执行. 需要接收一个 Response 类的对象				作为参数 并返回一个新的Response 对象 或者 直接返回接受到的Response 对象

teardown_request:注册一个函数在每个请求的末尾运行,不管是否有异常, 每次请求的最后都会执行.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wXQNyYLA-1592465098991)(C:\Users\Administrator\Desktop\python第四阶段\images\钩子执行顺序.png)]

11.2在app对象中的使用

#__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")

11.3在蓝图对象中使用

"""
实现现在当其他蓝图对象的路由接收到用户请求时候,不会执行钩子
只有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")

12、flask-mail

12.1安装与配置

安装 :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="客户端授权密码"

12.2核心代码实现

#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 = 'json_yuheng@163.com'
    MAIL_PASSWORD = 'yuheng19950619'#客户端授权密码

#mailApi.py
class MailResource(Resource):
    def get(self):
        msg = Message(subject='激活',sender="json_yuheng@163.com",recipients=["json_yuheng@163.com"])
        #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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        <span>欢迎您注册本网站,请点击链接实现用户激活,可以享受更多权益!</span>
        </p>
        <a href={{ url }}>激活</a>
        <p>如果上面链接不可点击,请复制下面的内容到浏览器中激活</p>
        <p>{{ url }}</p>
</body>

13、Celery框架

微信转账
钱包 减钱 等待2小时 账户 加钱
减钱是一个请求 然后我们收到了响应(2小时候内到账)
跨行转账
抢票

1、liunx

使用步骤
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('34327947@qq.com')
    return '邮件2小时发送给您'

if __name__ == '__main__':
    app.run(port=8001)

2、windows下虚拟环境

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('34327947@qq.com')
    return '邮件2小时发送给您'

if __name__ == '__main__':
    app.run(port=8001)

五、flask框架

1、flask实现

目录样式

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 是否开启多线程

================================================================================================================================================================================================================================================================================================================================================================================================================

2、封装flask

2.1封装框架思路

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管理对象)、可以接收命令行参数

2.2 封装flask代码

(1)manager.py
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()

(2)_init.py
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
(3)ext.py
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)
(4)models.py
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))
(5)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,
}
(6)views.py
from flask import Blueprint

blue=Blueprint('blue',__name__)#创建蓝图对象,在括号中的‘blue’是蓝图的名字,可以和对象不同。

def init_blue(app):#将蓝图和app进行关联
    app.register_blueprint(blueprint=blue)


@blue.route('/')
def index():
    return '欢迎来到德莱联盟'

================================================================================================================================================================================================================================================================================================================================================================================================================

3、restful思想框架

3.1封装框架思路

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管理对象)、可以接收命令行参数

3.2 实现restful

(1)manager.py
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()

(2)_init.py
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
(3)ext.py
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)
(4)models.py
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))
(5)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,
}
(6)apis.py
from flask import Blueprint

blue=Blueprint('blue',__name__)#创建蓝图对象,在括号中的‘blue’是蓝图的名字,可以和对象不同。

def init_blue(app):#将蓝图和app进行关联
    app.register_blueprint(blueprint=blue)


@blue.route('/')
def index():
    return '欢迎来到德莱联盟'

================================================================================================================================================================================================================================================================================================================================================================================================================

六、数据模型操作

1、数据操作DML

1.1增加

步骤:创建对象、放到数据连接的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 "添加成功"

1.2查询

通过过滤器进行查询

**获取结果集:**返回为数据的数据类型为结果集(多条数据)

@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]))

1.3删除

@blue.route("/deleteperson/")
def delete_person():
    # 查询操作
    person = Person.query.get(3)

    db.session.delete(person)
    db.session.commit()

    return "删除成功

1.4修改

@blue.route("/addperson/")
def add_person():
    p = Person()
    p.p_name = "小明"
    p.p_age = 15

    db.session.add(p)
    db.session.commit()

    return "添加成功"

2、分页操作

2.1paginate参数以及属性

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:

2.2核心代码实现

"""
创建分页函数对象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">
       <!-- Brand and toggle get grouped for better mobile display-->
       <div class="navbar-header">
       <button type="button"class="navbar-toggle collapsed"data-toggle="collapse">
       		<data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
        </button>
        <a class="navbar-brand" href="#">Brand</a>
        </div>

 <!-- Collect the nav links, forms, and other content for toggling -->
   <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
     <ul class="nav navbar-nav">
         <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
            <li><a href="#">首页</a></li>
            <li><a href="#">电影</a></li>
            <li><a href="#">电视剧</a></li>
      </ul>
      <form class="navbar-form navbar-left">
         <div class="form-group">
            <input type="text" class="form-control" placeholder="Search">
          </div>
          <button type="submit" class="btn btn-default">Submit</button>
       </form>
       <ul class="nav navbar-nav navbar-right">
          <li><a href="#">注册</a></li>
          <li><a href="#">登录</a></li>
        </ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
{% endblock %}

{% block content %}
<div class = 'container'>
    <div class="jumbotron">
        <h1>欢迎来到德莱联盟</h1>
        <p>一人带四坑,一打九,干就完了</p>
        <p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
    </div>
</div>
    
<div>
    <ol>
        {% for movie in pagination.items %}
        	<li>{{ movie.m_name }}</li>
        {% endfor %}
    </ol>
</div>
    
<div>
   <nav aria-label="Page navigation">
        <ul class="pagination">
        {% if pagination.has_prev %}
           <li>
           <a href="{{ url_for('blue.index') }}?page={{ pagination.prev_num }}" aria-label="Previous"><span aria-hidden="true">上一页</span></a>
            </li>
        {% else %}
            <li>
            <a href="#" aria-label="Previous"><span aria-hidden="true">上一页</span></a>
            </li>
        {% endif %}

        {% for page in pagination.iter_pages() %}
            {% if page %}
               {% if page != pagination.page %}
                  <li>
                  <a href="{{ url_for('blue.index') }}?page={{ page }}">{{ page }}</a>
                   </li>
               {% else %}
                   <li class="active">
                   <a href="{{ url_for('blue.index')}}?page={{ page }}">{{ page }}</a>
                   </li>
               {% endif %}
            {% endif %}
        {% endfor %}
`	{% if pagination.has_next%}
       <li>
       <a href="{{ url_for('blue.index') }}?page={{ pagination.next_num }}" aria-label="Next"><span aria-hidden="true">下一页</span></a>
        </li>
    {% else %}
        <li>
        <a href="#" aria-label="Next"><span aria-hidden="true">下一页</span></a>
        </li>
    {% endif %}
  </ul>
</nav>
</div>
{% endblock %}

3、数据定义

3.1字段

Integer、String、Text、Unicode、Date、Boolean

3.2约束

primary_key:主键
autoincrement:主键自增长
unique:唯一
default:默认
index:索引
not null:非空
ForeignKey:外键、用来约束级联数据
		db.Column( db.Integer, db.ForeignKey(xxx.id) )
		使用relationship实现级联数据获取、声明级联数据、backref="表名"、lazy=True

4、模型关系

4.1一对一

class Parent(Base):
    id =db.Column(db.Integer, primary_key=True)
    child_id = db.Column(db.Integer, ForeignKey('child.id'))
    child = relationship("Child", backref=backref("parent", uselist=False)) 

class Child(Base):
    id = db.Column(db.Integer, primary_key=True)
    parent_id = db.Column(db.Integer, ForeignKey('parent.id'))

4.2一对多

#models.py
class Grade(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    g_name = db.Column(db.String(16))
    g_type = db.Column(db.Integer, default=1)
    g_students = db.relationship("Student", backref="grade", lazy=True)

class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    s_name = db.Column(db.String(16))
    s_age = db.Column(db.Integer, default=4)
    s_grade = db.Column(db.Integer, db.ForeignKey(Grade.id))

#views.py
@blue.route("/getstudents/<int:gradeid>/")
def get_students(gradeid):

    students = Student.query.filter_by(s_grade=gradeid)
    # grade = Grade.query.get(gradeid)
    # students = grade.g_students
    return render_template("StudentList.html", students=students)

参数和函数

relationship函数:sqlalchemy对关系之间提供的一种便利的调用方式,关联不同的表;
backref参数:对关系提供反向引用的声明,在Address类上声明新属性的简单方法,之后可以在		   				my_address.person来获取这个地址的person;
lazy参数
	'select'(默认值):SQLAlchemy 会在使用一个标准 select 语句时一次性加载数据;
	'joined':让 SQLAlchemy 当父级使用 JOIN 语句是,在相同的查询中加载关系;
	'subquery':类似 'joined' ,但是 SQLAlchemy 会使用子查询;
	'dynamic':SQLAlchemy 会返回一个查询对象,在加载这些条目时才进行加载数据,大批量数据查询				处理时推荐使用。
ForeignKey参数:代表一种关联字段,将两张表进行关联的方式,表示一个person的外键,设定上必须要能在父表中找到对应的id值

4.3多对多

#models.py
class User(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    u_name = db.Column(db.String(16))
    u_age = db.Column(db.Integer, default=1)
    
class Movie(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    m_name = db.Column(db.String(256))
    
class Collect(db.Model):
    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    c_user = db.Column(db.Integer, db.ForeignKey(User.id))
    c_movie = db.Column(db.Integer, db.ForeignKey(Movie.id))

#views.py
@blue.route("/addtocollect/")
def add_to_collect():
    movie_id = int(request.args.get("movie_id"))
    user_id = int(request.args.get("user_id"))

    collects = Collect.query.filter_by(c_user=user_id).filter_by(c_movie=movie_id)

    if collects.count() > 0:
        return "添加成功"
    else:
        collect = Collect()
        collect.c_user = user_id
        collect.c_movie = movie_id

        db.session.add(collect)
        db.session.commit()
        return "真添加成功了"

5、数据库设计

数据库绝对是开发中的重点,设计好了数据库,那么我们开发就成功了一半,可以看出数据库有多重要了。

对于前台的模型有以下几个表:

  • 会员表(user)
  • 会员登录日志(userlog)
  • 标签表(tag)
  • 电影表(movie)
  • 上映预告(preview)
  • 评论(comment)
  • 电影收藏(moviecol)

其中的关系:

会员表(user)
id编号,整型,主键,自动递增
name昵称,字符串型,唯一
pwd密码,字符串型
email邮箱,字符串型,唯一
phone手机号码,字符串型,唯一
info个性简介,文本型
face头像,字符串型,唯一
addtime添加时间,日期时间类型,默认当前十年
uuid唯一标识符,字符串型,唯一
uerlog关联会员登录日志模型
comments关联评论模型
moviecols关联收藏模型
会员登录日志表(userlog)
id编号,整型,主键,自动递增
user_id所属会员ID,整型,关联user表的id字段
ipIP地址,字符串型
addtime添加时间,日期时间类型,默认为当前的时间
标签表(tag)
id编号,整型,主键,自动递增
name标题,字符串型,唯一
addtime添加时间,日期时间类型,默认为当前的时间
movies关联电影模型
电影表(movie)
id编号,整型,主键,自动递增
title标题,字符串型,唯一
url地址,字符串型,唯一
info简介,文本型
logo封面,字符串型,唯一
star星型,小整型
playnum播放量,大整型
commentnum评论量,大整型
tag_id所属标签ID,整型,关联tag表的id字段
area上映地区,字符串类型
release_time上映时间,日期类型
length播放时间,字符串整型
addtime添加时间,日期时间型,默认单前时间
comments关联评论模型
moviecols关联电影收藏模型
上映预告(preview)
id编号,整型,主键,自动递增
title标题,字符串型,唯一
logo封面,字符串型,唯一
addtime添加时间,日期时间型,默认为当前时间
评论(comment)
id编号,整型,主键,自动递增
content内容,文本型
movie_id所属电影ID,整型,关联movie表的id地段
user_id所属用户ID,整型,关联user表的id字段
addtime添加时间,日期时间型,默认为当前时间
电影收藏(moviecol)
id编号,整型,主键,自动递增
movie_id所属电影ID,整型,关联movie表的id地段
user_id所属用户ID,整型,关联user表的id字段
addtime添加时间,日期时间型,默认为当前时间

后台模型

  • 权限表(auth)
  • 角色表(role)
  • 管理员表(admin)
  • 管理员登录日志(adminlog)
  • 操作日志(oplog)
权限表(auth)
id编号,整型,主键,自动递增
name名称,字符串型,唯一
url地址,字符串型,唯一
addtime添加时间,日期时间类型
角色表(role)
id编号,整型,主键,自动递增
name名称,字符串型,唯一
auths角色权限列表,字符串型
addtime添加时间,日期时间类型,默认为当前时间
admin关联admin模型
管理员表(admin)
id编号,整型,主键,自动递增
name管理员账号,字符串型,唯一
pwd管理员密码,字符串型
is_super是否为超级管理员,小整型
role_id所属角色ID,模型,关联role表的id字段
addtime添加时间,日期时间类型,默认为当前时间
adminlogs关联adminlog模型
oplogs关联oplog模型
管理员登录日志(adminlog)
id编号,整型,主键,自动递增
adminlog所属管理员id,整型,关联admin的id字段
ip登录IP,字符串型
addtime添加时间,日期时间类型,默认为当前时间
操作日志(oplog)
id编号,整型,主键,自动递增
adminlog所属管理员ID, 整型, 管理admin的id字段
ip操作IP,字符串型
reason操作原因,字符串型
addtime添加时间,日期时间类型,默认为当前时间

七、getjson(ajax)

views.py
@blue.route('/getjson/')
def getjson():
    data={
        'msg':'ok',
        'status':'200',
        'scorelist':[100,90,99,101]
    }
    #return是不可以直接返回json的 必须使用jsonify方法  然后才可以相应
    return jsonify(data)

@blue.route('/a/')
def a():
    return render_template('scoreList.html')
#scoreList.html
<script type="text/javascript">
    $(function () {
        $.getJSON("/getjson/", function (data) {
            var scores = data["scorelist"];
            var $ul = $("#idol");
            for ( var i=0; i < scores.length; i++){
                var $li = $("<li></li>").html(scores[i]);
                $ul.append($li);
            }
        })
    })
</script>   
<body>
    <ol id = 'idol'></ol>
</body>

1、json数据处理

json数据

{#还有 "B": [
  "returnCode": "0",
  "returnValue": {
    "A": [
      {
        "id": 3643,
        "parentId": 0,
        "regionName": "阿坝",
        "cityCode": 513200,
        "pinYin": "ABA"
      },
      {
        "id": 3090,
        "parentId": 0,
        "regionName": "阿克苏",
        "cityCode": 652901,
        "pinYin": "AKESU"
      },

数据处理函数

#此文件将将json文件保存到数据库
import json
import pymysql


def save_model():
    #获取json数据中的字母,保存到letter表中
    #获取json数据中id:3643
    with open('cities.json','r',encoding="UTF-8") as fp:
        result=json.load(fp)
    returnValue=result.get('returnValue')
    letters=returnValue.keys()
    print(type(letters))
    #将数据插入到letter表中
    conn=pymysql.connect(host='localhost',port=3306,user='root',password='123456',database='Tpp',charset='utf8')
    cursor=conn.cursor()
    for letter in letters:
        sql='insert into letter(letter) values("{}")'.format(letter)
        cursor.execute(sql)
        conn.commit()

    #将数据插入到ctiy表中
    sql='select * from letter'
    cursor.execute(sql)
    results=cursor.fetchall()
    i=1
    for letter in letters:

        for re in  results:
            if re[1]==letter:
                letter_id=re[0]
        citylist=returnValue[letter]

        for city in citylist:
            id=city['id']
            print(i)
            parentId=city['parentId']
            regionName=city['regionName']
            cityCode=city['cityCode']
            pinYin=city['pinYin']
            print(id,parentId,regionName,cityCode,pinYin,letter_id )
            sql1 = "insert into city values ('{}','{}','{}','{}','{}','{}')".format(id,parentId,regionName,cityCode,pinYin,letter_id)
            cursor.execute(sql1)
            conn.commit()
            i=i+1

if __name__=='__main__':
    save_model()

八、零散知识

1、数据加密解密

from werkzeug.security import generate_password_hash
password = generate_password_hash(password)#数据加密

from werkzeug.security import check_password_hash
check_password_hash(user.password,password)

2、装饰器进阶

""""
装饰器进化过程思密达。。。
1普通方法的调用之计算运行时间
"""''
import time
def work(job):
    print('我正在玩儿命' + job)
    time.sleep(3)

def eat():
    print('我正在慢慢的吃东西')
    time.sleep(10)

if __name__ == '__main__':
    start_time = time.time()
    work()
    end_time = time.time()
    print(end_time - start_time)

    start_time = time.time()
    eat()
    end_time = time.time()
    print(end_time - start_time)

""""
2简易装置器调用
"""
def cal_time(func):
    start_time = time.time()
    func()
    end_time = time.time()
    print(end_time - start_time)


def work(job):
    print('我正在玩儿命' + job)
    time.sleep(3)


def eat():
    print('我正在慢慢的吃东西')
    time.sleep(10)


if __name__ == '__main__':
    cal_time(work)
    cal_time(eat)

""""
3简单装饰器调用
"""
import time


def cal_time(func):
    def do_cal():
        start_time = time.time()
        func()
        end_time = time.time()
        print(end_time - start_time)
    return do_cal

@cal_time
def work():
    print('我正在玩儿命玩耍 ')
    time.sleep(3)

@cal_time
def eat():
    print('我正在慢慢的吃东西')
    time.sleep(3)

if __name__ == '__main__':
    work()
    eat()

""""
4装饰器方法传参数
"""

def cal_time(func):
    def do_cal(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print(end_time - start_time)
    return do_cal

@cal_time
def work(job):
    print('我正在玩儿命' + job)
    time.sleep(3)


if __name__ == '__main__':
    work('玩耍')

"""
5装饰器传参数
"""


def can_play(clock):
    def can_play_func(func):
        def play(*args, **kwargs):
            if clock > 22:
                print('洗洗睡吧')
            else:
                func(*args, **kwargs)
        return play
    return can_play_func

@can_play(21)
def game(name):
    print('我正在玩儿' + name)


if __name__ == '__main__':
    game('连连看')

"""
6终极权限
"""
ADMIN = 4

def check_permission(permission):
    def check_permission_fun(func):
        def check(*args, **kwargs):
            parse = parser_post.parse_args()
            u_token = parse.get("token")
            users = UserModel.query.filter(UserModel.u_token.__eq__(u_token))
            if users.count() > 0:
                user = users.first()
                if user.u_promission == permission:
                    print("用户是拥有权限的,准备查看电影")
                    return func(*args, **kwargs)
                else:
                    abort(403, message="你没有权限查看此模块,请联系系统管理员")
            else:
                abort(401, message="您还没有登录,请登录查看")
        return check
    return check_permission_fun


3、数据库多条件查询进阶

	需求:如果是全部,那么都检索所有数据
	      否则检索输入的城区
	
	解决方案:
	      难点:检索的数据不确定 
	id    name  age  条件不确定

	难点:sql不好写
                 select * from user 
                 select * from user where id = xxx
                 select * from user where name = xxx and age = xxx

                 sql = select * from user where 1=1[注意后面要写一个空格] 
                 if id:
                       sql +=  and id= xxx
                 if name  
                       sql  += and name = xxx

                 select * from user where 1=1 and id= xxx and name = xxx
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值