Python学习笔记第二十三周(Flask架构)

目录:

  一、变量引用

内容:

备注:PyCharm小技巧,comm+alt+l  自动修改格式,comm+alt+return  向上添加新行

  一、变量引用

  1、url生成

  

from flask import Flask,render_template #在Flask中使用render_template代替render使用

app = Flask('__name__')

@app.route('/') #所有的url都使用app.route做装饰器来引用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{{ url_for('static',filename='style.css') }}"/>
</head>
<body>
<h1>{{ title }}</h1>
<a href="{{ url_for('.services') }}">Services</a>
<a href="{{ url_for('.about') }}">About</a>
</body>
</html>

def hello_world():
return render_template('index.html', title='Hello World') @app.route('/services')
def services():
return 'Services!' if __name__ == '__main__':
app.run()

  2、增加debug

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
return '<h1>Hello World!</h1>' if __name__ == '__main__':
app.run(debug=True) #增加这个参数,可以在修改完毕后不重启直接运行

  3、配置文件

  在根目录下使用一个config.py文件,内容:

  DEBUG = True

  在主配置文件中,添加:

  import config

  app = Flask(__name__)

  在这添加config内容:

  app.config.from_object(config)  #通过这种方式添加配置文件

  备注:

  SECRET_KEY和SQLCHAMY均可以放在config.py文件中使用

  二、路由

  1、普通路由,带字符串式

@app.route('/user/<username>')
def user(username):
return 'User %s' % username

  

  2、带数字

  分类:

    1、int

    2、float

    3、path

@app.route('/user1/<int:user_id>')
def user1(user_id):
return 'User_id %s' % user_id

int类型

  

  3、正则表达式方式URL

from flask import Flask, render_template
from werkzeug.routing import BaseConverter class RegexConverter(BaseConverter): def __init__(self,url_map,*items):
super(RegexConverter,self).__init__(url_map)
self.regex = items[0] app = Flask(__name__) app.url_map.converters['regex'] = RegexConverter @app.route('/user2/<regex("[a-z]{3}"):user2_id>')
def user2(user2_id):
return 'user2 %s' % user2_id

  4、url的类型:

  在app.route中的关键字定义有两种:

  • @app.route('/about')   文件名类型,后面不能加‘/’ 这个类似于文件名
  • @app.route('/projects/')  文件夹类型,后面还可以跟文件名

  

  URL反转:

  from flask import Flask,url_for

  @app.route('/')

  def index():

    print(url_for('my_list'))  #通过url_for方式可以将my_list对应的URL打印出来,这种方式通常用于template的文件中,用这种方式映射,在修改了url后,由于url_for对应的是函数名称,所以不受影响,仍然可以映射到正确的视图函数

    print(url_for('article',id='abc'))

    return 'Hello World'

  @app.roue('/list')

  def my_list():

    return 'list'

  @app.route('/article/<id>/')

  def article(id):

    return '你请求的id是%s' %id

反转URL:

  1、什么叫反转URL:从视图函数到url的转换叫反转url

  2、反转url用处:

    在页面重定向时候,会使用url反转

    在模板中,也会使用url反转

  5、Flask中一个views函数对应多个URL

@app.route('/projects/')
@app.route('/program/')
def projects():
return 'The Projects Page'

  6、POST与GET方法

@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
print(username, password)
return redirect(url_for('index'))
# else:
# username = request.args['username'] return render_template('login.html', method=request.method)

  7、上传文件

@app.route('/uploads', methods=['GET', 'POST'])
def uploads():
if request.method == 'POST':
f = request.files['file']
print(f.filename)
basepath = path.abspath(path.dirname(__file__))
upload_path = path.join(basepath, 'static/uploads')
f.save(path.join(upload_path, secure_filename(f.filename)))
return redirect(url_for('uploads'))
return render_template('upload.html')
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/uploads" method="POST" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit" value="提交"/>
</form>
</body>
</html>

