python flask框架优点_python之全栈(Flask框架)

虚拟环境

虚拟环境顾名思义就是虚拟的,在这里面装任何软件都不会影响到其他的程序,类似与一个抽屉。

使用虚拟环境的好处是:让电脑中安装很多种解释器,并且互不影响

virtualenv的使用

安装virtualenv

通过pip或者pip3来安装:pip install virtualenv

可以用pip list 来查看都安装了那些包

创建虚拟环境

virtualenv [虚拟环境的名字]

就是在当前目录下创建了一个文件夹,文件夹中有好多文件

进入虚拟环境

windows系统:需要进入进入到虚拟环境的 Scripts 文件夹中,然后执行 activate。

Liunx系统:进入虚拟环境: source /path/to/virtualenv/bin/activate。

退出虚拟环境

deactivate :退出虚拟环境命令

virtualenvwrapper的使用

安装virtualenvwrapper

Liunx:pip install virtualenvwrapper

windows: pip install virtualenvwrapper-win

创建虚拟环境

mkvirtualenv my_env

并且默认文件位置是在C://Administor/Envs中

切换某个虚拟环境

workon my_env

退出当前虚拟环境

deactivate

删除某个虚拟环境

rmvirtualenv my_env

列出所有虚拟环境

lsvirtualenv

进入到虚拟环境所在的目录

cdvirtualenv

修改mkvirtualenv 的默认路径

在 我的电脑->右键->属性->高级系统设置->环境变量->系统变量 中添加一个参数 WORKON_HOME ,将这个参数的值设置为你需要的路径,并且重新打开dos窗口才生效。

创建虚拟环境的时候指定 Python 版本

mkvirtualenv --python==C:\Python36\python.exe hy_env

Flask视图基础和URL

认识URL

URL : Uniform Resource Locator 的简写,统一资源定位符。一个 URL 由以下几部分组成:scheme://host:port/path/?query-string=xxx#anchorscheme:代表的是访问的协议,一般为 http 或者 https 以及 ftp 等。

host:主机名,域名,比如 www.baidu.com。

port:端口号。当你访问一个网站的时候,浏览器默认使用80端口。

path:查找路径。比如: www.jianshu.com/trending/now,后面的 trending/now就是 path。

query-string:查询字符串,也叫请求参数,比如: www.baidu.com/s?wd=python,后面的 wd=python就是查询字符串。

anchor:锚点,后台一般不用管,前端用来做页面定位的。

注意: URL 中的所有字符都是 ASCII 字符集,如果出现非 ASCII 字符,比如中文,浏览器会进行编码再进行传输。

web服务器和应用服务器以及web应用框架

web服务器:负责处理http请求,响应静态文件,常见的有 Apache,Nginx以及微软的IIS

应用服务器:负责处理逻辑的服务器。比如 php 、 python 的代码,是不能直接通过 nginx 这种web服务器来处 理的,只能通过应用服务器来处理,常见的应用服务器有 uwsgi 、tomcat 等。

web应用框架:一般使用某种语言,封装了常用的 web 功能的框架就是web应用框架, flask、Django以及 Java中的 SSM(Spring+SpringMVC+Mybatis) 框架都是web应用框架。

三者的应用顺序,以及职责所在

第一个Flask框架程序(代码认识)

# 从flask中导入Flask

# Flask这个类是项目的核心,以后很多操作都是基于这个类对象

# 注册url、注册蓝图等等都是基于这个类对象

from flask import Flask

app = Flask(__name__)

# 是一个装饰器,将url中/映射到hello_world这个视图函数上,

# 当以后访问这个网站的/目录是,就会执行hello_world这个函数,然后将函数的返回值返回给浏览器

# 例如:www.baidu.com/ --> hello_world执行

@app.route('/')

def hello_world():

print('hhah')

return '你好呀~'

@app.route('/list/')

def my_list():

return '我就是我哦~'

if __name__ == '__main__':

# 默认为5000端口

# app.run()

app.run(port=8000)

开启Flask框架的DeBug模式

每个版本的PyCharm开启的方式不同,下面所记录是在PyCharm2017中的开启方式。

开启方式直接在运行的地方,添加app.run(debug=True)

在代码中间,添加app.debug= True

同样是在代码中间,app.config.update(DEBUG=True)

