Flask-论坛开发-1-基础知识
对Flask感兴趣的,可以看下这个视频教程:http://study.163.com/course/courseLearn.htm?courseId=1004091002
1. 第一个 flask 程序
# 从 flask 框架中导入 flask 类
from flask import Flask
# 用 flask() 初始化一个 flask 对象,并赋给 app
# 需传递一个参数 __name__
# 1. 方便 flask 框架去寻找资源
# 2. 方便 flask 插件去定位问题
app = Flask(__name__)
# @app.route() 是一个装饰器,作用是对 url 与 视图函数进行映射
# 将 `/` 映射到 hello_world() 函数上
# 即用户访问 http://example:80/ 的时候,用 hello_world() 函数来响应
@app.route('/')
def hello_world():
return 'Hello World!'
# 如果当前文件作为程序入口,那么就执行 app.run()
if __name__ == '__main__':
# app.run() 是启动一个应用服务器来响应用户请求并不断监听
# app.run() 是 FLask 中的一个测试应用服务器(性能差,在部署的时候应该使用 uwsgi 而不是 app.run)
# app.run() 在底层实际上是一个 while(True) 循环,循环体是 listen() 函数,不断地监听指定端口号
app.run(debug=True,port=8000)
2. 使用 Debug 模式
使用 Debug 模式有很多好处:
1. 将报错信息显示到浏览器上,而不需要进入编辑器中查看报错信息,方便开发者查看错误
2. 当检测到程序代码(.py文件)发生改动,程序会自动加载而不需要手动重启服务器
对 flask 程序使用 debug 模式有 4 种方式,如下:
2.1 在 app.run() 中使用
在 app.run()
中直接传入一个关键字参数:app.run(debug=True)
。
2.2 在主 app 文件中使用 app.debug=True
from flask import Flask
app = Flask(__name__)
app.debug = True # 在主 app 文件中使用
…… 略 ……
2.3 在主 app 文件中使用 app.config.update(DEBUG=True)
from flask import Flask
app = Flask(__name__)
app.config.update(DEBUG=True) # 在主 app 文件中使用
…… 略 ……
使用 app.config.update(DEBUG=True)
这种方法实际上是借助了 Python 中的字典(Dict)属性,即:
a = {'a':1}
b = {'b':2}
a.update(b)
print(a) # {'a':1,'b':2}
a.update(c=3)
print(a) # {'a':1,'b':2,'c':3}
可以使用 print(isinstance(app.config,dict))
来判断 app.config
是不是一个字典类型的数据。但是要注意 DEBUG
一定要大写。
以上这三种开启 Debug 模式的方法比较简单,还有一种开启 Debug 模式的方法需要借助配置文件,借助配置文件开启 Debug 模式的方法也比较规范,如下。
2.4 在配置文件中使用
在相同目录下,新建一个
python
文件,建议命名为config
,并在里面指定该程序配置了DEBUG
模式,即config.py
文件的内容如下:config.py # encoding:utf-8
DEBUG = True
# SECRET_KEY
# SQLALCHEMY_DB # 数据库的一些参数配置
然后在主 app 文件中导入这个文件并配置到 app 中,主 app 文件内容如下:
First_Flask.py # encoding:utf-8
from flask import Flask
import config # 导入 config 配置文件 app = Flask(__name__)
app.config.from_object(config) # 将该配置文件的配置信息应用到 app 中 @app.route('/')
def hello_world():
a = 3
b = 0
c = a/b
return 'Hello,World.' if __name__ == '__main__':
app.run()
2.5 PIN 码
开启了 DEBUG 模式后,当程序抛出异常,则可以在网页上对程序进行调试,在网页上报出的任何一行错误信息中都有一个命令行小图标,点击该图标就可以进行调试了。
但是要注意,如果想要在网页上对程序进行调试,那么就需要输入 PIN 码,PIN 码在 Pycharm 中执行程序的时候会显示,复制过去粘贴即可。其中,PIN 码的有效时间是 8 小时,保存在浏览器的 Cookie 中,所以也不用每次抛出异常时都要输入一遍 PIN 码。
PIN 码的作用是为了保证程序更加安全,比如我不想让其他开发者知道我的代码写的是什么,但是实际上并没有什么卵用,因为都是开发者,没必要隐藏自己的代码。这个机制反而更加麻烦了一些。
3. 应用配置文件的两种方式
如上所示,在主 app 文件中导入 config 文件后,使用
app.config.from_object(config)
来将配置文件应用到 app 中,如下所示:from flask import Flask
import config
app = Flask(__name__)
app.config.from_object(config)
不需要
import config
,直接使用app.config.from_pyfile
来将配置文件应用到 app 中,如下所示:from flask import Flask
app = Flask(__name__)
app.config.from_pyfile('config.py')
实际上,
from_pyfile
并不局限于 python 文件,也可以是其他类型的文件,如config.txt
。from_pyfile
还有一个被隐藏的默认参数是silent=False
,所以完整格式是app.config.from_pyfile('config.py',silent=False)
。当 silent 被置为 False 时,如果前面输入的文件不存在,则抛出异常;当 silent 被置为 True 时,则会忽略这种错误。
4. URL 传参到视图
参数的作用:可以在相同的 URL 但是指定不同的参数时,来加载不同的数据。
如:http://localhost:8000/article/abc
和 http://localhost:8000/article/def
中,两条 URL 的参数不同,我们可以获取这个参数并渲染后返回客户浏览器
如何传参:如何在 flask 中使用参数?有两种方式实现。
第一种,使用 path 的形式,将参数嵌入到路径中
传递参数的语法是:
/<参数名>/
,在对应的视图函数中也要定义相同的参数名。如下代码所示:@app.route('/article/<id>')
def article(id):
return u'<h1>你请求的参数是:%s<h1>' % id
如果要限制传入参数的数据类型,可以这么定义:
/article/<数据类型:参数名>
,如/<int:id>/
,如下:@app.route('/article/<int:id>')
def article(id):
return u'<h1>你请求的参数是:%s<h1>' % id
对于这段代码,当浏览器中的 url 是
127.0.0.1:5000/article/1
时能正确返回,当 url 是127.0.0.1:5000/article/abc
时则提示 not found。如果没有指定数据类型,则默认是 str 型。其中,这些类型可以是:
string 默认的数据类型,接受没有斜杠"/"和"\"的任何字符
int 只接受整型
float 只接受浮点型
path 与 string 类似,但是接受斜杠
uuid 只接受 uuid 字符串,其中 uuid 是全球唯一的字符串,一般可以用来作为表的主键
any 可以指定多种路径,示例说明:
any 示例:
@app.route('/<any(article,user):url_path>/<id>')
def detail(url_path,id):
return '详情页面,id=%s' % id
# 这个方法用于不同的 url 对应相同的视图函数的需求
# 例如:/article/1 和 /user/1 对应同一个视图函数
第二种,使用查询的方式,调用 request.args.get('args') 方法,获取问号传递的参数
from flask import request
…… 略 ……
@app.route('/keyword/')
def keyword_args():
wd = request.args.get('wd')
return '?后面的参数是:%s' % wd
这样,就可以获取 url 后面以问号的形式跟上的关键字了,如:
/keyword/?wd=python
。如果需要传递多个参数,那么问号后面可以跟&
符号进行连接,如:/keyword/wd=python&name=myyd
那么在视图函数中再加上
name = request.args.get('name')
即可。
5. URL 反转
正转指的是:在获取到用户输入的 URL 后将该 URL 映射到对应的视图函数中,让对应的视图函数去处理该用户的请求;
反转指的是:与正转相反,通过视图函数来查找对应的 URL。
反转的作用是:1. 在页面重定向的时候会使用 URL 反转;2. 在模板中会使用 URL 反转
实现反转的方法:
在 flask 框架中导入
url_for
模块用
url_for('FunctionName',key=value)
实现反转第一个参数
FunctionName
是视图函数的函数名。第二个参数
key=value
是传递给视图函数的参数,即@app.route('/article/<id>')
中的 id。如果这个参数在@app.route()
时已被定义,则该参数则以 path 的形式出现在 url 中;如果这个参数在@app.route()
时未被定义,则该参数通过问号?
跟在 url 的后面传递给后台。例如:
@app.route('/article/<id>')
def article(id):
return 'article' print(url_for('article',id='123',name='myyd')) # /article/123?name=myyd
源代码如下
from flask import Flask,url_for
import config app = Flask(__name__)
app.config.from_object(config) @app.route('/')
def hello_world():
print(url_for('article',id='123')) # /article/123
print(url_for('article',id='123',name='myyd')) # /article/123?name=myyd
print url_for('my_list') # /list/
return 'Hello,World.' @app.route('/article/<id>/')
def article(id):
return u'<h1>你请求的参数是:%s<h1>' % id @app.route('/list/')
def my_list():
return '<h1>list</h1>' if __name__ == '__main__':
app.run()
为什么需要 url_for ?
将来如果修改了 URL,但是没有修改 URL 对应的函数名,就不用到处去替换 URL 了。
url_for
会自动地处理 URL 中的特殊字符(如"/"),不需要手动处理。如:
print(url_for('article',next='/'))
会输出 /article/%2F,因为 "/" 在 URL 中有歧义。
6. 自定义 URL 转换器
客户提出两个需求
6.1 需求一:
在一个 URL 中,含有手机号码的变量,必须限定这个变量的字符串格式满足手机号码的格式。
为了实现这个需求,需要做如下几个步骤:
从 werkzeug.routing 导入 BaseConverter:
from werzeug.routing import BaseConverter
实现一个类,继承自
BaseConverter
,重写正则表达式查看 BaseConverter 中的底层定义:光标停留在 BaseConverter 上,按 Ctrl+B 组合键进入 BaseConverter 的定义代码,参考
PathConverter()
类的定义,依葫芦画瓢自定义一个手机号码格式的转换器。# PathConverter(葫芦)
class PathConverter(BaseConverter):
regex = '[^/].*?' # TelephoneConverter(瓢)
class TelephoneConverter(BaseConverter):
regex = '1[34578]\d{9}' # \d 代表数字,{9} 代表重复 9 次
添加自定义转换器到默认转换字典
Flask 中原来就定义的转换器有:string、int、float、path、uuid、any 等,如下所示:
DEFAULT_CONVERTERS = {
'default': UnicodeConverter,
'string': UnicodeConverter,
'any': AnyConverter,
'path': PathConverter,
'int': IntegerConverter,
'float': FloatConverter,
'uuid': UUIDConverter,
}
所以我们需要将自定义的转换器也添加进来,有两种方式:第一种就是按照格式在 DEFAULT_CONVERTERS 中添加;第二种方式是借助
url_map
来实现,如下:app.url_map.converters['tel'] = TelephoneConverter
限制视图函数中的参数类型
@app.route('/telephone/<tel:number>') # 限制类型
def telephone(number):
return 'Number is %s' % number
6.2 需求二:
在一个 URL 中,包含 a+b
的 path,需要将其拆分为 a
和 b
,后台再进行处理。
传统方法如下:
在视图函数中对传进来的参数进行拆分:
@app.route('/list/<id>')
def my_list(id):
id_list = id.split('+')
return 'the id list is %s' % id_list
# 若浏览器地址栏的 url 写的是:127.0.0.1:5000/list/a+b
# 则返回页面的信息是:the id list is ['a','b'],而不是:the id list is a+b
对于传进来的参数,在调用视图函数时都要进行一次拆分,会降低执行效率,能否在传到视图函数之前就已经对 a+b
格式的参数进行拆分?
借助 URL 转换器:
在 URL 转换器中定义了一个两个函数:to_python()
和 to_url()
。
前者的作用是:将 URL 中的参数经过解析后传递给视图函数,即在
to_python
函数体中解析 URL 中的参数,然后 return 到视图函数中作为参数,如下:class ListConverter(BaseConverter):
def to_python(self,value): # value 就是 /list/ 后面本来要跟的 a+b
return 'value.split('+')' # 然后以 ['a','b'] 的格式返回给视图函数 my_list()
然后要记得添加到默认的转换器字典中:
app.url_map.converters('List') = ListConverter
,最后限制类型:@app.route('/list/<List:id>')
。这样,视图函数就不用再进行拆分处理,而是能直接拿到最终想要的内容。
后者的作用是:在使用
url_for
时将参数还原成 url,如下:class ListConverter(BaseConverter):
def to_url(self,value): # value 就是从视图函数中传过来的参数 ['a','b']
return "+".join(value) # 然后以 a+b 的格式返回给 url_for 的参数 @app.route('/')
def index():
return url_for('my_list',id=['a','b'])
注意:这两个函数是成对出现的,一般情况下,要解析也要还原。
源代码如下
from flask import Flask,url_for
from werkzeug.routing import BaseConverter
class ListConverter(BaseConverter):
def to_python(self, value):
return value.split('+')
def to_url(self, value):
return "+".join(value)
app = Flask(__name__)
app.url_map.converters['List'] = ListConverter
@app.route('/')
def hello_world():
return url_for('my_list',id=['a','b'])
@app.route('/list/<List:id>/')
def my_list(id):
return 'The List is %s' % id
if __name__ == '__main__':
app.run(debug=True)
7. Flask 开发的小细节
想要让自己写的网站,在局域网中被其他网络设备访问,则必须指定 host,即
app.run(host='0.0.0.0')
,同时还需要注意以下 3 点:指定端口号:Flask 的默认端口号是 5000,如果想要改成 8000 端口,应将
app.run
写成app.run(port=8000)
。URL 唯一
在定义 URL 的时候,一定要记得在最后加一个
/
,这是为了更好的用户体验。而且搜索引擎会将加了斜杠的和不加斜杠的 URL 视为两个不同的 URL,但实际上加不加斜杠都是同一个 URL,这样就会给搜索引擎造成一个误解。指明 GET 或者 POST 请求
参考我的另一片博客:Flask基础,第 10 点:GET 、POST 和 钩子函数。
8. 页面跳转和重定向
重定向指的是浏览器自动地从一个页面跳转到另一个页面,可以用在一些需求上,如:用户访问某些需要登录的页面时,如果用户没登录,则可以让他重定向到登录页面。重定向分为两种:永久性重定向和暂时性重定向。
8.1 永久性重定向
状态码是 301,多用于旧网址被废弃了要转到一个新网址上,如京东网站,当你访问 www.jingdong.com
时会被重定向到 www.jd.com
,因为旧网址已经被弃用了,所以这种情况应该使用永久重定向。
8.2 暂时性重定向
状态码是 302,表示页面的暂时性跳转。比如访问一个需要权限的网页,如果当前用户没有登录,应该重定向到登录页面。这种情况下应该使用暂时性重定向。
8.3 重定向的实现
在 Flask 中,重定向是通过 flask.redirect(location,code=302)
这个函数来实现的。其中:locate
代表重定向之后的 URL,应该配合之前将的 url_for()
来使用,code
表示使用的状态码,默认是 302。
看一个具体的例子:
from flask import Flask,redirect,url_for,request
app = Flask(__name__)
app.debug = True
@app.route('/')
def index():
return 'hello world'
@app.route('/login/')
def login():
return '请登录!'
@app.route('/profile/')
def profile():
name = request.args.get('name')
if name:
return '个人详情页面'
else:
return redirect(url_for('login'))
if __name__ == '__main__':
app.run(host='0.0.0.0')
9. 视图函数 response 返回值详解
Flask 的视图函数默认只可以返回字符串、元组合 Response 对象,Flask 转换响应对象的逻辑是:
如果返回的是一个合法的相应对象,则直接返回;
如果返回的是一个字符串:
则 Flask 会构建一个
werkzeug.wrappers.response
对象,response
对象会将该字符串作为主体,状态码为 200,MIME 类型为 text/html,即构建成为:response('string',status=200,mimetype='text/html')
然后返回 response 对象。我们在视图函数中使用 return 返回内容,实际上就是 Flask 帮我们完成的这个动作。所以视图函数中的
return 'Hello World!'
等价于return response('Hello World!')
如果返回的是一个元组:
元组的数据类型是
(response,status,headers)
,其中,status 会覆盖默认的 200 状态码,header 可以是一个列表或者字典,作为额外的消息头。如果非以上内容:
Flask 会去底层调用
Response.force_type(rv,request,environ)
返回一个 response 对象。这样,视图函数在调用 return 的时候就可以正确返回了。如下例:from flask import Flask,Response,jsonify app = Flask(__name__)
app.debug = True class JSONResponse(Response): @classmethod
def force_type(cls, response, environ=None):
'''
这个方法只有在视图函数返回非字符串、非元组、非response对象的时候被调用
response:视图函数的返回值
'''
print(response)
print(type(response))
# jsonify:除了将字典转换成json对象,还将该对象包装成了一个Response对象
if isinstance(response,dict):
return super(JSONResponse,cls).force_type(response,environ) app.response_class = JSONResponse @app.route('/dict/')
def dict():
return {'username':'myyd','age':18} if __name__ == '__main__':
app.run(host='0.0.0.0')
实现响应自定义内容,需要完成 3 个步骤:
- 继承自
Response
类 - 实现方法
force_type(cls,response,environ=None)
- 指定
app.response_class
为你自定义的Response
对象
- 继承自
Flask-论坛开发-1-基础知识的更多相关文章
- ArcGIS API for JavaScript开发初探——基础知识
1.前言 在ArcGIS Web API开发体系中一共有四大类,分别为: ArcGIS API for Flex ArcGIS API for JavaScript ArcGIS API for RE ...
- Java开发培训基础知识解析之反射机制
Java是老牌编程语言,是当前应用最广泛的编程语言之一.想要学习Java你就一定要掌握Java基础知识,而反射对于初学Java的人来说绝对是非常重要的知识点.什么是反射?如何理解反射机制?如何使用反射 ...
- 【千纸诗书】—— PHP/MySQL二手书网站后台开发之基础知识
前言: 在具体回顾每一个功能的实现前,还是有必要先温习一些项目涉及到的PHP.MySQL[语法基础].项目github地址:https://github.com/66Web/php_book_stor ...
- ArcGIS Engine开发前基础知识(4)
ArcGIS不同开发方式的比较 关于GIS应用软件的开发,通常有三种方式:C/S架构.网络GIS和移动GIS.ArcGIS平台提供了对三种开发方式的支持,对于采用从C/S架构的大多数开发者来讲,首先想 ...
- ArcGIS Engine开发前基础知识(3)
对象模型图 一.对象模型图中的类与接口 ArcGIS Engine 提供大量的对象,这些对象之间存在各种各样的关系,如继承.组合.关联等.对象模型图(Object model diagram,ODM) ...
- ArcGIS Engine开发前基础知识(1)
ArcGIS二次开发是当前gis领域的一项重要必不可少的技能.下面介绍它的基本功能 一.ArcGIS Engine功能 在使用之前首先安装和部署arcgis sdk,(在这里不在赘述相关知识)可以实现 ...
- Python开发——1.基础知识
一.开发 开发语言分为高级语言和低级语言 高级语言:Python.Java.PHP.C++.C#.GO.Ruby等:低级语言:C.汇编语言. 高级语言对应的是字节码,是将代码编译成字节码,然后交给机器 ...
- android开发学习---基础知识学习、如何导入已有项目和开发一个电话拨号器
一.基础知识点学习 1.Android体系结构 如图所示,android 架构分为三层: (1)最底层是linux内核,主要是各种硬件的驱动,如相机驱动(Camera Driver),闪存驱动(Fl ...
- Unity游戏开发面试基础知识
面试第一次知识总结: 一.Unity基本操作 1.unity提供哪几种光源? 点光源.平行光.聚光灯.区域光. 2.物体发生碰撞的必要条件什么? 两个物体必须有碰撞体Collider组件,一个物体上必 ...
- ArcGIS Engine开发前基础知识(2)
ArcGIS基本控件简介 ArcGIS Engine控件是一组可视化的开发组件,每个ArcGIS Engine控件都是一个COM组件.这些组件包括MapControl,PageLayoutContro ...
随机推荐
- 关于hover和after、before合用
通常hover后面跟的选择器,都是在myClass结构之下 的dom元素. 如果想在myClass下添加after等,就需要两个::号. 注:after/before是属于myclass的下级元素,并 ...
- github拓展,以及ModelForm的使用
github - git init/add/commit/reset/log/status/stash pop/checkout/branch 新入职到公司,地址: git clone h ...
- Java没有头文件的原因
http://bbs.csdn.net/topics/100134244 C/C++ 之所以需要头文件(.h),有两个用处,一个是在开发编译的时候,在各个编译单元(Compile Unit)之间共享同 ...
- P1481 魔族密码 (LIS)
题的连接:https://www.luogu.org/problemnew/show/P1481 简单思路: 就是LIS,最长上升子序列,当然把条件改一下,从模板里的A[ i ]> A[ j ] ...
- go标准库的学习-crypto/des
参考:https://studygolang.com/pkgdoc 导入方式: import "crypto/des" des包实现了DES标准和TDEA算法,参见U.S. Fed ...
- OpenCV (C++) 颜色跟随
#include<opencv2/opencv.hpp> #include<iostream> using namespace cv; using namespace std; ...
- 国产的骄傲,Deepin发布v15.9
深度操作系统是一个致力于为全球用户提供美观易用.安全可靠的Linux发行版.深度操作系统基于Linux内核,以桌面应用为主的开源GNU/Linux操作系统,支持笔记本.台式机和一体机.深度操作系统(d ...
- PAT A1076 Forwards on Weibo (30 分)——图的bfs
Weibo is known as the Chinese version of Twitter. One user on Weibo may have many followers, and may ...
- 【Codeforces 464D】World of Darkraft - 2
Codeforces 464 D 首先我们知道这K个装备是互不干扰的,就是说如果一个装备升级了或者卖掉了,不会对其它装备的挣到的钱产生任何影响.所以我们就考虑单独处理某一个装备挣到的钱. 那么就设\( ...
- 【Codeforces 204E】Little Elephant and Strings
Codeforces 204 E 题意:给\(n\)个串,求对于每一个串在至少\(k\)个串中出现的它的子串\(S_{l..r}\)有多少个. 思路:后缀自动机上\(dp\)... 我们首先构造出这\ ...