load.html

  8、cookie

@app.route('/projects/')
@app.route('/program/')
def projects():
request.cookies['username'] #获取cookie
return 'The Projects Page'

获取cookie

from flask import Flask, render_template, request, redirect, url_for, make_response
from werkzeug.routing import BaseConverter
from os import path
from werkzeug.utils import secure_filename @app.route('/')
def hello_world():
response = make_response(render_template('index.html', title='welcome '))
response.set_cookie('username','a') #设置cookie return response

设置cookie

  9、自定义错误代码页面

app.route('/users/<user_id>')
def users(user_id):
if int(user_id) == 1:
return render_template("user.html")
else:
abort(404) #定义异常代码以便被异常方法捕获

正常用户界面

@app.errorhandler(404)
def page_not_found(error):
return render_template('404.html'), 404
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>404</h1>
<h1>很抱歉!</h1>
<p>访问的页面不存在</p>
</body>
</html>

404.html

  10、消息捕获:

  后端通过flash方法发送提示,前端通过get_flashed_messages()[0]方法来获取提示

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ get_flashed_messages()[0] }}</h1> //由于消息只有一条消息,所以消息提示的数组使用第一条记录
</body>
</html>

前端

from flask import Flask, flash, render_template

app = Flask(__name__)

app.secret_key = '' #当消息提示时会使用秘钥进行加密
@app.route('/')
def hello_world():
flash('hello user')
return render_template('index.html')

后端

  二、包管理

  通过pip命令生成一个requirements文件

  . venv/bin/active

  pip freeze > requirements.txt 生成一个文件

  如果要安装的话:

  pip install -r requirements.txt

  安装包:

  Flask_Script

  

from flask import Flask, render_template, request, redirect, url_for, make_response, abort
from werkzeug.routing import BaseConverter
from os import path
from werkzeug.utils import secure_filename
from flask_script import Manager
# from flask.ext.script import Manager class RegexConverter(BaseConverter):
def __init__(self, url_map, *items):
super(RegexConverter, self).__init__(url_map)
self.regex = items[0] app = Flask(__name__)
# UPLOAD_FOLDER = 'static/uploads/'
# app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.url_map.converters['regex'] = RegexConverter
manager = Manager(app) @app.route('/user2/<regex("[a-z]{3}"):user2_id>')
def user2(user2_id):
return 'user2 %s' % user2_id @app.route('/')
def index():
# abort(404)
response = make_response(render_template('index.html', title='welcome '))
response.set_cookie('username','a') #设置cookie return response @app.errorhandler(404)
def page_not_found(error):
return render_template('404.html'), 404 @app.route('/services')
def services():
return 'Services' @app.route('/user/<username>')
def user(username):
return 'User %s' % username @app.route('/user1/<int:user_id>')
def user1(user_id):
return 'User_id %s' % user_id @app.route('/about')
def about():
return 'About' @app.route('/projects/')
@app.route('/program/')
def projects():
request.cookies['username'] #获取cookie
return 'The Projects Page' @app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
print(username, password)
return redirect(url_for('index'))
# else:
# username = request.args['username'] return render_template('login.html', method=request.method) @app.route('/uploads', methods=['GET', 'POST'])
def uploads():
if request.method == 'POST':
f = request.files['file']
print(f.filename)
basepath = path.abspath(path.dirname(__file__))
upload_path = path.join(basepath, 'static/uploads')
f.save(path.join(upload_path, secure_filename(f.filename)))
return redirect(url_for('uploads'))
return render_template('upload.html') if __name__ == '__main__':
# app.run(debug=True)
manager.run()