通过配置文件开启创建config.py文件,先引入(import config),然后执行app.config.form_object(config)

创建config文件,不局限py文件,普通文本文件也可以,执行:app.config.form_pyfile(‘config.txt’)

注意文件路径要写全名,后缀名也要写,不然会导致整个项目挂掉,解决方式:silent =True

URL与函数映射

传递参数的两种方式

/路径/参数,(就是将参数嵌入到路径中)

代码:

@app.route('/article//')

def article_detail(id):

return '您请求的文章是:%s'% id

其中的,尖括号是固定用法,语法为,variable默认的数据类型是字符串(string),如果想要指定数据类型,则要写成,其中的converter的类型有如下的六种:string:字符串,如果没有指定具体的数据类型,那么默认为字符串

int

float

path:path数据类型和字符串类型类似,区别在与一点,就是对于‘/’右斜杠的处理。

uuid:uuid是一个全宇宙都唯一的字符串,一般可以用来作为表的主键。

any:数据类型可以在一个url中指定多个路径。例如: @app.route('/any(user,blog):url_path/') def detail(url_path,id): if url_path=='blog': return "博客详情:%s" %id else : return "用户详情:%s" %id

/路径?参数名1=参数值1&参数名2=参数值2...

代码:

from flask import request,render_template

# 第二种:/路径?参数名1=参数值1&参数名2=参数值2...,

# @app.route('/list7') # 这种写法只支持get请求方式,不支持post请求方式

@app.route('/list7',methods=['GET','POST'])

# 这种写法及支持get有支持post

def list7():

if request.method=='GET':

uname = request.args.get('uname')

pwd = request.args.get('pwd')

return render_template('login.html')

elif request.method =='POST':

uname = request.form.get('uname')

pwd = request.form['pwd']

return 'POST方式接收到的参数为;%s,%s'%(uname,pwd)

要注意,两种请求方式的区别!!!

url_for的使用详解

之前都是用一个url调用函数,这次反过来了,给定函数生成url,这个功能的实现依托于url_for。

url_for接收两个以上的参数,并且接收到的函数名作为第一个参数(这个是规定),然后接收对应的URL规则命名参数,如果还有其他的参数,会自动添加到URL后面作为查询参数。

使用代码:

@app.route('/')

def hello_world():

# return 'Hello World!'

# 希望返回页面一个指定的url,如'/list/'

# return '/list/'

# 使用url_for函数构建url

# 这么做的好处:如果将来修改了url 但是没有修改url对应的函数名,就不用了到处替换url了(路径变化概率要大于函数名变化)

# return url_for('list1') #******

# 构建url 如/list2/3/

# return url_for('list2',page=3) #******

# 构建url 如:/list2/4/?num=8&pwd=123 了解

# return url_for('list2',page=4,num=8,pwd=123)

# 这么做的好处:url_for() 函数会转义一些特殊字符和 unicode 字符串,这些事情 url_for 会自动的帮我们搞定。

return url_for('list1',next='/')

参数底层的原理

Flask项目中,底层是如何实现参数类型格式判断的呢?

根据werkzeug.routing模块中的BaseConverter类中的每个分类确定的。

每个数据类型都是调用werkzeug.routing模块中的对应类来做格式判断的!

自定义URL转换器

步骤:实现一个类,继承自BaseConverter。

在自定义的类中,重写regex,也就是这个变量的正则表达式。

将自定义的类,映射到app.url_map.converters上。理解为加入字典DEFAULT_CONVERTERS中 书写格式:app.url_map.converters['tel']=TelephoneConveter

代码:

# 需求1:希望路径中能匹配一个电话号码类型的参数

class TelephoneConverter(BaseConverter):

regex = r"1[345789]\d{9}"

app.url_map.converters['tel']=TelephoneConverter

# 使用自定义转换器实现需求

@app.route('/telephone/')

def my_telephone(pnum):

return '您请求过来的电话号码值为:%s'%pnum

to_python和to_url方法

to_python:可以把url拆分,并且返回txt格式的文件。

to_url:在调用url_for函数的时候,生成一个合适的url形式

代码:

# 需求2:查询多个模块的数据

# 自定义转换器实现

class LiConverter(BaseConverter):

def to_python(self, value):

# value是自己传递过来的参数

# 可以对value进行加工后在返回

