• 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) #增加这个参数,可以在修改完毕后不重启直接运行
    View Code

      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
    View Code

      

      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
    View Code

      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'
    View Code

      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')
    View Code
    <!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
    View Code
    <!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 = '123' #当消息提示时会使用秘钥进行加密
    @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()
    View Code

    通过终端运行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)
    View Code

      十三、表单

      备注:

       首先表单提交需要避免跨站请求攻击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="提交")
    View Code

      主配置文件中引入该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)
    View Code

      在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表单样式与校验器样式:

     

      校验器样式:

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

      消息提示:

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

    from flask import Flask, flash, render_template, request
    
    app = Flask(__name__)
    #flask在使用消息提示时,会使用secret_key进行加密
    app.secret_key = '123'
    
    @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 == '123':
            flash('登录成功')
            return render_template('index.html')
        else:
            flash('用户名或密码错误')
            return render_template('index.html')
    if __name__ == '__main__':
        app.run()
    View Code

      异常处理:

      在页面找不到时,需要做异常处理,返回自己特色的页面,而不是使用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')
    View Code

      

  • 相关阅读:
    DISTINCT 方法用于返回唯一不同的值 。
    UNION操作用于合并两个或多个 SELECT 语句的结果集。
    JOIN方法也是连贯操作方法之一
    HAVING方法也是连贯操作之一
    GROUP方法也是连贯操作方法之一
    page方法也是模型的连贯操作方法之一
    limit方法也是模型类的连贯操作方法之一
    order方法属于模型的连贯操作方法之一
    field方法属于模型的连贯操作方法之一
    data方法也是模型类的连贯操作方法之一,
  • 原文地址:https://www.cnblogs.com/xiaopi-python/p/7237912.html
Copyright © 2020-2023  润新知