通过终端运行python3 learn_flask.py runserver

  三、jinjia2模板

  首先创建flask项目后 ,需要写两个文件夹,static和template

  在template目录里写一个index.html文件:

  <body>

    <p>用户名:{{ username }}</p>

    <p>年龄:{{ age }}</p>

    <p>性别:{{ gender }}</p>

  </body>

  在视图函数里添加:

  from flask import Flask,render_template

  @app.route('/')

  def index():

    contex ={

        'username': 'gavin',

        'age': '18',

        ''gender:'male',

        }

    return render_template('index.html',**context)  #如果有多个参数需要传递,可以使用字典的方式进行传参

 

  在模板中如果要使用一般变量,语法{{变量名}}

  访问模型中的属性或者字典,可以通过‘{{ params.property }}’的形式,或者是使用{{ params['age'] }}的形式

  例子:

    index.html中:

    <p>{{ person.name }}</p>

    <p>{{ person.age }}</p>

    <p>{{ websites.baidu }}</p>

    <p>{{ websites.google }}</p>

  视图函数中:

  

from flask import Flask,render_template

  @app.route('/')

  def index():

    class Person(object):

      name = 'gavin'

      age = 18

    p = Person()

    contex ={

        'username': 'gavin',

        'age': '18',

        ''gender:'male',

        'person': p,

        'websites':{

          'baidu': 'www.baidu.com',

          'google': 'www.google.com.hk',

             },

        }

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

   备注:

   在jinjia2中可以针对传递的变量的索引进行操作:

    例子:

    1、 {% if loop.index is odd %}| {% endif %} 如果索引为奇数,加 |

    2、{% if not loop.first %} |{% endif %}   如果不是第一个索引,加 |

  2、if判断:

    index.html中:

    {% if user and user.age > 18 %}

    {{内容}}

    {% else %}

    {{内容}}

    {% endif %}

   3、for循环

    字典的遍历:可以使用items()/keys()/values()/iteritems()/iterkeys()/itervalues()

    index.html中:

    {% for k,v in user.items() %}

    <p>{{k}}: {{v}}</p>

    {% endfor%}

    列表的遍历:

    {% for a in list1 %}

      {{a}} 

    {% endfor %}

    4、过滤器

    介绍:可以处理变量,原始的变量经过处理后展示出来,作用的对象的变量

    语法:

      {{  avater|default(‘xxx’)}}  如果当前变量不存在,可以指定默认值

      <p>评论数 {{  comments|length }}</p>  求列表、字符串、字典、元组的长度

      

    5、继承

    作用:可以把一些公共的代码放在base模板中

    语法:

    {% extends  ‘base.html’%}

    {%block XXX%}

    {% endblock %}

    block实现:

    作用:可以让子模板实现一些自己的需求,父模板必须定义好

    子模板中的代码,必须放在block块中

  四、URL链接和静态文件

    url链接:使用url_for(‘视图函数名称’),可以反正url

    加载静态文件:

    1、语法:‘url_for('static',filename='路径')’

    2、静态文件,flask会从static文件夹汇总开始寻找,所以不需要再写static这个路径了

    3、可以加载css文件、js文件、iamge文件

    例子:

    首先static目录下建立css目录,在css目录下建立index.css文件

    然后在index.html中添加<link rel='stylesheet' href="{{ url_for('static',filename="css/index.css") }}"> 

  

  五、SQLAlchemy:

    配置文件:

    config.py:

    DIALECT = 'mysql'

    DRIVER = 'mysqldb'

    USRNAME = 'root'

    PASSWORD = 'root'

    HOST = '127.0.0.1'

    PORT = '3306'

    DATABASE = 'db_demo1'

    SQLALCHEMY_DATABASE_URI = "{}+{}://{}:{}@{}:{}/{}?charset=utf8".format(DIALECT,DRIVER,USRNAME,PASSWORD,HOST,PORT,DATABASE)

    SQLALCHEMY_TRACK_MODIFICATIONS = True

    

    视图函数:

    from flask_sqlalchemy import SQLAlchemy

    import config

    app = Flask(__name__)

    app.config.from_object(config)

    db = SQLALchemy(app)

    #article表

    class Article(db.Model):

      __tablename__ = 'article'

      id = db.Column(db.Integer,primary_key=True,autoincrement=True)

      title = db.Column(db.String(100),nullable=False)

      content = db.Column(db.Text,nullable=False)

    db.create_all()#创建表

    

    对数据库进行增删改查操作:

         

    视图函数中:

    @app.route('/')

    def index():

      #增加

      article = Article(title='a',content='b')

      db.session.add(article)

      #事务操作(必须有commit才进行操作,上面操作还没有进行事务操作)

      db.session.commit()#完成事务操作后才真正写入数据库中

      

    #查

    @app.route('/')

    def index():

      result = Article.query.filter(Article.title=='a').all()  #query是专门用于查找的,query是从db.Model中继承下来的,这里返回的是Query对象,如果想只取第一个对象,可以使用first()代替all()     

      print(result[0].title,result[0].content) 

    #改

    1、先把要改的数据查找出来

    2、对该数据进行更改

    3、做事务提交

    article = Article.query.filter(Article.title='a').first()

    article.title = 'new title'

    db.session.commit()

    

    #删

    article = Article.query.filter(Article.title='a').first()

    db.session.delete(article)

    db.session.commit()

    

    外键约束:

    语法:

      author_id = db.Column(db.Integer,db.ForeignKey('user.id'))

      author = db.relationship('User',backref=db.backref('articles'))#这个模型添加一个author属性,可以访问这篇文章的作者的数据,像访问普通模型一样

      backref是定义反向引用,可以通过User.articles这个模型访问这个模型所写的所有文章      

    

    例子:

    首先创建了两个表

    class User(db.Model):

      __tablename__ = 'user'

      id = db.Column(db.Integer,primary_key=True,autoincrement=True)

      username = db.Column(db.String(100),nullable=False)

    class Article(db.Model):  

      __tablename__ = 'article'

      id = db.Column(db.Integer,primary_key=True,autoincrement=True)

      title = db.Column(db.String(100),nullable=False)

      content = db.Column(db.Text,nullable=False)

      author_id = db.Column(db.Integer,db.ForeignKey('user.id'))

      author = db.relationship('User',backref=db.backref('articles'))   #第一个参数是管理到那个模型的名字

    db.create_all()

    

    #添加文章与用户    

    @app.route('/')

    def index():

      user1 = User(username='gavin')

      db.session.add(user1)

      article = Article(title='a',content='b')

      article.author = User.query.filter(id==1).first() #在添加作者时通过author方式进行添加

      db.session.add(aricle)

      db.session.commit()  

      #需求:要找标题为a的文章的作者    

      article = Article.query.filter(Article.title=='a').first()  

      print(article.author.username) #通过title查找作者

      #需求:找到作者写过的所有文章

      author = User.query.filtr(User.username=='gavin').first()

      result = author.articles

      for article in result:

        print(print.article.title)

   

    多对多:

    article_tag = db.Table('article_tag'

            db.Column('article_id',db.Integer,db.ForeignKey('article_id'),primary_key=True),

            db.Column('tag_id', db.Integer.db.ForeighKey('tag_id'),primary_key=True),

            

          )

    class Article(db.Model):  

      __tablename__ = 'article'

      id = db.Column(db.Integer,primary_key=True,autoincrement=True)

      title = db.Column(db.String(100),nullable=False)

      tags = db.relationship('Tag', secondary=article_tag,backhref=db.backhref('articles'))

    class Tag(db.Model):  

      __tablename__ = 'tag'

      id = db.Column(db.Integer,primary_key=True,autoincrement=True)

      name = db.Column(db.String(100),nullable=False)

   

    db.create_all()

    

    @app.route('/')

    def index():

      article1 = Article(title='aaa')

      article2 = Article(title='bbb') 

      

      tag1 = Tag(name='111')  

      tag2 = Tag(name='222')  

      article1.tags.append(tag1)

      article1.tags.append(tag2)

      article2.tags.append(tag1)

      article.2tags.append(tag2)

      db.session.add_all(article1,article2,tag1,tag2) 

      db.session.commit()

      article1 = Article.query.filter(Article.title=='aaa').first()

      tags = article1.tags

      for tag in tags:

        print(tag.name)

           

 备注:

  如果要求前端显示按照顺序进行,可以添加:order_by(),在括号内需要添加models里对应数据库函数对应的条目,例如order_by('create_time')