lm = value.split('+')

print(lm)

print(lm[0])

print(lm[1])

return lm

def to_url(self, value):

# 目的是要把['hots','enter']---->hots+enter

return '+'.join(value)

app.url_map.converters['li']=LiConverter

@app.route('/news_list2/')

def news_list2(moudles2):

print(moudles2)

# 此时参数已经进行了拆分 slect *from news where nmoudles='hots' or nmoudles='enter'

return "您要查询的模块是:%s" % moudles2

@app.route('/hello/')

def hello_wrold():

# 构建url

args = url_for('news_list2',moudles2=['hots','enter'])

return '构建出url并返回:%s'%args

页面跳转和重定向

重定向分为暂时性重定向和永久性重定向,也就是在浏览器上会自动跳转到另一个页面。

永久性重定向: http 的状态码是 301 ,多用于旧网址被废弃了要转到一个新的网址确保用户的访问,最经典的就是京东网站,输入 www.jingdong.com 的时候,会被重定向到 www.jd.com。

暂时性重定向:http 的状态码是 302 ,表示页面的暂时性跳转。比如访问一个需要权限的网址,如果当前用户没有登录,应该重定向到登录页面,这种情况下,应该用暂时性重定向。

Flask中的重定向

重定向是通过 redirect(location,code=302) 这个函数来实现的。

location 表示需要重定向到的 URL,应该配合之前讲的 url_for()函数来使用。

code 表示采用哪个重定向,默认是 302( 暂时性重定向 ) ,可以修改成 301来实现永久性重定向。

代码:

from flask import Flask,request,url_for,redirect

app = Flask(__name__)

@app.route('/')

def hello_world():

return 'Hello World!'

# 登录界面

@app.route('/login/')

def login():

return '请登录'

# 页面跳转,暂时性重定向302 永久性重定向301

@app.route('/profile/')

def profile():

if request.args.get('name'):

return '用户中心页面'

else:

return redirect(url_for('login'),code=302)

app.debug=True

if __name__ == '__main__':

app.run()

Response返回值

Response是返回值的意思,类似于return的功能, 相当于一个包装,把返回的内容包装起来用于其他的操作。

自定义Response对象的步骤继承自Response类。

实现方法force_type(cls,rv,environ=None)。

指定app.response_class为你自定义的Response对象。

代码:

# 需求:希望将一个字典类型的数据,变成json对象返回给客户端

# 问题:视图函数不支持返回字典类型的数据

# 解决:自定义Response的子类对象来解决

# 步骤:

# 1.继承自`Response`类。

# 2.实现方法`force_type(cls, rv, environ=None)`。

# 3.指定`app.response_class`为你自定义的`Response`对象。

class JSONResponse(Response):

@classmethod

# 因为是类方法

def force_type(cls, response, environ=None):

'''这个方法只有视图函数返回 非字符串 非Response对象 非元组时才会调用response:视图函数的返回值'''

if isinstance(response,dict):

# 当返回类型为字典的时候,在加工操作

# 希望吧一个字典对象转化为json对象

resp = jsonify(response)

return super(JSONResponse, cls).force_type(resp)

app.response_class = JSONResponse

@app.route('/myprofile/')

def profile():

return {'uname':'wo','gender':'nan','school':'sxt'}

思维导图

查找路径

引入html文件要借助render_template方法。

@app.route('/')def hello_world():# return 'Hello World!'# 去数据库拿取数据# 模拟数据库的一个用户数据uname = 'momo'return render_template('index.html',content=uname)# 查询所有的新闻信息@app.route('/news/')def news_list():return render_template('news/news_list.html')

模板传参以及技巧

关键字传参(针对参数少的情况)

@app.route('/')

def hello_world():

# 关键词传参,只适用于键值对形式,且参数较少的情况

return render_template('index.html',uname='momo')

传参技巧(针对参数很多的情况)

使用传参技巧

@app.route('/list/')

def hello():

# 如果参数太多了,可以放到一个字典中,然后在传这个字典参数的时候,使用两个星号,将字典打散成关键字参数(也叫命名参数)。

context = {

'uname': 'momo',

'age': 18,

'country': 'china',

'childrens': {

'name': 'mjz',

'height': '62cm'

}

}

# 使用的传参技巧

# return render_template('index.html',**context)

不使用传参技巧

