无用之flask学习
一、认识flask
1、短小精悍、可扩展性强 的一个web框架
注意:上下文管理机制
2、依赖wsgi:werkzurg
from werkzeug.wrappers import Request, Response @Request.application
def hello(request):
return Response('Hello World!') if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', , hello)
注意__init__和__call__的区别:
class Foo():
def __init__(self):
print('init')
def __call__(self, *args, **kwargs):
print('call')
a = Foo()
a() #init
#call
一个简单的flask代码
from flask import Flask
app = Flask(__name__)
@app.route('/index')
def index():
return 'hello world' if __name__ == '__main__':
app.run('local
二、一个有登录功能的flask例子
1、template可以类似django修改
2、static有两种方式,
A: a、 static_folder="staticccc" b、将static文件夹命名为 staticccc c、img引用的时候用staticccc/xxxxx
B: a、 static_url_path='/vvvvv' b、 img引用的时候用 /vvvvv/xxxxx
from flask import Flask,render_template,request,redirect,session # app = Flask(__name__,template_folder="templates",static_folder="staticccc",static_url_path='/vvvvv')
app = Flask(__name__,template_folder="templates",static_folder="static")
app.secret_key = 'asdfasdf' @app.route('/login',methods=["GET","POST"])
def login():
if request.method == 'GET':
return render_template('login.html')
# request.args 获取的是get的信息
user = request.form.get('user') #获取的是post的信息
pwd = request.form.get('pwd')
if user == 'oldboy' and pwd == '':
session['user'] = user
return redirect('/index')
return render_template('login.html',error='用户名或密码错误')
# return render_template('login.html',**{"error":'用户名或密码错误'}) @app.route('/index')
def index():
user = session.get('user')
if not user:
return redirect('/login')
return render_template('index.html') if __name__ == '__main__':
app.run()
index.html
<body>
<h1>欢迎使用</h1>
<img src="/static/111.png" alt="">
</body>
login.html
<body>
<h1>用户登录</h1>
<form method="post">
<input type="text" name="user">
<input type="password" name="pwd">
<input type="submit" value="提交">{{error}}
</form>
</body>
三、flask基础
、配置文件 、路由系统 、视图 、请求相关 、响应 、模板渲染 、session 、闪现 、中间件 、蓝图(blueprint) 、特殊装饰器
1、django和flask的区别
django:是一个大而全的框架,内部提供了很多组件,如orm,admin,forms,分页等很多方便的组件,只需在配置里配置下就可以了
flask: 是一个轻量级的框架,短小精悍,可扩展性很强,适用于开发小的网站,他提供了很多第三方的组件,只需要跟这些组件结合起来也可以创造一个类似django的框架 ,可定制型强
就我个人而言,我比较偏向于。。。。。
2、flask和django最大的不同点
request/session,
django需要导入,参数;flask直接调用
3、flask知识点
--模板+静态文件 ,app=Flask(__name__,......)
--路由
@app.route('/index',methods=['GET'])
--请求
request.form
request.args
request.method
--响应
“”
render
redirect
--session
session['xx']=123
session.get('xx')
4、配置文件导入原理, ----即给一个路径‘settings.Foo’,可以找到类并获取去其中的大写的静态字段
settings.py
class Foo():
DEBUG = True
TEXT = True
test.py
import importlib path = 'settings.Foo'
p,c = path.rsplit('.',maxsplit=)
m = importlib.import_module(p)
cls = getattr(m,c) for key in dir(cls):
if key.isupper():
print(key,getattr(cls,key)) #DEBUG True
#TEXT True
5、配置文件使用
app.config.from_object('settings.Dev')
test.py
from flask import Flask
app = Flask(__name__) print(app.config)
app.config.from_object('settings.Dev')
print(app.config) if __name__ == '__main__':
app.run()
settings.py
class Base(object): #无论哪种环境都需要的类
XX = class Pro(Base): #生产环境
DEBUG = False class Dev(Base): #开发环境
DEBUG = True
6、路由系统
实例:
from flask import Flask,url_for
app = Flask(__name__) app.route('/index/<int:nid>',methods=['GET','POST'])
def index(nid):
print(url_for("index",nid=))
知识点:
---endpoint,反向生成URL,默认函数名 ---url_for('endpoint') ---动态路由: /index/<int:nid> def index(nid): print(nid)
return "index"
7、请求和响应相关
请求相关消息
# 请求相关信息
# request.method
# request.args
# request.form
# request.values
# request.cookies
# request.headers
# request.path
# request.full_path
# request.script_root
# request.url
# request.base_url
# request.url_root
# request.host_url
# request.host
# request.files
响应相关消息
A、响应体
return render_template('xxx.html')
return redirect('/index')
return 'xxx'
return jsonify({'k1':'v1'})
B、响应头
obj = make_response('asdf')
obj.headers['xxxx'] = ''
obj.set_cookie('key','value')
return obj
8、学生管理系统
版本一几乎不用,版本二在某些函数前做定制,版本在全局使用的时候用到
版本一:
@app.route('/index')
def index():
if not session.get('user'):
return redirect(url_for('login'))
return render_template('index.html',stu_dic=STUDENT_DICT)
版本二:
import functools
def auth(func):
@functools.wraps(func)
def inner(*args,**kwargs):
if not session.get('user'):
return redirect(url_for('login'))
ret = func(*args,**kwargs)
return ret
return inner @app.route('/index')
@auth
def index():
return render_template('index.html',stu_dic=STUDENT_DICT) 应用场景:比较少的函数中需要额外添加功能。 版本三:before_request
@app.before_request
def xxxxxx():
if request.path == '/login':
return None if session.get('user'):
return None return redirect('/login')
app.py
from flask import Flask,render_template,request,redirect,session,url_for,jsonify,make_response,Markup,flash,get_flashed_messages app = Flask(__name__) app.config.from_object("settings.DevelopmentConfig") STUDENT_DICT = {
:{'name':'王龙泰','age':,'gender':'中'},
:{'name':'小东北','age':,'gender':'男'},
:{'name':'田硕','age':,'gender':'男'},
} @app.before_request
def xxxxxx():
if request.path == '/login':
return None if session.get('user'):
return None return redirect('/login') @app.route('/login',methods=["GET","POST"])
def login():
print('login')
if request.method == 'GET':
return render_template('login.html')
user = request.form.get('user')
pwd = request.form.get('pwd')
if user == 'oldboy' and pwd == '':
session['user'] = user
return redirect('/index')
return render_template('login.html',error='用户名或密码错误') @app.route('/index')
def index():
print('index')
return render_template('index.html',stu_dic=STUDENT_DICT) @app.route('/delete/<int:nid>')
def delete(nid): del STUDENT_DICT[nid]
return redirect(url_for('index')) @app.route('/detail/<int:nid>')
def detail(nid):
info = STUDENT_DICT[nid]
return render_template('detail.html',info=info) if __name__ == '__main__':
app.run()
login.html
<body>
<h1>用户登录</h1>
<form method="post">
<input type="text" name="user">
<input type="password" name="pwd">
<input type="submit" value="提交">{{error}}
</form>
index.html
<body>
<h1>学生列表</h1>
<table border="">
<thead>
<tr>
<th>ID</th>
<th>姓名</th>
<th>年龄</th>
<th>性别</th>
<th>选项</th>
</tr>
</thead>
<tbody>
{% for k,v in stu_dic.items() %}
<tr>
<td>{{k}}</td>
<td>{{v.name }}</td>
<td>{{v.age}}</td>
<td>{{v.gender}}</td>
<td>
<a href="/detail/{{k}}">查看详细</a>
|
<a href="/delete/{{k}}">删除</a> </td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
detail.html
<body>
<h1>学生详细</h1>
<ul> {% for item in info.values() %}
<li>{{item}}</li>
{% endfor %}
</ul>
</body>
9、模板
. 模板渲染
- 基本数据类型:可以执行python语法,如:dict.get() list['xx']
- 传入函数
- django,自动执行
- flask,不自动执行
- 全局定义函数
@app.template_global()
def sb(a1, a2):
# {{sb(,)}}
return a1 + a2 @app.template_filter()
def db(a1, a2, a3):
# {{ |db(,) }}
return a1 + a2 + a3
- 模板继承
layout.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>模板</h1>
{% block content %}{% endblock %}
</body>
</html> tpl.html
{% extends "layout.html"%} {% block content %}
{{users.}} {% endblock %}
- include {% include "form.html" %} form.html
<form>
asdfasdf
asdfasdf
asdf
asdf
</form>
- 宏
{% macro ccccc(name, type='text', value='') %}
<h1>宏</h1>
<input type="{{ type }}" name="{{ name }}" value="{{ value }}">
<input type="submit" value="提交">
{% endmacro %} {{ ccccc('n1') }} {{ ccccc('n2') }} - 安全
- 前端: {{u|safe}}
- 前端: MarkUp("asdf")
10、session
当请求刚到来:flask读取cookie中session对应的值:eyJrMiI6NDU2LCJ1c2VyIjoib2xkYm95,将该值解密并反序列化成字典,放入内存以便视图函数使用。 视图函数:
@app.route('/ses')
def ses():
session['k1'] =
session['k2'] =
del session['k1'] return "Session" session['xxx'] =
session['xxx'] 当请求结束时,flask会读取内存中字典的值,进行序列化+加密,写入到用户cookie中。
settings.py
from datetime import timedelta
class Config(object):
DEBUG = False
TESTING = False
SECRET_KEY = "asdfasdfas23"
DATABASE_URI = 'sqlite://:memory:' SESSION_COOKIE_NAME = 'session'
SESSION_COOKIE_DOMAIN = None
SESSION_COOKIE_PATH = None
SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SECURE = False
SESSION_REFRESH_EACH_REQUEST = True
PERMANENT_SESSION_LIFETIME = timedelta(hours=)
11、闪现
在session中存储一个数据,读取时通过pop将数据移除。
from flask import Flask,flash,get_flashed_messages
@app.route('/page1')
def page1(): flash('临时数据存储','error')
flash('sdfsdf234234','error')
flash('adasdfasdf','info') return "Session" @app.route('/page2')
def page2():
print(get_flashed_messages(category_filter=['error']))
return "Session"
12、中间件
- call方法什么时候出发?
- 用户发起请求时,才执行。
- 任务:在执行call方法之前,做一个操作,call方法执行之后做一个操作。
class Middleware(object):
def __init__(self,old):
self.old = old def __call__(self, *args, **kwargs):
ret = self.old(*args, **kwargs)
return ret if __name__ == '__main__':
app.wsgi_app = Middleware(app.wsgi_app)
app.run()
13、特殊装饰器
. before_request . after_request 示例:
from flask import Flask
app = Flask(__name__) @app.before_request
def x1():
print('before:x1')
return '滚' @app.before_request
def xx1():
print('before:xx1') @app.after_request
def x2(response):
print('after:x2')
return response @app.after_request
def xx2(response):
print('after:xx2')
return response @app.route('/index')
def index():
print('index')
return "Index" @app.route('/order')
def order():
print('order')
return "order" if __name__ == '__main__': app.run() . before_first_request from flask import Flask
app = Flask(__name__) @app.before_first_request
def x1():
print('') @app.route('/index')
def index():
print('index')
return "Index" @app.route('/order')
def order():
print('order')
return "order" if __name__ == '__main__': app.run() . template_global . template_filter . errorhandler
@app.errorhandler()
def not_found(arg):
print(arg)
return "没找到"
14、内容慧谷
. django和flask区别?
.什么是wsgi?
web服务网关接口,wsgi是一个协议,实现该写一个的模块:
- wsgiref
- werkzeug
实现其协议的模块本质上就是socket服务端用于接收用户请求,并处理。
一般web框架基于wsgi实现,这样实现关注点分离。 wsgiref示例:
from wsgiref.simple_server import make_server def run_server(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ] if __name__ == '__main__':
httpd = make_server('127.0.0.1', , run_server)
httpd.serve_forever() werkzeug示例:
from werkzeug.wrappers import Response
from werkzeug.serving import run_simple def run_server(environ, start_response):
response = Response('hello')
return response(environ, start_response) if __name__ == '__main__':
run_simple('127.0.0.1', , run_server) Flask源码入口:
from werkzeug.wrappers import Response
from werkzeug.serving import run_simple class Flask(object):
def __call__(self,environ, start_response):
response = Response('hello')
return response(environ, start_response) def run(self):
run_simple('127.0.0.1', , self) app = Flask() if __name__ == '__main__':
app.run() . Flask提供功能
- 配置文件
- 所有配置都在app.config中
- app.config["xx"] =
- app.config.from_object("类的路径")
- 应用:importlib、getattr
- django中间件
- rest framework全局配置
- session
- 加密后放置在用户浏览器的cookie中。
- 流程:
- 请求到来
- 视图函数
- 请求结束
- 配置文件
- 闪现
- 基于session实现
- 路由
- 装饰器(带参数)
- 自定义装饰器放下面
- 参数
- url_for
- 视图
- FBV
- 请求和响应
- 请求:request
- 响应: 4种
- 模板
- ...
- 特殊装饰器
- before_first_request
- before_request
- after_request
- template_global()
- template_filter()
- errorhandler()
- 中间件 今日内容:
. 路由+视图
. session实现原理(源码)
. 蓝图
. threading.local
. 上下文管理(第一次)
15、路由+视图
a. 路由设置的两种方式:
@app.route('/xxx')
def index():
return "index" def index():
return "index"
app.add_url_rule("/xxx",None,index) 注意事项:
- 不用让endpoint重名
- 如果重名函数也一定要相同。
16、路由+视图之 参数
rule, URL规则
view_func, 视图函数名称
endpoint=None, 名称,用于反向生成URL,即: url_for('名称')
methods=None, 允许的请求方式,如:["GET","POST"]
strict_slashes=None, 对URL最后的 / 符号是否严格要求,
redirect_to=None, 重定向到指定地址 defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数
subdomain=None, 子域名访问
实例
需要去hosts文件里将 127.0.0.1 wupeiqi.com,将ip和域名配置下
from flask import Flask, views, url_for app = Flask(import_name=__name__)
app.config['SERVER_NAME'] = 'wupeiqi.com:5000'
"""
127.0.0.1 wupeiqi.com
127.0.0.1 web.wupeiqi.com
127.0.0.1 admin.wupeiqi.com """ # http://admin.wupeiqi.com:5000/
@app.route("/", subdomain="admin")
def admin_index():
return "admin.your-domain.tld" # http://web.wupeiqi.com:5000/
@app.route("/", subdomain="web")
def web_index():
return "web.your-domain.tld" # http://sdsdf.wupeiqi.com:5000/
# http://sdfsdf.wupeiqi.com:5000/
# http://asdf.wupeiqi.com:5000/ @app.route("/dynamic", subdomain="<username>")
def username_index(username):
"""Dynamic subdomains are also supported
Try going to user1.your-domain.tld/dynamic"""
return username + ".your-domain.tld" if __name__ == '__main__':
app.run()
17、路由+视图之 CBV
import functools
from flask import Flask,views
app = Flask(__name__) def wrapper(func):
@functools.wraps(func)
def inner(*args,**kwargs):
return func(*args,**kwargs) return inner class UserView(views.MethodView):
methods = ['GET']
decorators = [wrapper,] def get(self,*args,**kwargs):
return 'GET' def post(self,*args,**kwargs):
return 'POST' app.add_url_rule('/user',None,UserView.as_view('uuuu')) if __name__ == '__main__':
app.run()
18、路由+视图之 自定义正则
from flask import Flask,url_for app = Flask(__name__) # 步骤一:定制类
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
"""
自定义URL匹配正则表达式
""" def __init__(self, map, regex):
super(RegexConverter, self).__init__(map)
self.regex = regex def to_python(self, value):
"""
路由匹配时,匹配成功后传递给视图函数中参数的值
:param value:
:return:
"""
return int(value) def to_url(self, value):
"""
使用url_for反向生成URL时,传递的参数经过该方法处理,返回的值用于生成URL中的参数
:param value:
:return:
"""
val = super(RegexConverter, self).to_url(value)
return val # 步骤二:添加到转换器
app.url_map.converters['reg'] = RegexConverter """
. 用户发送请求
. flask内部进行正则匹配
. 调用to_python(正则匹配的结果)方法
. to_python方法的返回值会交给视图函数的参数 """ # 步骤三:使用自定义正则
@app.route('/index/<reg("\d+"):nid>')
def index(nid):
print(nid,type(nid)) print(url_for('index',nid=))
return "index" if __name__ == '__main__':
app.run()
19、session原理
session流程图(加分项)
20、蓝图
目标:给开发者提供目录结构 其他:
- 自定义模板、静态文件
- 某一类url添加前缀 -----用以加版本号如,v1....
- 给一类url添加before_request
A、小蓝图(template、views放一起,大蓝图类似django分布)目录
B、manage.py
from crm import create_app app = create_app() if __name__ == '__main__':
app.run()
init.py
from flask import Flask
from .views.account import ac
from .views.user import uc def create_app(): app = Flask(__name__) # @app.before_request
# def x1():
# print('app.before_request') app.register_blueprint(ac)
app.register_blueprint(uc,url_prefix='/api')
return app
accout.py
from flask import Blueprint,render_template ac = Blueprint('ac',__name__) @ac.before_request
def x1():
print('app.before_request') @ac.route('/login')
def login():
return render_template('login.html') @ac.route('/logout')
def logout():
return 'Logout'
user.py
from flask import Blueprint uc = Blueprint('uc',__name__) @uc.route('/list')
def list():
return 'List' @uc.route('/detail')
def detail():
return 'detail'
21、threading.local【和flask无任何关系】
flask里local()原码
作用:为每个线程创建一个独立的空间,使得线程对自己的空间中的数据进行操作(数据隔离)。
import threading
from threading import local
import time obj = local() def task(i):
obj.xxxxx = i
time.sleep()
print(obj.xxxxx,i) for i in range():
t = threading.Thread(target=task,args=(i,))
t.start() 问题:
- 如何获取一个线程的唯一标记? threading.get_ident()
- 根据字典自定义一个类似于threading.local功能?
import time
import threading DIC = {} def task(i):
ident = threading.get_ident()
if ident in DIC:
DIC[ident]['xxxxx'] = i
else:
DIC[ident] = {'xxxxx':i }
time.sleep() print(DIC[ident]['xxxxx'],i) for i in range():
t = threading.Thread(target=task,args=(i,))
t.start() - 根据字典自定义一个为每个协程开辟空间进行存取数据。 import time
import threading
import greenlet DIC = {} def task(i): # ident = threading.get_ident()
ident = greenlet.getcurrent()
if ident in DIC:
DIC[ident]['xxxxx'] = i
else:
DIC[ident] = {'xxxxx':i }
time.sleep() print(DIC[ident]['xxxxx'],i) for i in range():
t = threading.Thread(target=task,args=(i,))
t.start() - 通过getattr/setattr 构造出来 threading.local的加强版(协程)
import time
import threading
try:
import greenlet
get_ident = greenlet.getcurrent
except Exception as e:
get_ident = threading.get_ident class Local(object):
DIC = {} def __getattr__(self, item):
ident = get_ident()
if ident in self.DIC:
return self.DIC[ident].get(item)
return None def __setattr__(self, key, value):
ident = get_ident()
if ident in self.DIC:
self.DIC[ident][key] = value
else:
self.DIC[ident] = {key:value} obj = Local() def task(i):
obj.xxxxx = i
time.sleep()
print(obj.xxxxx,i) for i in range():
t = threading.Thread(target=task,args=(i,))
t.start()
22、上下文管理
请求到来时候:
# ctx = RequestContext(self, environ) # self是app对象,environ请求相关的原始数据
# ctx.request = Request(environ)
# ctx.session = None # 将包含了request/session的ctx对象放到“空调”
{
:{ctx:ctx对象}
:{ctx:ctx对象}
:{ctx:ctx对象}
:{ctx:ctx对象}
:{ctx:ctx对象}
} 视图函数:
from flask import reuqest,session request.method 请求结束:
根据当前线程的唯一标记,将“空调”上的数据移除。
23、上下文管理前戏
1、偏函数
# by luffycity.com
import functools def index(a1,a2):
return a1 + a2 # 原来的调用方式
# ret = index(,)
# print(ret) # 偏函数,帮助开发者自动传递参数
new_func = functools.partial(index,)
ret = new_func()
print(ret)
2、执行父类方法
- super和执行类的区别?
"""
class Base(object): def func(self):
print('Base.func') class Foo(Base): def func(self):
# 方式一:根据mro的顺序执行方法
# super(Foo,self).func()
# 方式二:主动执行Base类的方法
# Base.func(self) print('Foo.func') obj = Foo()
obj.func()
"""
####################################
class Base(object): def func(self):
super(Base, self).func()
print('Base.func') class Bar(object):
def func(self):
print('Bar.func') class Foo(Base,Bar):
pass # 示例一
# obj = Foo()
# obj.func()
# print(Foo.__mro__) # 示例二
# obj = Base()
# obj.func()
3、面向对象中特殊方法 setattr/getattr注意事项:
class Foo(object):
def __init__(self):
# self.storage = {}
object.__setattr__(self,'storage',{}) def __setattr__(self, key, value):
print(key,value,self.storage) obj = Foo()
obj.xx =
4、基于列表实现栈
class Stack(object): def __init__(self):
self.data = [] def push(self,val):
self.data.append(val) def pop(self):
return self.data.pop() def top(self):
return self.data[-] _stack = Stack() _stack.push('佳俊')
_stack.push('咸鱼') print(_stack.pop())
print(_stack.pop())
24、flask-session
pip3 install flask-session 掌握:
- 使用
# by luffycity.com
import redis
from flask import Flask,request,session
from flask.sessions import SecureCookieSessionInterface
from flask_session import Session app = Flask(__name__) # app.session_interface = SecureCookieSessionInterface()
# app.session_interface = RedisSessionInterface()
app.config['SESSION_TYPE'] = 'redis'
app.config['SESSION_REDIS'] = redis.Redis(host='140.143.227.206',port=,password='')
Session(app) @app.route('/login')
def login():
session['user'] = 'alex'
return 'asdfasfd' @app.route('/home')
def index():
print(session.get('user')) return '...' if __name__ == '__main__':
app.run()
- 原理:
- session数据保存到redis
session:随机字符串1:q23asifaksdfkajsdfasdf
session:随机字符串2:q23asifaksdfkajsdfasdf
session:随机字符串3:q23asifaksdfkajsdfasdf
session:随机字符串4:q23asifaksdfkajsdfasdf
session:随机字符串5:q23asifaksdfkajsdfasdf
- 随机字符串返回给用户。
随机字符串 源码:
from flask_session import RedisSessionInterface
25、判断是否是函数和方法
def func():
pass class Foo(object): def func(self):
pass # 执行方式一
# obj = Foo()
# obj.func() # 方法 # 执行方式二
# Foo.func() # 函数 from types import FunctionType,MethodType # obj = Foo()
# print(isinstance(obj.func,FunctionType)) # False
# print(isinstance(obj.func,MethodType)) # True print(isinstance(Foo.func,FunctionType)) # True
print(isinstance(Foo.func,MethodType)) # False
26、redis安装下载地址:https://github.com/MicrosoftArchive/redis/releases
redis-desktop manager 0.9.3.817.exe
27、code management system
1、注意设计表的时候,自增和外键的id类型要一致
2、work
内容详细:
- 代码统计 - 数据库连接池:
pip3 install DBUtils 注意:
- 使用数据库连接池
- 封装SQLHelper 作业:
. 功能完善
. BootStrap 模板
. 详细页面: http://127.0.0.1:5000/detail/1 -> 折线图
. 用户列表:
- 柱状图
- 表格
PS: select user_id,sum(line) from record group by user_id + 连表查询到用户姓名
28、review
第一部分:Flask
. 谈谈你对django和flask的认识? . Flask基础:
- 配置文件:反射+importlib
- 路由系统:
- 装饰器 @app.route()
- 参数:
- url
- endpoint
- methods
- 加装饰器
- endpoint默认是函数名
- functools.wraps(func) + functools.partial
- 写路由两种方式:
- 装饰器
- add_url_rule
- 自定义支持正则的URL
- session
- 蓝图
- 目录结构划分
- 前缀
- 特殊装饰器
. 上下文管理
- threading.local
- 为每个线程开辟空间,使得线程之间进行数据隔离。
- 应用:DBUtils中为每个线程创建一个数据库连接时使用。
- 面向对象特殊方法:
- getattr
- setattr
- delattr
- 偏函数
- 单例模式
- 请求上下文流程:
- 班级示例:
- 源码流程:
- __call__
- wsgi_app
- ctx = RequestContext(): 封装= 请求数据+空session
- ctx.push() : 将ctx传给LocalStack对象,LocalStack再将数据传给Local存储起来。
问题:Local中是如何存储?
__storage__ = {
:{}
}
问题:LocalStack作用?
__storage__ = {
:{stack:[ctx] }
}
- 视图函数:再次去获取
- 关闭 . 第三方组件:
. flask-session
. DBUtils
29、数据库&前端
. 什么是响应式布局?
@media属性
. MySQL数据库
- 引擎:
- innodb
- 支持事务
- 锁
- 行锁
- 表锁
- 示例:
- 终端:
begin;
select xx from xx for update;
commit;
- pymysql
cursor.execute('select * from xx for update')
- django
with trancation.automic():
models.User.objects.all().for_update()
- mysaim
- 不支持事务
- 锁
- 表锁
- 快
30、上下文管理
知识点
# by luffycity.com class Foo(object): def __str__(self):
return 'asdf' def __getattr__(self, item):
return "" def __getitem__(self, item):
return '' def __add__(self, other):
return other + obj = Foo() print(obj)
print(obj.x)
print(obj['x1']) print(obj + )
上下文
. 上下文管理:LocalProxy对象
. 上下文管理:
- 请求上下文:request/session
- App上下文: app/g
from flask import Flask,request,session app = Flask(__name__) @app.route('/index')
def index():
# . request是LocalProxy对象
# . 对象中有method、执行__getattr__
print(request.method)
# request['method']
# request + # . session是LocalProxy对象
# . LocalProxy对象的__setitem__
session['x'] = return "Index" if __name__ == '__main__':
app.run()
# app.__call__
# app.wsgi_app """
第一阶段:请求到来
将request和Session相关数据封装到ctx=RequestContext对象中。
再通过LocalStack将ctx添加到Local中。
__storage__ = {
:{'stack':[ctx(request,session)]}
}
第二阶段:视图函数中获取request或session
方式一:直接找LocalStack获取
from flask.globals import _request_ctx_stack
print(_request_ctx_stack.top.request.method) 方式二:通过代理LocalProxy(小东北)获取
from flask import Flask,request
print(request.method) """
详细
容详细:
. 上下文管理:LocalProxy对象
. 上下文管理:
- 请求上下文(ctx=RequestContext()):request/session
- App上下文(app_ctx=AppContext()): app/g - 程序启动:
两个Local:
local1 = { } local2 = { } 两个LocalStack:
_request_ctx_stack
_app_ctx_stack
- 请求到来
对数据进行封装:
ctx = RequestContext(request,session)
app_ctx = AppContext(app,g)
保存数据:
将包含了(app,g)数据的app_ctx对象,利用 _app_ctx_stack(贝贝,LocalStack())将app_ctx添加到Local中
storage = {
:{stack:[app_ctx(app,g),]}
}
将包含了request,session数据的ctx对象,利用_request_ctx_stack(刘淞,LocalStack()),将ctx添加到Local中
storage = {
:{stack:[ctx(request,session),]}
} - 视图函数处理: from flask import Flask,request,session,current_app,g app = Flask(__name__) @app.route('/index')
def index():
# 去请求上下文中获取值 _request_ctx_stack
request.method # 找小东北获取值
session['xxx'] # 找龙泰获取值 # 去app上下文中获取值:_app_ctx_stack
print(current_app)
print(g) return "Index" if __name__ == '__main__':
app.run()
app.wsgi_app - 结束
_app_ctx_stack.pop()
_request_ctx_stack.pop() 问题:
. Flask中g的生命周期?
. g和session一样吗?
. g和全局变量一样吗?
31、wtforms
基本使用
from flask import Flask,request,render_template,session,current_app,g,redirect
from wtforms import Form
from wtforms.fields import simple
from wtforms.fields import html5
from wtforms.fields import core from wtforms import widgets
from wtforms import validators app = Flask(__name__) class LoginForm(Form):
name = simple.StringField(
validators=[
validators.DataRequired(message='用户名不能为空.'),
# validators.Length(min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d')
],
widget=widgets.TextInput(),
render_kw={'placeholder':'请输入用户名'}
)
pwd = simple.PasswordField(
validators=[
validators.DataRequired(message='密码不能为空.'),
# validators.Length(min=8, message='用户名长度必须大于%(min)d'),
# validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}",
# message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符') ],
render_kw={'placeholder':'请输入密码'}
) @app.route('/login',methods=['GET','POST'])
def login():
if request.method == "GET":
form = LoginForm()
# print(form.name,type(form.name)) # form.name是StringField()对象, StringField().__str__
# print(form.pwd,type(form.pwd)) # form.pwd是PasswordField()对象,PasswordField().__str__
return render_template('login.html',form=form) form = LoginForm(formdata=request.form)
if form.validate():
print(form.data)
return redirect('https://www.luffycity.com/home')
else:
# print(form.errors)
return render_template('login.html', form=form)
import helper
class UserForm(Form):
city = core.SelectField(
label='城市',
choices=(),
coerce=int
)
name = simple.StringField(label='姓名') def __init__(self,*args,**kwargs):
super(UserForm,self).__init__(*args,**kwargs) self.city.choices=helper.fetch_all('select id,name from tb1',[],type=None) @app.route('/user')
def user():
if request.method == "GET":
#form = UserForm(data={'name':'alex','city':3}) #默认传入值,在编辑用户界面适合用a
form = UserForm()
return render_template('user.html',form=form) if __name__ == '__main__':
app.run()
login.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form method="post" novalidate>
<p>用户名:{{form.name}} {{form.name.errors[]}}</p>
<p>密码:{{form.pwd}} {{form.pwd.errors[]}} </p>
<p><input type="submit" value="提交" ></p>
</form>
</body>
</html>
32、wtforms的注册实例,数据库实时更新
出现数据库未实时更新的原因是如下,类的静态字段在实例化时只会导入一次,之后不作处理
若想实时更新,需要将静态字段放在__init__里,每次实例化的时候都导入一次
class Foo(object): country = helper.fetch_all('select id,name from tb1',[],type=None) def __init__(self):
self.name = '东北' print(Foo.country)
obj = Foo()
obj = Foo()
obj = Foo()
obj = Foo()
obj = Foo()
obj = Foo()
views.py
class RegisterForm(Form):
name = simple.StringField(
label='用户名',
validators=[
validators.DataRequired()
],
widget=widgets.TextInput(),
render_kw={'class': 'form-control'},
default='alex'
) pwd = simple.PasswordField(
label='密码',
validators=[
validators.DataRequired(message='密码不能为空.')
],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
) pwd_confirm = simple.PasswordField(
label='重复密码',
validators=[
validators.DataRequired(message='重复密码不能为空.'),
validators.EqualTo('pwd', message="两次密码输入不一致")
],
widget=widgets.PasswordInput(),
render_kw={'class': 'form-control'}
) email = html5.EmailField(
label='邮箱',
validators=[
validators.DataRequired(message='邮箱不能为空.'),
validators.Email(message='邮箱格式错误')
],
widget=widgets.TextInput(input_type='email'),
render_kw={'class': 'form-control'}
) gender = core.RadioField(
label='性别',
choices=(
(, '男'),
(, '女'),
),
coerce=int # int("")
)
city = core.SelectField(
label='城市',
choices=(
('bj', '北京'),
('sh', '上海'),
)
) hobby = core.SelectMultipleField(
label='爱好',
choices=(
(, '篮球'),
(, '足球'),
),
coerce=int
) favor = core.SelectMultipleField(
label='喜好',
choices=(
(, '篮球'),
(, '足球'),
),
widget=widgets.ListWidget(prefix_label=False),
option_widget=widgets.CheckboxInput(),
coerce=int,
default=[, ]
) @app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'GET':
form = RegisterForm()
return render_template('register.html', form=form) form = RegisterForm(formdata=request.form)
if form.validate():
print(form.data)
return redirect('https://www.luffycity.com/home') return render_template('register.html', form=form) import helper
class UserForm(Form):
city = core.SelectField(
label='城市',
choices=(),
coerce=int
)
name = simple.StringField(label='姓名') def __init__(self,*args,**kwargs):
super(UserForm,self).__init__(*args,**kwargs) #数据库实时更新
self.city.choices=helper.fetch_all('select id,name from tb1',[],type=None) @app.route('/user')
def user():
if request.method == "GET":
#form = UserForm(data={'name':'alex','city':})
form = UserForm()
return render_template('user.html',form=form) if __name__ == '__main__':
app.run()
register.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<form method="post" novalidate> {% for field in form %}
<p>{{field.label}}: {{field}} {{field.errors[]}}</p>
{% endfor %} <input type="submit" value="提交">
</form>
</body>
</html>
33、review
第一部分:Flask
. flask和django比较? . wsgi? . flask上下文理解?
两类:
请求上下文管理
应用上下文管理
流程:
请求到来:
将请求和session相关封装到ctx = RequestContext对象中。
将app和g封装到app_ctx = AppContext对象中。
再通过LocalStack对象将ctx、app_ctx封装到Local对象中。 问题:
Local是什么?作用?
LocalStack是什么?作用?
获取数据
通过LocalProxy对象+偏函数,调用LocalStack去Local中获取响应ctx、app_ctx中封装的值。 问题:
为什么要把 ctx=request/session app_ctx = app/g ?
答:因为离线脚本需要使用app_ctx。
请求结束:
调用LocalStack的pop方法,将ctx和app_ctx移除。 . threading.local . 偏函数 . 单例模式 . 问题:
before_request的执行时机(源码实现),在local之后,因为local需要request
34、review - database Mysql
. 数据库引擎 . 数据库授权 . 表结构设计:代码统计(教育机构,班级表结构设计) . SQL语句
https://www.cnblogs.com/wupeiqi/articles/5729934.html . 了解:https://www.cnblogs.com/wupeiqi/articles/5713323.html
- 视图
- 存储过程
- 触发器
- 函数
select max(id) from tb group by xid; . 索引
索引作用:加速查找+约束。
索引种类:
- 主键索引:加速查找、不重复、非空
- 唯一索引:加速查找、不重复
- 普通索引:加速查找
- 联合索引:加速查找
- 联合唯一索引:加速查找、不重复
PS:联合索引遵循最左前缀原则。 id name pwd email select * from tb where name='x'
select * from tb where name='x' and pwd=''
select * from tb where name='x' and pwd='' and email='xs' 名词:
- 覆盖索引:在索引文件中就可以把想要的数据得到。
select name from tb1;
- 索引合并:使用多个单列索引去查找数据。
35、类的知识点储备
1、对象可以被for循环
- form对象为什么可以被for循环?
答:变为可迭代对象。
class Foo(object): # def __iter__(self):
# return iter([,,]) #iter()为生成器 def __iter__(self):
yield
yield 2 #生成器也是迭代器的一种
yield obj = Foo() for item in obj:
print(item)
2、 new方法的返回值决定对象到底是什么?
class Bar(object):
pass class Foo(object): def __new__(cls, *args, **kwargs):
# return super(Foo,cls).__new__(cls,*args, **kwargs)
return Bar()
obj = Foo()
print(obj)
3、 metaclass
# . 类创建的两种方式 # class Foo(object):
# a1 =
# def func(self):
# return # Foo = type("Foo",(object,),{'a1':,'func':lambda self:}) # . 自定义type # class MyType(type):
# pass
#
# class Foo(object,metaclass=MyType):
# a1 =
# def func(self):
# return
#
# Foo = MyType("Foo",(object,),{'a1':,'func':lambda self:}) # 注意:metaclass作用是指定当前类由谁来创建。
分析
- 创建类时,先执行type的__init__。
- 类的实例化时,执行type的__call__,__call__方法的的返回值就是实例化的对象。
__call__内部调用:
- 类.__new__,创建对象
- 类.__init__,对象的初始化 class MyType(type):
def __init__(self,*args,**kwargs):
super(MyType,self).__init__(*args,**kwargs) def __call__(cls, *args, **kwargs):
obj = cls.__new__(cls) cls.__init__(obj,*args, **kwargs) return obj class Foo(object,metaclass=MyType):
a1 =
def __init__(self):
pass def __new__(cls, *args, **kwargs):
return object.__new__(cls) def func(self):
return # Foo是类
# Foo是MyType的一个对象 obj = Foo()
36、SQLAlchemy
SQLAlchemy,ORM框架。
作用:帮助我们使用类和对象快速实现数据库操作。 数据库:
- 原生:
- MySQLdb:py2
- pymysql:py2/py3
http://www.cnblogs.com/wupeiqi/articles/5095821.html - ORM框架
- SQLAlchemy
使用
SQLAlchemy使用:
参考:https://www.cnblogs.com/wupeiqi/articles/8259356.html . 单表操作
表:
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column
from sqlalchemy import Integer,String,Text,Date,DateTime
from sqlalchemy import create_engine Base = declarative_base() class Users(Base):
__tablename__ = 'users' id = Column(Integer, primary_key=True)
name = Column(String(), index=True, nullable=False) def create_all():
engine = create_engine(
"mysql+pymysql://root:123456@127.0.0.1:3306/s9day120?charset=utf8",
max_overflow=, # 超过连接池大小外最多创建的连接
pool_size=, # 连接池大小
pool_timeout=, # 池中没有线程最多等待的时间,否则报错
pool_recycle=- # 多久之后对线程池中的线程进行一次连接的回收(重置)
) Base.metadata.create_all(engine) def drop_all():
engine = create_engine(
"mysql+pymysql://root:123456@127.0.0.1:3306/s9day120?charset=utf8",
max_overflow=, # 超过连接池大小外最多创建的连接
pool_size=, # 连接池大小
pool_timeout=, # 池中没有线程最多等待的时间,否则报错
pool_recycle=- # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
Base.metadata.drop_all(engine) if __name__ == '__main__':
create_all() 行:
示例:
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from models import Users engine = create_engine(
"mysql+pymysql://root:123456@127.0.0.1:3306/s9day120?charset=utf8",
max_overflow=, # 超过连接池大小外最多创建的连接
pool_size=, # 连接池大小
pool_timeout=, # 池中没有线程最多等待的时间,否则报错
pool_recycle=- # 多久之后对线程池中的线程进行一次连接的回收(重置)
)
SessionFactory = sessionmaker(bind=engine) # 根据Users类对users表进行增删改查
session = SessionFactory() # . 增加
# obj = Users(name='alex')
# session.add(obj)
# session.commit() # session.add_all([
# Users(name='小东北'),
# Users(name='龙泰')
# ])
# session.commit() # . 查
# result = session.query(Users).all()
# for row in result:
# print(row.id,row.name) # result = session.query(Users).filter(Users.id >= )
# for row in result:
# print(row.id,row.name) # result = session.query(Users).filter(Users.id >= ).first()
# print(result) # .删
# session.query(Users).filter(Users.id >= ).delete()
# session.commit() # .改
# session.query(Users).filter(Users.id == ).update({Users.name:'东北'})
# session.query(Users).filter(Users.id == ).update({'name':'小东北'})
# session.query(Users).filter(Users.id == ).update({'name':Users.name+"DSB"},synchronize_session=False)
# session.commit() session.close()
常用
# ############################## 其他常用 ###############################
# . 指定列
# select id,name as cname from users;
# result = session.query(Users.id,Users.name.label('cname')).all()
# for item in result:
# print(item[],item.id,item.cname)
# . 默认条件and
# session.query(Users).filter(Users.id > , Users.name == 'eric').all()
# . between
# session.query(Users).filter(Users.id.between(, ), Users.name == 'eric').all()
# . in
# session.query(Users).filter(Users.id.in_([,,])).all()
# session.query(Users).filter(~Users.id.in_([,,])).all()
# . 子查询
# session.query(Users).filter(Users.id.in_(session.query(Users.id).filter(Users.name=='eric'))).all()
# . and 和 or
# from sqlalchemy import and_, or_
# session.query(Users).filter(Users.id > , Users.name == 'eric').all()
# session.query(Users).filter(and_(Users.id > , Users.name == 'eric')).all()
# session.query(Users).filter(or_(Users.id < , Users.name == 'eric')).all()
# session.query(Users).filter(
# or_(
# Users.id < ,
# and_(Users.name == 'eric', Users.id > ),
# Users.extra != ""
# )).all() # . filter_by
# session.query(Users).filter_by(name='alex').all() # . 通配符
# ret = session.query(Users).filter(Users.name.like('e%')).all()
# ret = session.query(Users).filter(~Users.name.like('e%')).all() # . 切片
# result = session.query(Users)[:] # .排序
# ret = session.query(Users).order_by(Users.name.desc()).all()
# ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all() # . group by
from sqlalchemy.sql import func # ret = session.query(
# Users.depart_id,
# func.count(Users.id),
# ).group_by(Users.depart_id).all()
# for item in ret:
# print(item)
#
# from sqlalchemy.sql import func
#
# ret = session.query(
# Users.depart_id,
# func.count(Users.id),
# ).group_by(Users.depart_id).having(func.count(Users.id) >= ).all()
# for item in ret:
# print(item) # .union 和 union all
"""
select id,name from users
UNION
select id,name from users;
"""
# q1 = session.query(Users.name).filter(Users.id > )
# q2 = session.query(Favor.caption).filter(Favor.nid < )
# ret = q1.union(q2).all()
#
# q1 = session.query(Users.name).filter(Users.id > )
# q2 = session.query(Favor.caption).filter(Favor.nid < )
# ret = q1.union_all(q2).all()
37、SQLAlchemy
无用之flask学习的更多相关文章
- [ZHUAN]Flask学习记录之Flask-SQLAlchemy
From: http://www.cnblogs.com/agmcs/p/4445583.html 各种查询方式:http://www.360doc.com/content/12/0608/11/93 ...
- Flask 学习目录
Flask 学习目录 Flask 的学习过程是一个了解如何从单个模块搭建一个 Web 框架的过程. Python.Flask 的安装和设置 简单的 Hello World 程序 使用 Jinjia2 ...
- Python Flask学习笔记之模板
Python Flask学习笔记之模板 Jinja2模板引擎 默认情况下,Flask在程序文件夹中的templates子文件夹中寻找模板.Flask提供的render_template函数把Jinja ...
- Python Flask学习笔记之Hello World
Python Flask学习笔记之Hello World 安装virtualenv,配置Flask开发环境 virtualenv 虚拟环境是Python解释器的一个私有副本,在这个环境中可以安装私有包 ...
- Flask学习-Wsgiref库
一.前言 前面在Flask学习-Flask基础之WSGI中提到了WerkZeug,我们知道,WerkZeug是一个支持WSGI协议的Server,其实还有很多其他支持WSGI协议的Server.htt ...
- Flask 学习篇二:学习Flask过程中的记录
Flask学习笔记: GitHub上面的Flask实践项目 https://github.com/SilentCC/FlaskWeb 1.Application and Request Context ...
- Flask 学习(四)静态文件
Flask 学习(四)静态文件 动态 web 应用也需要静态文件,一般是 CSS 和 JavaScript 文件.理想情况下你的服务器已经配置好提供静态文件的服务. 在开发过程中, Flask 也能做 ...
- Flask 学习(三)模板
Flask 学习(三)模板 Flask 为你配置 Jinja2 模板引擎.使用 render_template() 方法可以渲染模板,只需提供模板名称和需要作为参数传递给模板的变量就可简单执行. 至于 ...
- Flask 学习(一)概述及安装
Flask 概述及安装 Flask 简介 Flask是一个使用 Python 编写的轻量级 Web 应用框架.其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2 . 官方网址 ...
随机推荐
- Vue + Element UI 实现权限管理系统 (功能组件封装)
组件封装 为了避免组件代码的臃肿,这里对主要的功能部件进行封装,保证代码的模块化和简洁度. 组件结构 组件封装重构后,试图组件结构如下图所示 代码一览 Home组件被简化,包含导航.头部和主内容三个组 ...
- POJ 2002 Squares 几何, 水题 难度: 0
题目 http://poj.org/problem?id=2002 题意 已知平面内有1000个点,所有点的坐标量级小于20000,求这些点能组成多少个不同的正方形. 思路 如图,将坐标按照升序排列后 ...
- django搭建博客
https://andrew-liu.gitbooks.io/django-blog/content/index.html
- MySQL - exists与in的用法
[1]exists 对外表用loop逐条查询,每次查询都会查看exists的条件语句. 当 exists里的条件语句能够返回记录行时(无论记录行是多少,只要能返回),条件就为真 , 返回当前loop到 ...
- 第一篇 入门必备 (Android学习笔记)
第一篇 入门必备 第1章 初识Android 第2章 搭建你的开发环境 第3章 创建第一个程序--HelloWorld 第4章 使用Android工具 ●Android之父 Android安迪·罗 ...
- VSTO:使用C#开发Excel、Word【2】
<Visual Studio Tools for Office: Using C# with Excel, Word, Outlook, and InfoPath >——By Eric C ...
- 深入理解java虚拟机---java虚拟机内存管理(六)
java虚拟机栈的理解 虚拟机栈就是我们所熟知的栈内存,栈内存属于线程独有的.而在栈内存中的局部变量表中存储的引用类型只是存储对象的内存地址.对象的创建在堆内存中,即对象在线程共享区中. 局部变量表: ...
- 开发框架DevExtreme发布v18.2.4|附下载
DevExtreme Complete Subscription是性能最优的 HTML5,CSS 和 JavaScript 移动.Web开发框架,可以直接在Visual Studio集成开发环境,构建 ...
- python中的import,reload,以及__import__
python中的import,reload,以及__import__ 分类: UNIX/LINUX C/C++LINUX/UNIX shellpython2013-04-24 20:294536人阅读 ...
- Oracle触发器报错
Oracle编写触发器时,执行时候报错,错误提示信息如上图所示,类似这种一般都是触发器语句有语法错误.重新审核语句,并再次执行. 如果用的是pl/sql developer的话,可以查看当前用户下的对 ...