就是按照创建时间来排序,按照正序方式进行,如果想倒序,只需要order_by('-create_time')方式来进行

  六、flask-script

    作用:通过命令行的形式操作flask,例如通过命令跑一个并发版本的服务器,设置数据库,定时任务等,要使用flask-scrtipt,可以通过pip install flask-script安装最新版本,首先看一个简单的例子:

    创建一个manager.py文件:

    from flask_script import Manager

    from your_app import app

    manager = Manager(app)

    @manager.command

    def hello():

      print('hello')

    if __name__ == '__main__':

      manager.run()

    可以在script中完成数据库操作:

    1、创建一个db_scrtipt.py文件

    from flask_script import Manager

    DBmanager = Manger()

    @DBmanager.command

    def init():

      print('数据库初始化完成')

    @DBmanager.command

    def migrate():

      print('数据表迁移完成')

    回到manage.py文件中添加:

    

    from flask_script import Manager

    from your_app import app

    from db_script import DBmanager

    manager = Manager(app)

    @manager.command

    def hello():

      print('hello')

    manager.add_command('db',DBmanager)  #db表示想要操作DBmanager的话使用的一个标示,可以是任意,后面DBmanger表示引用

    if __name__ == '__main__':

      manager.run()

    

    执行操作:

    python3 manage.py db init #完成初始化操作

    python3 manage.py db migrate #完成迁移操作

    定义命令的三种方法:

    1、使用@command装饰器

    2、使用类继承自Command类:

       

  七、分开models和解决循环引用

    1、分开models的目的,是为了代码简洁

    2、解决循环引用的方法,把db放在另外一个文件中,切断循环引用

  

  八、flask_migrate

    

    例子:

    1、创建exts.py文件:

     from flask_sqlalchemy import SQLAlchemy

     db = SQLAlchemy()

    2、创建models.py文件

     from exts import db

    

     def Article(db.Model):

        __tablename__ = 'article' 

        id = db.Column(db.Integer,primary_key= True,autocrement=True)

        title = db.Column(db.String(100),nullable=False) 

    3、config.py文件   

    DIALECT = 'mysql'

    DRIVER = 'mysqldb'

    USRNAME = 'root'

    PASSWORD = 'root'

    HOST = '127.0.0.1'

    PORT = '3306'

    DATABASE = 'db_demo1'

    SQLALCHEMY_DATABASE_URI = "{}+{}://{}:{}@{}:{}/{}?charset=utf8".format(DIALECT,DRIVER,USRNAME,PASSWORD,HOST,PORT,DATABASE)

    SQLALCHEMY_TRACK_MODIFICATIONS = True

     

    4、视图函数

    from flask import Flask 

    from exts import db

    from models import Article

    import config

    app = Flask(__name__)

    app.config.from_object(config)

    db.init_app(app) #由于exts没有指定哪个数据库,所以需要在这里重新指定    

    with app.app_context():

      db.create_all()      

   如果此时要添加数据库的结构,需要进行migrate

    1、介绍:因为采用db.create_all()在后期修改字段的时候,不会字段的映射到数据库中,必须删除表,然后重新运行,这样不符合我的要求,因此flask-migrate就是为了解决这种歌问题,它可以在每次修改模型后,可以将修改的东西映射到数据库中

    2、首先进入到虚拟机环境中,然后使用pip install flask_migrate进行安装

  使用:

    1、flask-script方式

  首先创建manage.py文件 : 

    from flask_script import Manager

    from <视图函数名字> import app

    from flask_migrate import Migrate,MigrateCommand

    from models import Article #需要导入这个,migrate才知道要对哪个表进行迁移

    from exts import db

    manager = Manager(app)

    #1、要使用flask_migrate,必须绑定db和app

    migrate = Migrate(app,db)

    #2、把MigrateCommand命令加到manager中

    manager.add_command('db', MigrateCommand)

    if __name__ == '__main__':

      manager.run()

    其次回到视图函数中,将

    with app.app_context():

      db.create_all() 

    条目删除

    最后执行:#模型-->迁移文件 --> 表

    python manage.py db init  #生成migrate文件夹

    python manage.py db migrate #将模型生成迁移文件 

    python manage.py db upgrade #将迁移文件生成表

       

    

    

 九、cookie和session

   1、cookie:出现原因:在网站里,http请求是无状态的,也就是说即使第一次和服务器连接后并且登录成功,第二次请求服务器依然不知道当前请求是哪个用户,cookie的出现就是为了解决这个问题,第一次登录服务器返回一个数据cookie给浏览器,然后浏览器保存再本地,当该用户第二次请求时,就会自动把上次请求存储的cookie数据字典携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个

   2、如果服务器返回了cookie给浏览器,那么浏览器下次再请求相同的服务器时,会自动把cookie发送给服务器,这个过程中,用户不需要管

   3、cookie是保存在浏览器中,相对的的是浏览器

     session:

   1、session介绍:session和cookie的作用类似都是为了保存用户相关形象,不同的是cookie是存储在浏览器,而session是存储在服务器,存在服务器的数据更加安全,不容易被窃取,但存储在服务器也有一定的弊端,就是会占用服务器资源,但是现在服务器发展到今天,这些session新潮存储绰绰有余

   2、使用session的好处:

    敏感数据不是直接发送给浏览器,而是发送回一个session_id 服务器将session_id和敏感数据做一个映射存储在session(服务器上面)中,更加安全

    session可以设置过期时间,也从另外一个方面,保存了用户的账号安全

   flask中session工作机制:

    flask中的session机制:把敏感数据加密后放入session中,再把session存放在cookie中,下次请求的时候,再从浏览器发送过来的cookie中读取session,在从session中读取敏感数据,并进行解密,获取最终数据

    flask的这种session机制,可以节省服务器开销,因为把所有的信息都存在到了客户端(浏览器)

    安全是相对的,吧session放到cookie中也是经过加密的

   例子:

    视图函数:

    

    from flask import Flask,session 

    app = Flask(__name__)

    #添加数据到session中

    #操作session的时候,和操作字典是一样的

    #SECRET_KEY 放在config.py文件中,或者直接单独设置

    import os

    #app.config[SECRET_KEY] = '必须24个字符的字符串'

    app.config['SECRET_KEY'] = os.urandom(24)

    #如果不想超时时间为31天(默认)可以按照如下设置

    from datetime import timedelta

    app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)

    @app.route('/')

    def hello_world():

      #如果没有指定session过期时间,那么在浏览器结束就过期

      session['username'] = 'gavin'

      #如果设置session.permanent=True,默认情况下(没有设置app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(XX))session的超时时间为31天

      session.permanent = True

      return 'hellow world'

    @app.route('/get/')

    def get():

      #获取session,如果不存在会返回None

      return session.get('username')

    @app.route('/delete')

    def delete():

      print(session.get('username'))

      #删除session

      session.pop('username')

      print session.get('username')

      return 'success'

    

    @app.route('/clear/')

    def clear():

      print(session.get('username'))

      #删除session中的所有数据

      session.clear()

      print session.get('username')

      return 'success'

    

    if __name__ == '__main__':

      app.run(debug=True)

  十、get与post请求

    1、get请求:

      使用场景:如果只对服务器获取数据不对服务器产生影响,使用get请求

      传参: get请求传参是放在url中并且是通过?的形式来指定key和value的

    2、post请求:

      使用场景:如果要对服务器产生影响,使用post请求

      传参:post请求传参是通过form data的形式发送给服务器

    例子:   

    from flask import Flask,render_tempalte,request 

    app = Flask(__name__)

    @app.route('/')

    def index():

      return render_template('index.html')

    @app.route('/search/')

    def search():

      #arguments,以字典的形式获取url中所有参数

      print(request.args) #get请求可以通过request.args来获取数据,post请求可以通过request.form.get来获取数据

      return 'success'

    #默认的视图函数只能采用get请求,如果要采用post请求,要单独说明

    @app.route('/login/',method=['GET','POST'])

    def login():

      if request.method == 'POST':

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

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

        

      return 'login'

    在index.html中:

    <a href="{{  urlf_for('search',q="hello")}}">跳转到搜索</a>

    在login.html中:

    <form action='{{ url_for('login')}}' method='post'>

      <input type='text' name="username"/>

      <input type='password'  name='password'/>

      <inpu ttype='submit' />

    </form>

    

  十一、g变量

  g变量就是global的简称,可以使用:

  from flask import g的方式调用,

  在g变量中可以使用类似于jinjia2的方式赋值,g.username = ‘gavin’  、g.password=123

  在g变量引入后,在整个项目的其他文件想引用,可以直接从from flask import g后直接引用,无序通过传参方式赋值,但是g只在每一次请求时生效,等下一次请求时g会被第二次赋值,就不是原来的数据了

  十二、钩子函数

    1、before_request 在任何请求之前执行,在执行完毕后再执行视图函数中其他函数,这个代码只是一个装饰器,它可以把需要设置为钩子函数的代码放到视图函数执行之前来执行

    例子:

    视图函数:

    from flask import Flask,render_template,request,session,redirect,url_for,g

    import os

    app = Flask(__name__)

    app.config['SECRET_KEY'] = os.urandom(24)

    @app.route('/')

    def index():

    return render_to_template('index.html')

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

    def login():

      if request.method == 'post':

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

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

        if username == 'gavin' and password == '123':

          session['username'] == username

          return 'success'

        else:

          return 'fail to login'

      return render_template('login.html')

    @app.route('/edit/')

    def edit():

      

        

      if hasattr(g,'username'):

        return '修改成功'

      else:

        return direct(url_for('login'))

    

    @app.before_request

    def my_before_request():

      user_id = session.get('user_id')

      user = User.query.filter(User.id == user_id).first()

      if session.get('username'):

        g.username = session.get('username')

               

    if __name__ == '__main__':

      app.run(debug=True)

    

    在login.html中:

    <form action='{{ url_for('login')}}' method='post'>

      <input type='text' name="username"/>

      <input type='password'  name='password'/>

      <inpu ttype='submit' />

    </form>

    

    2、context_processor

       上下文处理器应该返回一个字典,字典中的key会被模板中当做变量来渲染

       上下文处理器中返回的字典,在所有页面都是可用的

         被这个装饰器修饰的钩子函数,必须返回一个字典,即使是空的字典

    例子:

    from flask import Flask,render_template,request,session,redirect,url_for,g

    import os

    app = Flask(__name__)

    app.config['SECRET_KEY'] = os.urandom(24)

    @app.route('/')

    def index():

    return render_to_template('index.html')#有了context_processor以后,不需要在这里传递参数,template里的html文件照样可以接收模板文件

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

    def login():

      if request.method == 'post':

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

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

        if username == 'gavin' and password == '123':

          session['username'] == username

          return 'success'

        else:

          return 'fail to login'

      return render_template('login.html')

    @app.route('/edit/')

    def edit():

      

        

      if hasattr(g,'username'):

        return '修改成功'

      else:

        return direct(url_for('login'))

    

    @app.before_request

    def my_before_request():

      user_id = session.get('user_id')

      user = User.query.filter(User.id == user_id).first()

      if session.get('username'):

        g.username = session.get('username',)

    @app.context_processor

    def my_context_processor():

      username = session.get('username')

      if username:

        return {'username': username} #返回了这个字典,在所有模板里都会把这个当做模板去渲染

              

    if __name__ == '__main__':

      app.run(debug=True)

  十二、livereload方法

    livereload方法可以实现自动加载任意修改的界面     