# 不是用传参技巧

return render_template('index.html',c=context)

过滤器

相当于一个函数,把当前变量传入到过滤器中,然后过滤器根据自己功能那个,返回对应的值,然后再将结果渲染到页面上

基本用法

‘{{ variables | 过滤器名字 }}’

使用管道符‘|’进行组合。

介绍+一些常用过滤器

过滤器是通过管道符号(|)进行使用的,例如:{{ name|length }},将返回name的长度abs(value):返回一个数值的绝对值。 例如:-1|abs。

default(value,default_value,boolean=false):如果当前变量没有值,则会使用参数中的值来代替。name|default('xiaotuo')——如果name不存在,则会使用xiaotuo来替代。boolean=False默认是在只有这个变量为undefined的时候才会使用default中的值,如果想使用python的形式判断是否为false,则可以传递boolean=true。也可以使用or来替换。

escape(value)或e:转义字符,会将<、>等符号转义成HTML中的符号。例如:content|escape或content|e。

first(value):返回一个序列的第一个元素。names|first。

format(value,*arags,**kwargs):格式化字符串。例如以下代码: {{ "%s" - "%s"|format('Hello?',"Foo!") }}将输出:Helloo? - Foo!

last(value):返回一个序列的最后一个元素。示例:names|last。

length(value):返回一个序列或者字典的长度。示例:names|length。

join(value,d=u''):将一个序列用d这个参数的值拼接成字符串。

safe(value):如果开启了全局转义,那么safe过滤器会将变量关掉转义。示例:content_html|safe。

int(value):将值转换为int类型。

float(value):将值转换为float类型。

lower(value):将字符串转换为小写。

upper(value):将字符串转换为小写。

replace(value,old,new): 替换将old替换为new的字符串。

truncate(value,length=255,killwords=False):截取length长度的字符串。

striptags(value):删除字符串中所有的HTML标签,如果出现多个空格,将替换成一个空格。

trim:截取字符串前面和后面的空白字符。

string(value):将变量转换成字符串。

wordcount(s):计算一个长字符串中单词的个数。

default过滤器使用

以个性签名为举例

用法

@app.route('/')

def hello_world():

context ={

'postion':-1,

'signature':'偶买噶'

}

return render_template('index.html',**context)

注意:当value为一些指定的特定值之后,需要给default添加boolean = True.

拓展知识(可以用or代替default过滤器)

default过滤器的使用

个性签名[使用过滤器]:{{ signature|default('此人很懒,暂无签名',boolean = True) }}


个性签名[不是使用过滤器]:{{ signature or ('此人很懒,暂无签名') }}

常用过滤器讲解01

escape过滤器(转义)

JinJa2模板默认全局开启了自动转义功能 意思是:会把'<'转换位html知识里面的实体字符'<'

safe(关闭转义)

如果开启了全局转义,那么safe过滤器会将变量关掉转义。

小总结

autoescapejinja标签,可以对他里面的代码块关闭或开启自动转义。

{% autoescape off/on %}

...代码块

{% endautoescape %}

常用过滤器讲解02

frist+last+length

第一个人:{{ persons|first }}

最后一个人:{{ persons|last }}

总人数:{{ persons|length }}

format

{{ "%s" - "%s"|format('Hello?',"Foo!") }}将输出:Helloo? - Foo!

helloo对应第一个%s

Foo!对象第二个%s

int

{% if gender|int ==1 %}

性别:男

{% else %}

性别:女

{% endif %}

自定义过滤器

步骤

#4、自定义过滤器

# 需要是用一个装饰器:@app.template_filter('过滤器名称')

@app.template_filter('cut')

def cut_world(value):

value = value.replace('十大酷刑','****')

return value

注意

自定义过滤器需要一个装饰器:

@app.template_filter('过滤器名称')

由于工具不同,所以要把模板设置为自动加载模式

app.config['TEMPLATES_AUTO_RELOAD']=True

自定义时间过滤器

逻辑顺序差值小于60s 返回刚刚

差值大于60s小于360s 返回XX分钟之前

差值大于360s小于24小时 返回XX小时前

差值大于24小时 返回XX天前

代码实现

@app.template_filter('time_to_time')

def time_to_time(time):

if isinstance(time,datetime):

now = datetime.now()

timestap = (now-time).total_seconds()

