Flask学习笔记(二)
- 1.知识点
- 1.1虚拟环境
- 1.1.1virtualenv
- 1.1.2virtualenvwrapper
- 1.2web与视图
- 1.3jinja2
- 1.3.1template知识点
- 1.3.2豆瓣列表页
- 1.3.3视图知识点
1.知识点
1.1虚拟环境
1.1.1virtualenv
在系统级python环境下,安装virtualenv虚拟环境。我电脑安装了anconda,所以这一块我就不用操作了。-p参数指定使用系统级的哪一个python.exe 来执行。
win
pip install virtualenv
virtualenv abc#就会在当前地址下新建了一个环境文件夹abc
cd abc/Scripts#进入环境的scripts目录
activate#激活环境
linux
source abc/bin activate#linux是放在bin目录下的
1.1.2virtualenvwrapper
win
pip install virtualenvwrapper-win
mkvirtualenv abc#放在当前win用户的文件夹里面envs的文件夹下
workon abc#激活此环境
deactivate#推出此环境
rmvirtualenv abc#删除此环境
lsvirtualenv abc#列出环境
cdvirtualenv de#立即进入de环境
linux
pip install virtualenvwrapper
1.2web与视图
1.url:scheme://host:port/path/?query-string=xxx#anchor
2.web服务器:负责处理http请求,响应静态文件,常见的有Apache,Nginx以及微软的IIS.
3.应用服务器:负责处理逻辑的服务器。比如php、python的代码,是不能直接通过nginx这种web服务器来处理的,只能通过应用服务器来处理,常见的应用服务器有uwsgi、tomcat等。
4.web应用框架:一般使用某种语言,封装了常用的web功能的框架就是web应用框架,flask、Django以及Java中的SSH(Structs2+Spring3+Hibernate3)框架都是web应用框架。
5.config设置配置文件的四种方式:
app.config['DEBUG'] = True#1.硬编码
app.config.update(DEBUG=True)#2.因为app.config是flask.config.Config的实例,而Config类是继承自dict,因此可以通过update方法
import config
app.config.from_object(config)#3.通过模块对象,将config.py文件的数据导入
app.config.from_pyfile('settings.py',silent=True)#4.也可使用.txt后缀的文件;默认是为False,找不到配置文件就会抛出异常
6.永久性重定向:http的状态码是301,多用于旧网址被废弃了要转到一个新的网址确保用户的访问,最经典的就是京东网站,你输入www.jingdong.com的时候,会被重定向到www.jd.com,因为jingdong.com这个网址已经被废弃了,被改成jd.com,所以这种情况下应该用永久重定向。
7.暂时性重定向:http的状态码是302,表示页面的暂时性跳转。比如访问一个需要权限的网址,如果当前用户没有登录,应该重定向到登录页面,这种情况下,应该用暂时性重定向。
8.redirect(url,code=301)#默认是302
1.3jinja2
1.3.1template知识点
1.在渲染模版的时候,默认会从项目根目录下的templates
目录下查找模版。也可以在Flask
初始化的时候指定template_folder
来指定模版的路径。
app=Flask(__name__,template_folder="xxx")
2.当需要渲染的参数比较多时,通过关键字传参方式,给html渲染传参。
@app.route("/key")
def key():context={"a":1,"b":2,"c":3}return render_template("key.html",**context)#==render_template("key.html","a"=1,"b"=2,"c"=3)
<html><head>key</head><title>key</title><body><h1>a={{a}}</h1> <h1>b={{b}}</h1> <h1>c={{c}}</h1> </body>
</html>
3.html中,{{ … }}:用来装载变量,或者字典的key。
{% … %}:用来装载控制语句。
{# … #}:用来装载注释
4.过滤器:通过管道符号(|)进行使用,过滤器相当于是一个函数,把当前的变量传入到过滤器中,然后过滤器根据自己的功能,再返回相应的值,之后再将结果渲染到页面中。过滤器官网。
abs(value):返回一个数值的绝对值。 例如:-1|abs。
default(value,default_value,boolean=false):如果当前变量没有值,则会使用参数中的值来代替。name|default(‘xiaotuo’)——如果name不存在,则会使用xiaotuo来替代。boolean=False默认是在只有这个变量为undefined的时候才会使用default中的值,如果想使用python的形式判断是否为false,则可以传递boolean=true。也可以使用or来替换。name
or ‘xiaotuo’
escape(value)或e:转义字符,会将<、>等符号转义成HTML中的符号。例如:content|escape或content|e。({%autoescape off/on%} XXXXX{%autoescape%}关掉或开启局部转义)
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):计算一个长字符串中单词的个数。
5.自定义过滤器(两种方式)
app.config['TEMPLATES_AUTO_RELOAD']=True
@app.template_filter('cut')
def cut(value):value=value.replace("hello",'')return value
def datetime_format(value,format="%Y年%m月%d日 %H:%M"):return value.strftime(format)
app.add_template_filter(datetime_format,"dformat")#将自定义的datetime_format,以dformat为名添加到app的过滤器中
自定义时间过滤器
@app.route("/time_filter")
def time_filter():now=datetime(2023,6,25,10,53,20)return render_template("key.html",now=now)
@app.template_filter("handle_time")
def handle_time(time):if isinstance(time,datetime):#首先判断是否时时间类型now=datetime.now()timestamp=(now-time).total_seconds()#时间间距if timestamp<60:return "刚刚"elif timestamp>=60 and timestamp<60*60:minutes=timestamp/60return "%s分钟前"%int(minutes)elif timestamp>=60*60 and timestamp<60*60*24:hours=timestamp/(60*60)return "%s小时前"%int(hours)elif timestamp>=60*60*24 and timestamp<60*60*24*30:days=timestamp/(60*60*24)return "%s天前"%int(days)else:return time.strftime('%Y/%m/%d %H:%M')else:return time
<html><body><h1>now is :{{now|handle_time}}</h1> </body>
</html>
6.for循环(for ,else ,endfor,if),不可以使用continue和break表达式来控制循环的执行
{% for user in users %}<li>{{ user.username}}</li>{% else %}<li>no users found</li>{% endfor %}{% for y in range(1,10) if y<x%}{#y从1开始循环,当不满足y<x时,就会跳出循环#}
参数 | 说明 |
---|---|
loop.index | 当前迭代的索引(从1开始) |
loop.index0 | 当前迭代的索引(从0开始) |
loop.first | 是否是第一次迭代,返回True或False |
loop.last | 是否是最后一次迭代,返回True或False |
loop.length | 序列的长度 |
用for循环写一个99乘法表。
@app.route("/mul")
def mul():return render_template('/mul.html')
<table border="1"><tbody>{% for x in range(1,10) %}<tr>{% for y in range(1,x+1) %}<td>{{y}}*{{x}}={{x*y}}</td>{%endfor%}</tr>{%endfor%}</tbody>
</table>
7.宏:模板中的宏跟python中的函数类似,可以传递参数,但是不能有返回值,可以将一些经常用到的代码片段放到宏中,然后把一些不固定的值抽取出来当成一个变量。
{% macro INPUT(name="",value="",type="text") %}{# 定义一个INPUT函数 #}<input name="{{name}}" value="{{value}}" type="{{type}}">
{% endmacro %}<table><tr><td>用户名</td><td>{{INPUT("username")}}</td></tr><tr><td>密码</td><td>{{INPUT("password",type="password")}}</td></tr><tr><td></td><td>{{INPUT(value="提交",type="submit")}}</td></tr>
</table>
8.导入宏
{% import 'forms.html' as forms %}
{% from 'forms.html' import input as input_field, textarea %}
如果你想要导入一个需要访问当前上下文变量的宏,有两种可能的方法:
A.显式地传入请求或请求对象的属性作为宏的参数。
B.与上下文一起(with context)导入宏。
{% from '_helpers.html' import my_macro with context %}
9.include语句可以把一个模板引入到另外一个模板中,类似于把一个模板的代码copy到另外一个模板的指定位置
{% include 'header.html' %}主体内容
{% include 'footer.html' %}
10.set语句:在模版中,可以使用set
语句来定义全局变量。
{% set username='你好' %}
<p>用户名:{{ username }}</p>
11.with
语句:定义局部变量。
{% with classroom = '你好' %}
<p>班级:{{ classroom }}</p>
{% endwith %}
{% with %}{% set classroom = '你好' %}<p>班级:{{ classroom }}</p>
{% endwith %}
12.继承:默认情况下,子模板如果实现了父模版定义的block。那么子模板block中的代码就会覆盖掉父模板中的代码。如果想要在子模板中仍然保持父模板中的代码,那么可以使用{{ super() }}
来实现。
{% block body_block %}<p style="background: red;">这是父模板中的代码</p>{% endblock %}
{% block body_block %}{{ super() }}<p style="background: green;">我是子模板中的代码</p>
{% endblock %}
如果想要在模版中使用其他模版中的其他代码。那么可以通过{{ self.其他block名字() }}
就可以了。
{% block title %}首页
{% endblock %}{% block body_block %}{{ self.title() }}<p style="background: green;">我是子模板中的代码</p>
{% endblock %}
1.3.2豆瓣列表页
1.3.3视图知识点
1.添加url与视图函数的映射: app.add_url_rule(rule,endpoint=None,view_func=None)
。如果没有填写endpoint
,那么默认会使用view_func
的名字作为endpoint
。以后在使用url_for
的时候,就要看在映射的时候有没有传递endpoint
参数,如果传递了,那么就应该使用endpoint
指定的字符串,如果没有传递,那么就应该使用view_func
的名字。 @app.route(rule,**options)
装饰器:这个装饰器底层,其实也是使用add_url_rule
来实现url与视图函数映射的。
2.类视图:支持继承,但是不能跟函数视图一样,写完类视图还需要通过app.add_url_rule(url_rule,view_func)来进行注册。必须继承自flask.views.View
.,必须实现dipatch_request
方法,以后请求过来后,都会执行这个方法。
标准类视图:
from flask import views,jsonify
class JSONView(views.View):#父类,格式化输出为json格式def get_data(self):raise NotImplementedErrordef dispatch_request(self):return jsonify(self.get_data())class lei_view(JSONView):#子类def get_data(self):return {"username":"xiaoming","password":"123"}app.add_url_rule("/lei/",endpoint="lei",view_func=lei_view.as_view('lei'))
基于请求方法的类视图:继承于views.MethodView。
class LoginView(views.MethodView):def get(self,error=None):return render_template("macro.html",error=error)def post(self):username=request.form.get('username')password=request.form.get('password')print(username,password)if username=="xiaoming" and password=="123":return "登陆成功"else:return self.get(error="用户名或密码错误")
app.add_url_rule("/mylogin/",view_func=LoginView.as_view('my_login'))
3 类视图中的装饰器
函数视图:自己定义的装饰器必须放在app.route
下面。否则这个装饰器就起不到任何作用。
类视图:类内定义类属性decorators
,这个类属性是一个列表或者元组都可以,里面装的就是所有的装饰器。
4.蓝图
from flask import Blueprintuser_bp = Blueprint('user',__name__)
from blueprints.user import user_bpapp.regist_blueprint(user_bp)```
#如果想要某个蓝图下的所有url都有一个url前缀,那么可以在定义蓝图的时候,指定url_prefix参数
user_bp = Blueprint('user',__name__,url_prefix='/user/')
A.在定义url_prefix的时候,要注意后面的斜杠,如果给了,那么以后在定义url与视图函数的时候,就不要再在url前面加斜杠了。
B.如果项目中的templates文件夹中有相应的模版文件,就直接使用了。如果没有,那么就到在定义蓝图的时候指定的路径中寻找。并且蓝图中指定的路径可以为相对路径,相对的是当前这个蓝图文件所在的目录。
news_bp = Blueprint('news',__name__,url_prefix='/news',template_folder='xxx')
C.蓝图中静态文件的查找规则:
* 在模版文件中,加载静态文件,如果使用url_for(‘static’),那么就只会在app指定的静态文件夹目录下查找静态文件。
* 如果在加载静态文件的时候,指定的蓝图的名字,比如news.static
,那么就会到这个蓝图指定的static_folder下查找静态文件(相对于这个蓝图位置的地址)。
news_bp = Blueprint('news',__name__,url_prefix='/news',template_folder='xxx',static_folder='blue_static')
D.url_for反转蓝图中的视图函数为url:
* 如果使用蓝图,那么以后想要反转蓝图中的视图函数为url,那么就应该在使用url_for的时候指定这个蓝图。比如news.news_list
。否则就找不到这个endpoint。在模版中的url_for同样也是要满足这个条件,就是指定蓝图的名字。
* 即使在同一个蓝图中反转视图函数,也要指定蓝图的名字。
E.蓝图实现子域名:
需要在主app文件中,需要配置app.config的SERVER_NAME参数。app.config['SERVER_NAME'] = 'jd.com:5000'
在创建蓝图对象的时候,需要传递一个subdomain
参数,来指定这个子域名的前缀。例如:
cms_bp = Blueprint('cms',__name__,subdomain='ccc')
。
在C:\Windows\System32\drivers\etc
下,找到hosts文件,然后添加域名与本机的映射。
域名和子域名都需要做映射。
127.0.0.1 jd.com
127.0.0.1 ccc.jd.com