from flask import Flask, render_template
from livereload import Server app = Flask(__name__) @app.route('/')
def index():
return render_template('index.html', title="<h1>Hello World!</h1>") if __name__ == '__main__':
#导入app.wsgi服务
live_server = Server(app.wsgi_app)
#watch用来监控哪个界面,这种方式表示所有页面
live_server.watch('**/*.*')
#开启livereload服务
live_server.serve(open_url_delay=True)

  十三、表单

  备注:

   首先表单提交需要避免跨站请求攻击CSRF

  创建一个config.py文件

import os

DEBUG = True

SECRET_KEY = os.urandom(24)

config.py

  创建forms.py文件,里面填写表单内容

from flask_wtf import Form
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired class LoginForm(Form):
#DataRequired()要求这个字段必须有值
username = StringField(label="用户名", validators=[DataRequired()])
password = PasswordField(label="密码", validators=[DataRequired()])
submit = SubmitField(label="提交")

  主配置文件中引入该forms.py文件

from flask import Flask, render_template
from livereload import Server
from flask_bootstrap import Bootstrap import config app = Flask(__name__)
app.config.from_object(config)
bootstrap = Bootstrap(app) @app.route('/login/',methods=['GET','POSt'])
def login():
from forms import LoginForm
form = LoginForm()
return render_template('login.html',title="登录",form=form)

  在login.html文件中添加