if timestap<60:

return '刚刚'

elif timestap>60 and timestap<60*60:

minutes = timestap//60

return '%s分钟之前'%minutes

elif timestap>60*60 and timestap<60*60*24:

hours = timestap//(60*60)

return '%s小时之前'%hours

elif timestap>60*60*24:

days = timestap//(60*60*24)

return '%s天之前'%days

else:

return time .strftime('%Y/%m/%d %H:%M')

else:

return time

控制语句

所有的控制语句都是放在{%.......%}中的

if语句

格式

{% if statement(条件语句)%}

...(里面加elif或者else都可以)

{% endif %}

应用案例1(简单案例)

简单判断

首页

学习Jinja2模板语言的if语句

{% if name=='momo' %}

姓名:momo

{% endif %}


{% if age>=18 %}

年龄大于{{ age }}可以进入网吧

{% else %}

未成年(年龄小于{{ age }})不可以进网吧

{% endif %}


{% if score>=90 %}

{{ name }}的成绩为:A

{% elif score>=80 %}

{{ name }}的成绩为:B

{% elif score>=60 %}

{{ name }}的成绩为:C

{% else %}

{{ name }}不及格

{% endif %}

应用案例2(标签中的案例)

个人信息修改页面

户籍:

{% if addr=='bj' %}

-请选择-

-北京市-

-上海市-

-重庆市-

{% elif addr== 'cq' %}

-请选择-

-北京市-

-上海市-

-重庆市-

{% else %}

-请选择-

-北京市-

-上海市-

-重庆市-

{% endif %}


性别:

{% if gender|int==1 %}

{% else %}

{% endif %}


for语句

注意在Jinja2的for语句中是没有break和contiune语句的

格式:

遍历列表:

{% for user in users %}

{{ user }}

{% else %}

没有任何用户

{% endfor %}

遍历字典:

{% for key in person.keys()[或者values(),item()] %}

{{ key }}

{% endfor %}

反向编历(reverse)

{% for user in users | reverse %}

{{ user }}

{% else %}

没有任何用户

{% endfor %}

小知识:通过变量描述当前的状态描述及用法: | loop.index | 当前迭代的索引(从1开始) | | loop.index0 | 当前迭代的索引(从0开始) | | loop.first | 是否是第一次迭代,返回True或False | | loop.last | 是否是最后一次迭代,返回True或False | | loop.length | 序列的长度 | 应用: 对上述的遍历进行添加背景色操作

使用for语句实现九九乘法表

4、for循环嵌套案例,实现九九乘法表

{% for x in range(1,10) %}

{% for y in range(1 , x + 1) %}

{{ y }}*{{ x }} ={{ x*y }}

{% endfor %}

{% endfor %}

和Python中的函数类似,可以传递参数,但是不能有返回值,减少代码量。

使用宏和不使用宏的比较

不使用宏:

正常方式创建表单域常用的标签

用户名:

密码:

使用宏的情况

