[Python自学] Flask框架 (1) (Flask介绍、配置、Session、路由、请求和响应、Jinjia2模板语言、视图装饰器)
oldboy:s9day114
参考博客:https://www.cnblogs.com/wupeiqi/articles/7552008.html
一、Flask简介
1.安装Flask
pip install flask
Flask:
- 短小精悍、可扩展性强的一个Web框架。
- 依赖wsgi:werkzurg(安装Flask时,这些依赖也会被自动安装)
2.Werkzurg服务器
单独使用Werkzurg服务器:
from werkzeug.wrappers import Request, Response
from werkzeug.serving import run_simple @Request.application
def run(request):
return Response('Hello World') if __name__ == '__main__':
run_simple('localhost', 4000, run)
3.实现简单页面请求
from flask import Flask # 创建一个Flask实例,参数是为这个实例定义一个名字,一般以__name__来指定
app = Flask(__name__) # 利用装饰器,绑定路由
@app.route('/index')
def index():
return "HelloWorld" if __name__ == '__main__':
# 开始运行
app.run()
二、简单使用Flask
1.默认模板目录
Flask默认使用templates作为模板目录。当我们要返回html页面时,默认去该文件夹下找模板文件:
from flask import Flask, render_template # 创建一个Flask实例,参数是为这个实例定义一个名字,一般以__name__来指定
app = Flask(__name__) @app.route('/login')
def login():
return render_template('login.html') if __name__ == '__main__':
# 开始运行
app.run()
2.修改模板目录
在Django中,我们是在setting配置文件中去修改。而在Flask中,我们可以以以下方式修改:
# 创建一个Flask实例,参数是为这个实例定义一个名字,一般以__name__来指定
app = Flask(__name__, template_folder='mytempfile')
我们查看一下Flask类的构造函数:
def __init__(
self,
import_name,
static_url_path=None,
static_folder='static',
static_host=None,
host_matching=False,
subdomain_matching=False,
template_folder='templates',
instance_path=None,
instance_relative_config=False,
root_path=None
):
可以看到,默认的模板目录参数就是"templates"。
3.Flask接受POST请求、获取请求数据
在Flask中,默认只允许接收GET请求,如果我们先接收POST请求,则需要设置。
在视图函数中获取请求数据时,我们需要导入request模块,而不是通过参数传递request。这是个Django不同的地方。
from flask import Flask, render_template, request app = Flask(__name__) @app.route('/login', methods=['GET', 'POST'])
def login():
# 这里的请求数据和Django中不一样,Flask是通过上下文来管理的,request不是参数,而是导入的模块
if request.method == 'GET':
pass if request.method == 'POST':
pass if __name__ == '__main__':
# 开始运行
app.run()
4.获取GET数据和POST数据
视图函数:
from flask import Flask, render_template, request, redirect app = Flask(__name__) @app.route('/login', methods=['GET', 'POST'])
def login():
# 这里的请求数据和Django中不一样,Flask是通过上下文来管理的,request不是参数,而是导入的模块
if request.method == 'GET':
# request.args对应django中的request.GET
# request.args.get('user)
return render_template('login.html')
if request.method == 'POST':
user = request.form.get('user')
pwd = request.form.get('pwd')
if user == 'leokale' and pwd == '':
return redirect('/index')
else:
return render_template('login.html', error="用户名或密码错误")
# 也可以传多个值(使用字典),但和Django不一样的地方是要解包
# return render_template('login.html', **{"error": "用户名或密码错误"}) @app.route('/index')
def index():
return '<h2>欢迎登录</h2>' if __name__ == '__main__':
# 开始运行
app.run()
注意几个和django框架不一样的地方:
1)需要在装饰器中传入methods参数,用来允许接收哪些请求
2)request.args和request.form分别对应django中的request.GET和request.POST
3)redirect跳转和django基本一致
4)模板渲染回传给页面的参数,可以单独传一个,也可以使用字典拆包的形式传入多个(django中参数为字典)
对应html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<h1>登录页面</h1>
<form method="POST">
<input type="text" name="user"/>
<input type="password" name="pwd"/>
<input type="submit" value="登录"/>{{error}}
</form> </body> </html>
5.静态文件
Flask中静态文件默认放在static目录下,如果要修改,也是修改Flask实例化时的参数。
app = Flask(__name__,static_folder='mystatic')
只需要将目录名和这个参数值对应上即可。
但是注意,我们在html中写图片请求连接时使用的url默认是和static_folder一致的:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>INDEX</title>
</head>
<body>
<h2>欢迎访问</h2>
<img src="/mystatic/111.png">
</body>
</html>
但实际上,我们也可以通过一个参数来修改:
app = Flask(__name__, static_folder='mystatic', static_url_path='/vvvvv')
我们将其修改为'/vvvvv',此时html中也要修改为'/vvvvv':
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>INDEX</title>
</head>
<body>
<h2>欢迎访问</h2>
<img src="/vvvvv/111.png">
</body>
</html>
6.Flask中的session
from flask import Flask, render_template, request, redirect, session app = Flask(__name__, static_folder='mystatic', static_url_path='/vvvvv') @app.route('/login', methods=['GET', 'POST'])
def login():
# 这里的请求数据和Django中不一样,Flask是通过上下文来管理的,request不是参数,而是导入的模块
if request.method == 'GET':
# request.args对应django中的request.GET
# request.args.get('user)
return render_template('login.html')
if request.method == 'POST':
user = request.form.get('user')
pwd = request.form.get('pwd')
if user == 'leokale' and pwd == '':
session['user'] = user
return redirect('/index')
else:
return render_template('login.html', error="用户名或密码错误")
# 也可以传多个值(使用字典),但和Django不一样的地方是要解包
# 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()
Flask中session的使用和django很类似,但Flask中的session是导入的模块。
注意,Flask的session默认是保存在加密的cookie中的,可以参照django相关的介绍:https://www.cnblogs.com/leokale-zz/p/12082478.html
这里要使用加密的cookie,又需要设置MD5加盐中的盐,否则会报错:
RuntimeError: The session is unavailable because no secret key was set. Set the secret_key on the application to something unique and secret.
127.0.0.1 - - [20/Jan/2020 00:27:46] "POST /login HTTP/1.1" 500 -
我们需要在代码中加上加密设置:
app = Flask(__name__, static_folder='mystatic', static_url_path='/vvvvv')
app.secret_key = "sndjkfn" # MD5加密的盐
此时就可以使用加密cookie来保存session了。
三、Flask的配置文件
1.通过importlib导入指定模块
在setting.py文件中有如下代码:
class Foo(object):
DEBUG = True
TEST = False
我们如果在其他模块中通过importlib导入Foo类,获取其中的DEBUG和TEST的值:
import importlib # 给定类所处模块
path = 'setting.Foo' # 分割path,获取模块名和类名
(m, c) = path.rsplit('.', maxsplit=1)
# 导入模块
m = importlib.import_module(m)
# 获取类
cls = getattr(m, c) # 遍历类中的属性,我们要获取的属性是大写的,所以使用isupper判断
for key in dir(cls):
if key.isupper():
print(key, getattr(cls, key))
这样,我们就使用importlib库动态的导入模块,并获取了其中的Foo类,以及其中的类属性。
Flask的配置文件也是通过这种方式来加载的(很多框架的配置文件都是通过这种方式加载)。
2.Flask默认的配置信息
Flask默认的配置信息:
from flask import Flask, request, render_template app = Flask(__name__)
# app.config获取所有配置信息
print(app.config)
# 可以通过这种方式修改
app.config['DEBUG'] = True
app.config配置内容:
{
'ENV': 'development',
'DEBUG': False,
'TESTING': False,
'PROPAGATE_EXCEPTIONS': None,
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
'SECRET_KEY': None,
'PERMANENT_SESSION_LIFETIME': datetime.timedelta(days = 31), # 默认session的保存周期(对应加密cookie的过期时间)
'USE_X_SENDFILE': False,
'SERVER_NAME': None,
'APPLICATION_ROOT': '/',
'SESSION_COOKIE_NAME': 'session', # 加密session写到cookie中的key,默认叫session
'SESSION_COOKIE_DOMAIN': None,
'SESSION_COOKIE_PATH': None,
'SESSION_COOKIE_HTTPONLY': True,
'SESSION_COOKIE_SECURE': False,
'SESSION_COOKIE_SAMESITE': None,
'SESSION_REFRESH_EACH_REQUEST': True, # 是否在每次访问的时候刷新session过期时间(即从最后一次访问开始计算过期时间),如果为False,则过期时间时从设置session开始算
'MAX_CONTENT_LENGTH': None,
'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(seconds = 43200),
'TRAP_BAD_REQUEST_ERRORS': None,
'TRAP_HTTP_EXCEPTIONS': False,
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http',
'JSON_AS_ASCII': True,
'JSON_SORT_KEYS': True,
'JSONIFY_PRETTYPRINT_REGULAR': False,
'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None,
'MAX_COOKIE_SIZE': 4093
}
3.使用自定义配置文件
使用以下方式为其指定一个自定义配置文件:
from flask import Flask, request, render_template app = Flask(__name__)
# app.config获取DEBUG,默认为False
print(app.config['DEBUG'])
# 通过from_object绑定一个类作为配置对象,其中DEBUG为True
app.config.from_object("setting.Myconfig")
# 再次获取DEBUG,为True
print(app.config['DEBUG'])
这里使用setting模块中的Myconfig类作为其配置文件。from_object源码就是使用的1.中的方式对setting模块进行导入,然后获取Myconfig中的属性值。
setting模块中,我们还可以根据需求,使用多个类来区分不同场景下的配置:
class BaseConfig(object):
# DEV和PROD场景下,相同的配置
XXX = False # 开发环境下的配置
class DevConfig(BaseConfig):
DEBUG = True
TEST = True # 生产环境下的配置
class ProdConfig(BaseConfig):
DEBUG = False
TEST = False
在使用的时候,我们只需要根据场景切换即可:
# 开发环境使用DevConfig配置
app.config.from_object("setting.DevConfig") # 生产部署环境使用ProdConfig配置
app.config.from_object("setting.ProdConfig")
4.其他配置文件的使用
除了3.中所描述的,使用模块中的类来作为配置。还有以下几种方式:
1)from_pyfile
app.config.from_pyfile("setting.py")
例如:
# settings.py DEBUG = True
TEST = False
2)from_envvar
app.config.from_envvar("FLASK_CONFIG_FILE")
例如在Linux下配置环境变量:
export FLASK_CONFIG_FILE='/path/to/config/file'
环境变量的值为python文件(不一定是.py结尾的文件,但内容要是 DEBUG = True这种Python代码格式)名称,内部调用from_pyfile方法。
3)from_json
app.config.from_json("json文件名称")
JSON文件名称,必须是json格式,因为内部会执行json.loads。
4)from_mapping
app.config.from_mapping({'DEBUG':True})
参数为一个字典。
四、Flask的路由系统
在Flask中,路由是通过装饰器加到每个视图函数的:
from flask import Flask, request, render_template app = Flask(__name__) @app.route('/index', methods=['GET', 'POST'])
def hello_world():
if request.method == 'GET':
return render_template('index.html') if __name__ == '__main__':
app.run()
1.@app.route中的endpoint
@app.route中的endpoint参数,就相当于django中的name参数,用来反向生成URL。
from flask import Flask, request, render_template, url_for app = Flask(__name__) @app.route('/index', methods=['GET', 'POST'], endpoint='n1')
def hello_world():
print(url_for('n1')) # 打印/index
if request.method == 'GET':
return render_template('index.html') if __name__ == '__main__':
app.run()
其中的url_for相当于django中的reverse函数,用来利用endpoint反向生成url。
注意:如果我们不指定endpoint,则endpoint默认等于视图函数名,这里即"hello_world"。url_for("hello_world")即为"/index"。
2.动态路由
Flask的路由中,我们可以使用动态参数。
from flask import Flask, request, render_template app = Flask(__name__) @app.route('/index/<int:nid>', methods=['GET', 'POST'])
def hello_world(nid):
print(nid)
if request.method == 'GET':
return render_template('index.html') if __name__ == '__main__':
app.run()
Flask是django使用动态路由的方式不同,在django中,动态路由是这样的:'/index/(?P<nid>\d+)'。
注意:<int:nid>中,int表示动态参数的类型,我们的视图函数接收的参数nid为整形,如果不写,则默认为字符串。
动态参数的类型除了有int以外,还有以下几种类型:
@app.route('/user/<username>') # 字符串
@app.route('/post/<int:post_id>') # 整数
@app.route('/post/<float:post_id>') # 浮点数
@app.route('/post/<path:path>') # 路径类型
@app.route('/post/<uuid:uuid>') # UUID
在使用动态路由的时候,也可以使用方向生成url:
url_for("hello_world",nid=777) # 生成/index/777
五、Flask的请求数据
在Flask中,视图函数没有request参数。Flask中的request是直接导入使用的(上下文管理)。
from flask import Flask, request
在视图函数中,可以直接使用request:
#例如请求: http://127.0.0.1:5000/index/2019-03?name=leo
#以下request的属性值为:
request.method # 请求类型
request.args # GET请求的数据
request.args.get('user')
request.form # POST请求的数据
request.form.get('user')
request.values
request.cookies # Cookie数据
request.headers
"""
Accept: text/html, application/xhtml+xml, image/jxr, */*
...
Connection: Keep-Alive
"""
request.path # 请求的url "/index/2019-12"
request.full_path # "/index/2019-12?name=leo" 包含query
request.script_root # ""
request.url # "http://127.0.0.1:5000/index/2019-12?name=leo"
request.base_url # "http://127.0.0.1:5000/index/2019-12"
request.url_root #"http://127.0.0.1:5000/"
request.host_url # "http://127.0.0.1:5000/"
request.host # "127.0.0.1:5000"
request.files
obj = request.files['file_name']
obj.save('/var/www/uploads/' + secure_filename(f.filename)) #上传文件
六、Flask的响应
1.Flask的几种常用响应
在Flask中,常用的响应方式有以下几种:
1)响应字符串
return "HelloWorld" # 相当于django中的HttpResponse
2)响应json数据
from flask import jsonify
return jsonify({'k':'v'})
# 或 return json.dumps({'k':'v'})
3)响应渲染模板
from flask import render_template
return render_template('login.html') # 相当于django中的render
4)响应重定向
from flask import redirect
return redirect('/index')
2.设置响应头
在Flask中如何设置响应头,特别是响应字符串的时候,无法设置响应头。
from flask import make_response # 使用响应对象来封装要返回的字符串
obj=make_response("hello world")
# obj=make_response(render_template('index.html')) # 设置响应头的字段xxx
obj.headers['xxx']=''
# 设置cookie
obj.set_cookie('key','value') # 返回obj
return obj
七、jinjia2模板语言
1.循环与字典取值
Jinjia2模板语言和django自带的模板语言很相似,但功能更加强大。语法比较接近于Python。
视图函数代码:
from flask import Flask, request, render_template app = Flask(__name__) USER_INFO = {
1: {'name': 'Leo', 'age': 32, 'gender': 'male'},
2: {'name': 'Jane', 'age': 33, 'gender': 'female'},
3: {'name': 'Jake', 'age': 12, 'gender': 'male'},
4: {'name': 'Alex', 'age': 45, 'gender': 'male'},
5: {'name': 'Lilei', 'age': 77, 'gender': 'female'}
} @app.route('/users', methods=['GET', 'POST'])
def user_list():
if request.method == 'GET':
return render_template('users.html', user_list=USER_INFO) if __name__ == '__main__':
app.run()
我们创建了一个字典,并返回给模板进行渲染。
html模板代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Users</title>
</head>
<body>
<h2>用户列表</h2>
<table>
<thead>
<tr>
<th>ID</th>
<th>名字</th>
<th>岁数</th>
<th>性别</th>
</tr>
</thead>
<tbody>
{% for k,v in user_list.items() %}
<tr>
<td>{{ k }}</td>
<td>{{ v.name }}</td>
<td>{{ v.age }}</td>
<td>{{ v.gender }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
可以看到,使用for循环的方法和django模板语言是一样的。
注意,user_list.items()这个括号一定要有,这和Python一样。
在取值的时候,使用{{ v.name }}这种形式可以获取字典中字段的值。在Jinjia2中,还可以使用{{ v.get('name','默认') }}以及{{ v['name'] }}的形式来取值,和Python基本一致。
2.数组取值
除了1.中所述的用法,这里补充一些用法:
{{ list.0 }} # django模板语言风格取index为0的元素
{{ list[0] }} # python风格取index为0的元素
列表按索引取元素,两种风格都支持。
2)XSS问题
当数据为html标签时:
# data = "<input type='text' />"
{{ data }} # 显示字符串<input type='text' />
{{ data|safe }} # 显示input标签元素
Flask默认帮我们做了XSS,要返回标签格式的字符串,在模板语言中使用"|safe"。
当然,也可以在后端python中使用Markup来传递安全的标签字符串(类似django中的mark_safe):
from flask import Markup Markup("<input type='text' />") # 相当于django中的mark_safe
3.传递函数引用并调用
当我们在视图函数中传递给模板的参数是一个函数引用时:
例如:
def func(arg):
return arg**2 # 视图函数index
def index():
return render_template("index.html",func=func) #将func函数引用传递到模板
Jinjia2模板语言调用func:
{{ func(6) }} # 显示36
虽然Jinjia2可以方便的调用函数(比django模板语言方便)。但是如果有多个页面都要调用这个函数,则每个对应的视图函数都要将该函数的引用传递给模板。则可以使用全局的模板函数(类似django中定义模板函数)。
4.全局模板函数
1)@app.template_global()装饰器
使用@app.template_global()装饰器,可以将自定义函数变为全局的模板函数,直接可以在模板语言中调用。
@app.template_global()
def my_add(a,b)
return a+b
在模板中调用:
{{ my_add(1,9) }} # 显示10
2)@app.template_filter()装饰器
还有另一种装饰器@app.template_filter(),和template_global差不多,但是在模板语言中的调用方式不同:
{{ 1|my_add(9) }} # 显示10
这两种方式在Jinjia2中其实效果差不多。
我们可以这样理解
@app.template_global装饰的模板函数,对应的是django中 @register.simple_tag装饰的模板函数(但由于django模板语言在调用模板函数时,不是使用括号来包裹参数,所以无法作为if的条件)。
@app.template_filter装饰的模板函数,对应的是django中 @register.filter装饰的模板函数(形式差不多)
由于Jinjia2中传参的方式和python很像,所以两种方式都可以作为if的条件。如下:
# tempalte_global装饰的my_add
{% if my_add(1,9) %}
{% endif %} # tempalte_filter装饰的my_add
{% if 1|my_add(9) %}
{% endif %}
5.定义宏(函数)
Jinjia2模板语言支持定义宏(其实就是定义函数):
<!-- 使用macro定义一个宏(相当于python的def定义函数) -->
{% macro my_func(name,type='text',value='') %}
<input type="{{ type }}" name="{{ name }}" value="{{ value }}"/>
{% endmacro %}
<!-- macro定义的函数,默认是不执行的,需要手动调用 -->
{{ my_func('n1') }}
{{ my_func("n2",type="button",value='确定') }}
也就是说Jinjia2不仅可以支持在后台Flask中定义全局函数,还可以使用macro直接在模板中定义函数。
八、使用装饰器给视图函数添加验证功能
1.简单装饰器的问题
# 最简单的装饰器
def auth(func):
def inner(*args, **kwargs):
ret = func(*args, **kwargs)
return ret
return inner # index函数使用了auth装饰器
@auth
def index():
print('index') # index2函数没有使用auth装饰器
def index2():
print('index2') if __name__ == '__main__':
print(index.__name__) # 打印inner
print(index2.__name__) # 打印index2
可以看到,当一个函数使用了简单装饰器后,打印其函数名,编程了装饰器中的inner。
在这种情况下,会影响我们使用反向生成url的功能,即url_for(视图函数名)。
2.使用functools.wraps
# 导入functools中的wraps
from functools import wraps def auth(func):
# 使用wraps装饰器
@wraps(func)
def inner(*args, **kwargs):
ret = func(*args, **kwargs)
return ret return inner @auth
def index():
print('index') if __name__ == '__main__':
print(index.__name__) # 打印index
使用了functools的wraps装饰器,实际上运行index函数时,还是调用的是inner,但是wraps帮我们将index函数的元信息封装到了inner函数中。
3.使用auth装饰器实现登录验证
from flask import Flask, request, render_template, redirect, session, url_for app = Flask(__name__)
# 使用密码盐(session默认保存在加密cookie中,必须设置密码盐)
app.secret_key = 'snjdkfnjsk' USER_INFO = {
1: {'name': 'Leo', 'age': 32, 'gender': 'male'},
2: {'name': 'Jane', 'age': 33, 'gender': 'female'},
3: {'name': 'Jake', 'age': 12, 'gender': 'male'},
4: {'name': 'Alex', 'age': 45, 'gender': 'male'},
5: {'name': 'Lilei', 'age': 77, 'gender': 'female'}
} from functools import wraps # 认证用户是否登录
def auth(func):
@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('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
user = request.form.get('username')
pwd = request.form.get('password')
# 用户名密码正确,则将用户名写到session中(默认保存在加密cookie中,默认cookie过期时间为31天)
if user == 'leokale' and pwd == '':
session['user'] = user
# 登录成功,跳转到users页面
return redirect('/users')
# 登录失败,返回login页面,并显示用户名或密码错误
return render_template('login.html', error='用户名或密码错误') # users页面,使用auth装饰器进行登录验证
@app.route('/users', methods=['GET', 'POST'])
@auth
def user_list():
if request.method == 'GET':
return render_template('users.html', user_list=USER_INFO) if __name__ == '__main__':
app.run()
1)实现验证装饰器,必须使用functools.wraps装饰器,保证视图函数名不变
2)在auth装饰器中实现验证登录功能(检查session中user是否存在)
3)将auth装饰器应用到需要验证的页面
♌
[Python自学] Flask框架 (1) (Flask介绍、配置、Session、路由、请求和响应、Jinjia2模板语言、视图装饰器)的更多相关文章
- flask模板语言,装饰器,路由及配置
1.模板语言jinja2 Flask中默认的模板语言是Jinja2 1.0 模板传参 from flask import Flask,render_template app = Flask(__nam ...
- Flask 模板语言,装饰器
Jinja2模板语言 # -*- coding: utf-8 -*- from flask import Flask, render_template, request, redirect, ...
- python三大web框架Django,Flask,Flask,Python几种主流框架,13个Python web框架比较,2018年Python web五大主流框架
Python几种主流框架 从GitHub中整理出的15个最受欢迎的Python开源框架.这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,爬虫等. Django: Python We ...
- Python的Django框架中的URL配置与松耦合
Python的Django框架中的URL配置与松耦合 用 python 处理一个文本时,想要删除其中中某一行,常规的思路是先把文件读入内存,在内存中修改后再写入源文件. 但如果要处理一个很大的文本,比 ...
- python 之 Django框架(Django框架简介、视图装饰器、request对象、Response对象)
12.33 Django框架简介: MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器( ...
- flask之jinjia2模板语言
flask_jinjia2.py ''' flask中的jinjia2模板语言(和django中模板类似): (1)模板变量{{ }} (2)模板标签{% %} ①for循环遍历 {% for foo ...
- Python:高级主题之(属性取值和赋值过程、属性描述符、装饰器)
Python:高级主题之(属性取值和赋值过程.属性描述符.装饰器) 背景 学习了Javascript才知道原来属性的取值和赋值操作访问的“位置”可能不同.还有词法作用域这个东西,这也是我学习任何一门语 ...
- ThinkPHP5.0框架开发--第6章 TP5.0 请求和响应
ThinkPHP5.0框架开发--第6章 TP5.0 请求和响应 第6章 TP5.0 请求和响应 ===================================== 上次复习 1.新建控制器 ...
- Flask框架(一):介绍与环境搭建
1.Flask介绍 Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架. Flask 本身相当于一个内核, ...
随机推荐
- Centos 7 下部署集群式阿波罗
apollo工作原理 用户通过浏览器登录Portal管理界面 >> 通过Admin server对配置进行修改 >> 应用程序主动向config server配置注意:Port ...
- mybatis 源码分析中的知识点
1. resultMap 和 resultType 之间的优劣 resultMap: 在联合查询的时候, 可以不用写Join (因为在resultMap 的定义里面已经写了这些东西了<asso ...
- 低功耗设计技术--Multi VDD--Level shifter
本文转自:自己的微信公众号<集成电路设计及EDA教程> 前面的推文中我们分别介绍了低功耗设计中的Multi-VDD技术以及门控电源技术.在实际的低功耗设计中,门控电源技术中也常常结合Mul ...
- 为什么建议使用Guid结构体做为数据库及排序时的主键
在.net2.0中,Guid结构体表示一个全局唯一标识符,是一个在生成时就可以肯定为全世界唯一的16字节值.Guid在数据库中通常可以作为各种排序的主键.比如 public class Company ...
- CCF_ 201312-3_最大的矩形
遍历数组中每一元素,左右延伸得出宽度. #include<iostream> #include<cstdio> using namespace std; int main() ...
- Mysql 5.7.18:主从复制,io优化
#目录 #挂盘#时间同步#master节点,进行如下操作: #下载安装 #初始化 #配置文件 #开机启动 #服务启动 #初始数据库#slave节点,进行如下操作: #下载安装 #初始化 #配置文件 # ...
- 题解 NOI2004【郁闷的出纳员】
\[ Preface \] 之前用 treap 打,交了四遍才过. 自学了 fhq treap 后,才意识到是一道 fhq treap 板子题,直接码上,一遍就过. 本题解提供的是 fhq treap ...
- 题解 bzoj3688【折线统计】
考虑 \(dp\) . 首先把所有节点按 \(x\) 从小到大排序是很有必要的. 记 f[i][j][0] 表示满足以第 \(i\) 个节点做折线结尾,选取的点集 \(S\) 满足 \(f(S)=j\ ...
- c++ 初始化列表和构造函数初始化区别
先上代码 #include <iostream> class MyContruct { public: MyContruct() { std::cout << "My ...
- Classmethod and Staticmethod - Python 类方法 和 静态方法
classmethod and staticmethod classmethod 的是一个参数是类对象 cls (本类,或者子类), 而不是实例对象 instance (普通方法). classmet ...