{% extends "bootstrap/base.html" %}
{% block content %}
<div class="container">
<form action="{{ url_for('login') }}" method="POSt"> {{ form.username.label }}
{{ form.username() }}
{{ form.password.label }}
{{ form.password() }}
{{form.submit() }}
</form>
</div>
{% endblock %}

  wtf表单样式与校验器样式:

Python学习笔记第二十三周(Flask架构) 

  校验器样式:

Python学习笔记第二十三周(Flask架构)

  十四、消息提示和异常处理

  消息提示:

  在登录页面,如果有步骤错误,比如没输入用户名或密码,都会有消息提示,在flask中使用flash()方式进行消息提示,这个提示在前端html中,使用{{get_flashed_messages()}}方式来获取

from flask import Flask, flash, render_template, request

app = Flask(__name__)
#flask在使用消息提示时,会使用secret_key进行加密
app.secret_key = '' @app.route('/')
def hello_world():
flash('Hello Gavin')
return render_template('index.html') @app.route('/login',methods=['get','post'])
def login():
username = request.form.get('username')
password = request.form.get('password') if not username:
flash("请输入用户名")
return render_template('index.html')
if not password:
flash('请输入密码')
return render_template('index.html')
elif username == 'gavin' and password == '':
flash('登录成功')
return render_template('index.html')
else:
flash('用户名或密码错误')
return render_template('index.html')
if __name__ == '__main__':
app.run()

  异常处理:

  在页面找不到时,需要做异常处理,返回自己特色的页面,而不是使用flask提供的原生页面

@app.route('/users/<user_id>')
def users(user_id):
if int(user_id) == 1: return render_template('user.html',user_id=user_id)
else:
#如果条件不满足,置为状态码,然后送入到异常处理界面处理
abort(404)
#使用errorhandler来处理404异常,如果捕获到异常就按照下面的函数进行处理
@app.errorhandler(404)
def not_found(error):
return render_template('404.html')

  

上一篇:webpack4.0各个击破(6)—— Loader篇


下一篇:关于LookAt