{# 1、定义宏 #}

{% macro input(name,type='text',value ='')%}

{% endmacro %}

使用宏创建表单域常用的标签

{# 2、使用宏 #}

用户名:

{{ input('name') }}

密码:

{{ input('pwd',type = 'password') }}

{{ input('',type= 'submit',value='提交表单') }}

相比之下,对于上面的简单例子来说,用宏的代码量多一些,但是当代码增多,使用宏就会便捷很多。

但是使用宏的情况,一般不会再模板中直接定义宏,而是会把宏放在一个单独的文件中,这样就需要导入宏了。

宏的导入

方式一:(注意:当使用了【as 宏的别名】时,下面对于宏的使用都要用别名。)from '宏文件的路径' import 宏的名字 [as 宏的别名]

{% from 'index/macros/macro1.html' import input %}

方式二:

import "宏文件的路径" as xxx [with context]

注意:这种方式是导入了一个对象,宏在这个对象中,使用就需要用{{对象名.宏名}}使用。并且也不会共享参数。那么就需要使用with context 让参数共享。

{% import 'index/macros/macro1.html' as inp with context %}

Include标签使用

相当于直接将制定模板中的代码复制粘贴到当前位置。

include的路径,也是跟import一样,直接从templates根目录下去找,不要以相对路径去找。

set+with语句以及模板中定义变量

SET语句

在模板中,可以使用'set'语句来定义变量,并且在后面的都可以使用这个变量。(类似于全局变量)

{% set uname='momo'%}​

用户名:{{ uname }}

WITH语句

'with'语句定义的变量,只能在'with'语句块中使用,超过了这个代码块,就不能使用了。(相当于局部变量)

{% with classroom='python202'%}​

班级:{{ classroom }}

​{% endwith %}

案例实现

在模板中定义变量:set语句 特点:全局变量

{# 观察在定义之前能否使用#}{% set flag = 'yes' %}

标志1:{{ flag }}

在模板中定义变量:with语句 特点:局部变量

{% with monitor = '张三丰' %}

班长为:{{ monitor }}

啊哈哈:{{ flag }}

{% endwith %}{# with语句块之外能否使用#}

班长为:{{ monitor }}

在模板中定义变量:涉及变量区域有效性问题时,可以用with和set语句组合使用 了解

{% with %}{% set boss = '王总' %}

老板是:{{ boss }}

{% endwith %}{# 出了区域#}

老板是:{{ boss }}

Flask中加载静态文件

静态文件

静态文件就是CSS JS 图片等文件

加载

加载静态文件使用的是url_for函数,两个参数,第一个参数为固定值‘static’,第二个参数为filename。语法:{{ url_for("static",filename='xxx') }}

CSS加载:

JS加载:

图片加载:(一些简单的样式可以在标签内书写)

模板继承

模板继承就是把公用的代码抽离出来,放到父模板中,让子模板继承使用。

模板继承的语法

使用‘extends’语句,指明父模板的路径,(父模板的路径也是templates文件夹下的绝对路径){% extends "base.html" %}

block语法

因为父模板要有能力提供一个接口,让子模板实现功能代码,从而引出block。

super()函数

默认情况下,子模板如果实现了父模版定义的block。那么子模板block中的代码就会覆盖掉父模板中的代码。如果想要在子模板中仍然保持父模板中的代码,那么可以使用{{ super() }}来实现。

相互调用不同的block

如果想要在另外一个模版中使用其他模版中的代码。那么可以通过{{ self.其他block名字() }}就可以了

注意事项要继承的时候。extends必须在html文件的第一行。

子模板中,如果要实现自己的代码,应该放到block中。如果放到其他地方,那么就不会被渲染。

了解add_url_rule和app.route的原理

add_url_ruleadd_url_rule(rule,endpoint=None,view_func=None)

这个方法用来添加url与视图函数的映射。rule是地址必须有的(如果没有填写endpoint,那么默认会使用view_func的名字作为endpoint)以后在使用url_for的时候,就要看在映射的时候有没有传递endpoint参数,如果传递了,那么就应该使用endpoint指定的字符串,如果没有传递,那么就应该使用view_func的名字。

app.route

app_route的底层原理就是add_url_rule函数。

代码:

from flask import Flask,url_for

app = Flask(__name__)

@app.route('/')

def hello_world():

# 构建url :/list/

# 研究app.add_url_rule()方法,若方法中【没有加】上endpoint时,可通过原来的函数名构建url,即url_for('原函数名')

# print(url_for('my_list'))

# 研究app.add_url_rule()方法,若方法中【加上】endpoint时,不能再通过原来的函数名构建url,而需要endpoint的值才行

# 即url_for('endpoint值')

print(url_for('li'))

return 'Hello World!'

def my_list():

return '啦啦啦啦'

#通过app对象的add_url_rule方法 来完成url与视图函数的映射

app.add_url_rule('/list/',endpoint='li',view_func=my_list)

#讨论:add_url_rule()方法 与@app.route()装饰器的关系

#结论:@app.route()装饰器 底层就是借助于add_url_rule()方法来实现的

app.debug = True

if __name__ == '__main__':

app.run()

类视图

之前我们接触的视图都是函数,所以一般简称视图函数。其实视图也可以基于类来实现,类视图的好处是支持继承,但是类视图不能跟函数视图一样,写完类视图还需要通过app.add_url_rule(url_rule,view_func)来进行注册。

标准类视图

使用步骤定义一个类,并且必须继承于views.View。而且也必须含有dispatch_request()函数。

注册类视图app.add_url_route('url地址',endpoint = '断点',view_func= '函数名‘)。

代码实现:

from flask import Flask,views,url_for

app = Flask(__name__)

@app.route('/')

def hello_world():

return 'Hello World!'

# 定义一个类视图

class ListView(views.View):

def dispatch_request(self):

return '我是列表'

# 注册类视图

app.add_url_rule('/list/',endpoint='mil',view_func=ListView.as_view('my_list'))

# 获取上下文

with app.test_request_context():

#若注册url时,没有指定endpoint,使用as_view()方法中的名称 来构建url

# print(url_for('my_list'))

# # 若注册url时,有指定endpoint,就不能再使用as_view()方法中的名称 来构建url,而要使用endpoint的值来构建url

print(url_for('mil'))

app.debug =True

if __name__ == '__main__':

app.run()

注意:定义类视图,必须继承views.View类和dispatch_request方法。

在app.add_url_rule()函数中,若无指定endpoint,则默认以view_func后的名字构建url,而且要用as_view方法进行转化。

基于调度的类视图

在继承的时候,要继承views.MethodView.

本质

是基于方法的类视图,是根据请求的method来执行不同的方法的。如果用户是发送的get请求,那么将会执行这个类的get方法。如果用户发送的是post请求,那么将会执行这个类的post方法。

作用

这种方式,可以让代码更加简洁。所有和get请求相关的代码都放在get方法中,所有和post请求相关的代码都放在post方法中。就不需要跟之前的函数一样,通过request.method == 'GET'。

基本使用

#定义一个基于方法调度的 类视图

class LoginView(views.MethodView):

def get(self):

return render_template('login.html')

def post(self):

#模拟实现

#拿到前端页面传过来的 账号 和密码 去数据库做查询操作 查询到 (跳转主页面) ,反之跳转到login.html页面并给出错误提示信息

uname = request.form['uname']

pwd = request.form['pwd']

if uname=="momo" and pwd =="123":

return render_template('index.html')

else:

return render_template('login.html',error="用户名或者密码错误")

# 注册类视图

app.add_url_rule('/login/', view_func=LoginView.as_view('my_login'))

但是上述代码是有优化的地方的。

改进1(不过会让代码紊乱,做不到各回各家,各找各妈)

python:

class LoginView(views.MethodView):

def get(self,error=None):

return render_template('login.html',error=error)

def post(self):

#模拟实现

#拿到前端页面传过来的 账号 和密码 去数据库做查询操作 查询到 (跳转主页面) ,反之跳转到login.html页面并给出错误提示信息

uname = request.form['uname']

pwd = request.form['pwd']

if uname=="momo" and pwd =="123":

return render_template('index.html')

else:

return self.get(error="用户名或者密码错误")

# render_template('login.html',error="用户名或者密码错误")

# 注册类视图

app.add_url_rule('/login/', view_func=LoginView.as_view('my_login'))

Jinja2:

{# {{ error }}#}

{# 优化,判断#}

{% if error %} {#None == False 不为None或者空的字符串和列表时,才为True#}

{{ error }}

{% endif %}

改进2(最终写法)

# 改进2:基于调度方法的类视图 ,通常get()方法处理get请求,post()方法处理post请求,为了便于管理,不推荐post方法和get方法互相调用

class LoginView(views.MethodView):

def __jump(self,error=None):

return render_template('login.html', error=error)

def get(self,error = None):

return self.__jump()

def post(self):

#模拟实现

#拿到前端页面传过来的 账号 和密码 去数据库做查询操作 查询到 (跳转主页面) ,反之跳转到login.html页面并给出错误提示信息

uname = request.form['uname']

pwd = request.form['pwd']

if uname=="momo" and pwd =="123":

return render_template('index.html')

else:

return self.__jump(error="用户名或者密码错误")

类视图的优点:可继承

这一优点可以减少代码量,比如说两个子类都需要把字典对象转化为json对象,就可以通过继承来实现。

代码:

class ListView2(views.View):

def getDate(self):

raise NotImplementedError

def dispatch_request(self):

return jsonify(self.getDate())

# 重写了父类的getDate()方法

class JSONView1(ListView2):

def getDate(self):

return {'name':'张善峰','age':123}

class JSONView2(ListView2):

def getDate(self):

return {'book':'你好','author':'我'}

app.add_url_rule('/people/',endpoint='people',view_func=JSONView1.as_view('JSONView1'))

app.add_url_rule('/book/',endpoint='book',view_func=JSONView2.as_view('JSONView2'))

类视图中的装饰器

装饰器

是用于拓展原来函数功能的函数,它的返回值也是一个函数,可以在不增加其源代码的前提下增加功能。

在视图函数中使用装饰器

# 定义一个装饰器

#需求:查看设置个人信息时,只有检测到用户已经登录了才能查看,若没有登录,则无法查看并给出提示信息

def login_required(func):

# 装饰器必须要有的

@wraps(func)

def wrapper(*args,**kwargs):

username = request.args.get("username")

if username and username == 'momo':

return func(*args,**kwargs)

else:

return '请先登录'

return wrapper

# 功能函数 能够执行成功的前提条件是, 必须先登录【写代码去判断当前用户是否已经登录--》放到自定义装饰器】

@app.route('/setting/')

# 在视图函数中使用自定义装饰器,那么自己定义的装饰器必须放在`app.route`下面。否则这个装饰器就起不到任何作用。

@login_required

def setting():

return '这是设置界面'

在类视图中使用装饰器

在类视图中使用装饰器,是需要重写类视图中的decorators属性,并且把装饰器加到属性中,列表、元组都可以。

class ProfileView(views.View):

# 列表或者元组都行

decorators = [login_required]

def dispatch_request(self):

return '这是个人中心界面'

app.add_url_rule('/profile/',view_func=ProfileView.as_view('profile'))

蓝图(Blueprint)

简介

让Flask更加模块化,更好的管理项目,分层解耦(mvc结构)

基本使用

使用的步骤分为两个步骤导入:在蓝图文件中导入Blueprint from flask import Blueprint users = Blueprint('users',name,url_prefix='/user')

注册:在主py文件中执行蓝图文件中的调用 #(先引入 ‘.’=/) from blueprints.book import books # (在注册) app.register_blueprint(users)

url_prefix参数

如果想要某个蓝图下的所有url都有一个url前缀,那么可以在定义蓝图的时候,指定url_prefix参数,同时也要注意:定义url_profix时,若后边有/,那么以后在定义url与视图函数的时候,就不要再在url前面加斜杠了。

模板文件

寻找规则如果项目中的templates文件夹中有相应的模版文件,就直接使用了。

如果项目中的templates文件夹中没有相应的模版文件,那么就到在定义蓝图的时候指定的路径中寻找。并且蓝图中指定的路径可以为相对路径,相对的是当前这个蓝图文件所在的目录。比如:news_bp = Blueprint('news',name,url_prefix='/news',template_folder='news_page')

注意

蓝图文件查找会默认在template为根目录查找。优先级是template目录要大于自定义目录,所以要想自定义先把template目录中的文件删除。

静态文件

寻找规则

常规写法(必须掌握)

个性化写法(了解)

如果在加载静态文件的时候,指定的蓝图的名字,比如news.static,那么就会到这个蓝图指定的static_folder下查找静态文件。

python:

from flask import Blueprint

news_bp=Blueprint('news',__name__,url_prefix='/news',template_folder='news_page',static_folder='news_page_static')

html

url_for反转蓝图注意事项

注意:要指定蓝图的名字。

场景一

url_for (‘蓝图名称.方法名')

场景二

新闻列表 OK写法

场景三

from flask import Blueprint,render_template,url_for

news_bp = Blueprint('news',__name__,url_prefix='/news',template_folder='news_page',static_folder='news_page_static')

@news_bp.route('/list/')

def news_list():

print(url_for('news.news_detail')) #/news/detail/

return render_template('news_list.html')

蓝图_子域名实现ip地址不能有子域名。

localhost也不能有子域名。

分为四个部分,蓝图文件,默认主页,子域名主页,主PY文件

蓝图文件

from flask import Blueprint,render_template

cms_bp = Blueprint('cms',__name__,subdomain='cms')

#子域名的首页

@cms_bp.route('/')

def hello():

return render_template('cms_index.html')

默认主页

系统主页


ko

ko

ok

学院

子域名主页

子域名首页

学院

主py文件

from blueprints.cms import cms_bp

app.register_blueprint(cms_bp)

app.config['SERVER_NAME']="momo.com:5000"

你可能感兴趣的:(python,flask框架优点)