Flask框架

#从flask这个框架中导入Flask这个类
from flask import Flask

# 初始化一个Flask对象
# 需要传递一个参数__name__
# 1.方便flask框架寻找资源
# 2.方便flask插件比如Flask-Sqlalchemy出现错误的时候,好去寻找问题所在的位置
app = Flask(__name__)

# @app.route是一个装饰器
# @开头,并且在函数的上面,说明是装饰器
# 这个装饰器的作用是,做一个url与视图函数的映射
# 127.0.0.1:5000/ -->去请求hello_world函数,然后将结果返回给浏览器
@app.route('/')
def hello_world():
    return 'Hello World!'

#如果当前这个文件是做为入口程序运行,那么就执行app.run()
if __name__ == '__main__':
    # app.run()
    # 启动一个应用服务器,来接受用户的请求
    # while True:
    #   listen()
    app.run()

 

### 设置debug模式

app.run(debug=True)

Debug 模式两大功能

* 当程序出现问题的时候,可以在页面中看到错误信息和出错位置

* 只要修改了项目中的.py文件,程序会自动加载,不需要手动重新启动服务器

 

### 使用配置文件

1. 新建一个config.py文件

2. 在主app文件中导入这个文件,并且配置到’app’中

示例代码如下

```

import config
app.config.from_object(config)

```

 

### url传参数

1. 参数的作用: 可以在相同的URL,但是指定不同的参数,来加载不同的数据

2. 在flask中如何使用参数

```

@app.route('/article/<id>')
def article(id):
    return '您请求的参数是: %s' %id

* 参数需要放在<>中

* 视图函数中需要放和url中的同名的参数

```

 

### 反转URL

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

2. 反转url的好处:

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

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

代码示例:

@app.route('/')
defindex():
    print(url_for('my_list'))
    print(url_for('article',id='abc'))
    return'Hello World!123'

@app.route('/list/')

def my_list():
    return 'list'

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

defarticle(id):
    return'您请求的参数是: %s' %id

 

 

### 页面跳转和重定向

1. 用处: 在用户访问一些需要登录的页面的时候,如果用户没有登录,那么可以让他重定向到登录页面

@app.route('/')
defindex():
    login_url=url_for('login')
    returnredirect(login_url)
    return'这是首页'

@app.route('/login/')

deflogin():
    return'这是登录页面'

 

 

### 模板渲染和参数传递

1.如何渲染模板:

  * 模板放在`templates`文件夹下

  * 从`flask`中导入`render_template`函数

  * 在视图函数中,使用`render_template`函数,不需要填写template路径

 @app.route('/')
defindex():
    return render_template('index.html')

2.模板传参:

* 如果只有一个或少量参数

 return render_template('index.html',username=’mike’)

* 如果有多个参数的时候,那么可以把所有参数放在字典中

@app.route('/')
def index():
    context={
        'username' : '瞿诗寒',
        'sex' : '男',
        'age' : 18
    }
    return render_template('index.html',**context)

* 在模板中,如果要使用一个变量,语法`{{params}}`

* 访问模型中的属性或者是字典,可以通过`{{websites.baidu}} `或者`{{websites[‘baidu’]}}`

 

### if判断语句

Jinja2

{% if user and user.age>19 %}
    <a href="#">{{ user.username }}</a>
    <a href="#">注销</a>
{% else %}
    <a href="#">登录</a>
    <a href="#">注册</a>
{% endif %}

 

### for循环遍历列表和字典

语法和python一样可以用 items() keys() values() iteritems() iterkeys() itervalues()

<table>
    <thead>
        <th>书名</th>
        <th>作者</th>
        <th>价格</th>
    </thead>
    <tbody>
        {% for book in books %}
            <tr>
                <td>{{ book.name }}</td>
                <td>{{ book.author }}</td>
                <td>{{ book.price }}</td>
            </tr>
        {% endfor %}
    </tbody>
</table>

 

@app.route('/')
def index():
    books=[
        {
            'name': '西游记',
            'author': '吴承恩',
            'price': 100
        },
        {
            'name': '红楼梦',
            'author': '曹雪芹',
            'price': 200
        },
        {
            'name': '三国演义',
            'author': '罗贯中',
            'price': 300
        },
        {
            'name': '水浒传',
            'author': '施耐庵',
            'price': 130
        }
    ]
    return render_template('index.html',books=books)

 

### 过滤器

作用的对象是模板中的变量{{param}}

* 介绍: 过滤器可以处理变量,把原始的变量经过处理后再展示出来

语法:{{ avatar|default('https://ss1.bdstatic.com/fm=27&gp=0.jpg') }}

 * default过滤器: 如果当前变量不存在,这时候可以指定默认值

 * length过滤器: 求列表或字符串或者字典或者元组的长度

@app.route('/')
def index():
    comments=[
        {
            'user':'mike',
            'content': '123123'
        },

        {
            'user': 'mike',
            'content': '123123'
        }

    ]
    return render_template('index.html',comments=comments)

 

<p>评论数:({{ comments|length }})</p>
<ul>
    {% for comment in comments %}
        <li>
            <a href="#">{{ comment.user }}</a>
            <p>{{ comment.content }}</p>
        </li>
    {% endfor %}
</ul>

 

### 继承和block: 参见flaskstu3

1. 继承作用和用法

* 作用: 可以把一些公共的代码放在父模板中,避免每个模板写同样的代码

* 语法

{% extends 'base.html' %}

2. block实现  

* 作用: 可以让子模版实现一些自己的需求,父模板提前定义好

* 注意点: 子模版中的代码,必须放在block块中

 

### url链接: 参见flaskstu4

<a href="{{ url_for('login') }}">登录</a>

 

### 加载静态文件: 参见flaskstu4

1. 语法

加载css文件

<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css') }}"/>

加载 js文件

<script src="{{ url_for('static',filename='js/index.js') }}"></script>

加载 image文件

<img src="{{ url_for('static',filename='images/1.jpg') }}" alt=""/>

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

3. 可以加载 css js image文件

 

Flask-SQLAlchemy的安装介绍

  1. ORM:object Relationship Mapping(模型关系映射)
  2. Flask-sqlalchemy 是一套ORM框架
  3. ORM的好处:可以让我们操作数据库跟操作对象是一样的,非常方便,因为一个表抽象为一个类,一条数据就抽象成该类的一个对象

### Flask-SQLAlchemy使用

1.初始化和设置数据库配置信息

*使用flask_sqlalchemy中的SQLALchemy进行初始化:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import config
app = Flask(__name__)
app.config.from_object(config)
db=SQLAlchemy(app)

2.设置配置信息

在config.py文件中添加以下配置信息

# dialect+driver://username:password@host:post/database
DIALECT = 'mysql'
DRIVER = 'mysqldb'
USERNAME = 'root'
PASSWORD = 'root'
HOST = '127.0.0.1'
PORT = '3306'
DATABASE = 'db_demo1'
SQLALCHEMY_DATABASE_URI="{}+{}://{}:{}@{}:{}/{}".format(DIALECT,DRIVER,USERNAME,PASSWORD,HOST,PORT,DATABASE)

 

### 使用Flask-SQLAlchemy创建模型与表的映射

1. 模型需要继承自db.Model, 然后需要映射到表中的属性,必须写成db.Column的数据类型

2. 数据类型

  * db.Integer 代表的是整型

  * db.String 代表的是varchar 需要指定最长长度

  * db.Text 代表的是 text

3. 最后需要调用db.create_all 来将模型真正的创建到数据库中

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import config
app = Flask(__name__)
app.config.from_object(config)
db=SQLAlchemy(app)

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():
    return 'index!'

if __name__ == '__main__':

    app.run(debug=True)

 

### Flask-SQLAlchemy数据的增、删、改、查

1. 增

@app.route('/')
def index():
    # 增加:
    article1=Article(title='aaa',content='bbb')
    db.session.add(article1)
    # 事务
    db.session.commit()
    return 'index!'

2. 查

@app.route('/')
def index():
# 查
result=Article.query.filter(Article.title=='aaa').all()
article1=result[0]
print(article1.title)
print(article1.content)
return 'index!'

3. 改

@app.route('/')
def index():
# 改
# 1. 先把你要更改的数据查找出来
article1 = Article.query.filter(Article.title=='aaa').first()
# 2. 把这条数据,你需要修改的地方进行修改
article1.title='new title'
# 3. 做事物的提交

db.session.commit()
return 'index!'

4. 删

@app.route('/')
def index():
# 删
# 1. 把需要删除的数据查找出来
article1=Article.query.filter(Article.content=='bbb').first()
# 2. 把这条数据删除掉
db.session.delete(article1)
# 3. 做事务提交
db.session.commit()
return 'index!'

 

Flask-SQLAlchemy 外键及其关系

 * backref 是定义反向引用通过User.articles 范文这个模型所写文章

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import config

app = Flask(__name__)
app.config.from_object(config)
db=SQLAlchemy(app)

# 用户表
# create table users(
#     id int primary key auto_increment,
#     username varchar(100) not null
# )
# 文章表
# create table article (
#     id int primary key auto_increment
#     title varchar(100) not null,
#     content text not null,
#     author_id int,
#     foreign key 'author_id' references 'users.id'
# )

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='zhiliao')
    # db.session.add(user1)
    # db.session.commit()
    # article1 = Article(title='aaa',content='bbb',author_id=3)
    # db.session.add(article1)
    # db.session.commit()

    # 我要找文章标题为aaa的这个作者
    # artile=Article.query.filter(Article.title=='aaa').first()
    # author_id=artile.author_id
    # user=User.query.filter(User.id==author_id).first()
    # print(user.username)

    # article = Article(title='aaa',content='bbb')
    # article.author = User.query.filter(User.id==3).first()
    # db.session.add(article)
    # db.session.commit()

    # 找文章标题为aaa的作者
    # artile= Article.query.filter(Article.title=='aaa').first()
    # print(artile.author.username)

    # 我要找到zhiliao这个用户的所有文章
    user = User.query.filter(User.username=='zhiliao').first()
    result=user.articles
    for article1 in result:
        print('-'*10)
        print(article1.title)
    return 'index!'

if __name__ == '__main__':

    app.run(debug=True)

 

多对多关系

* 需要通过一个中间表进行关联

* 中间表,不能通过`class`的方式实现,只能通过`db.Table`实现

需要使用一个关键字参数 secondary=中间表来进行关联

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import config

app = Flask(__name__)
app.config.from_object(config)
db=SQLAlchemy(app)

# create table article()(
#     id int primary key auto_increment,
#     title varchar(100)
# )
# create table tag(
#     id int primary key auto_increment,
#     name varchar(50) not null,
# )
# create table article_tag(
#     article_id int,
#     tag_id int,
#     primary key(article_id,tag_id),
#     foreign key `article_id`  references `article.id`
#     foreign `key tag`_id references `tag.id`
# )
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.ForeignKey('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,backref=db.backref('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)
    # article2.tags.append(tag2)
    # db.session.add(article1)
    # db.session.add(article2)
    # db.session.add(tag1)
    # db.session.add(tag2)
    # db.session.commit()

    article1=Article.query.filter(Article.title=='aaa').first()
    tags=article1.tags
    for tag in tags:
        print(tag.name)
    return 'index!'

if __name__ == '__main__':

    app.run(debug=True)

 

### 分开models以及解决循环引用

1. 分开models的目的:为了让代码更加方便的管理

2. 如果解决循环引用:把db放在一个单独的文件中,切断循环引用

exts.py

from flask_sqlalchemy import SQLAlchemy
db=SQLAlchemy()

models.py

from exts import db
class Article(db.Model):
    __tablename__='article'
    id=db.Column(db.Integer,primary_key=True,autoincrement=True)

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

Flaskstu5.py

from flask import Flask
import config
from models import Article
from exts import db

app = Flask(__name__)
app.config.from_object(config)
db.init_app(app)

#把app推到app栈顶上了
with app.app_context():
    db.create_all()

@app.route('/')
def index():
    return 'index!'
if __name__ == '__main__':

    app.run(debug=True)

 

 

### Flask-Migrate的介绍与安装:

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

 

 

Cookie和session

Cookie 在网站中 http请求是无状态的,也就是说即使第一次和服务器连接并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户

Cookie,第一次登录后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是哪个,cookie存储的数据量有限,一般不超过4kb。

 

Cookie和session区别 cookie是存储在本地浏览器,而session存储于服务器,存储在服务器的数据更加安全,不容易被窃取,但存储在服务器也有一定的弊端,就是会占用资源

 

使用session的好处

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

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

 

用户登录成功,把用户的信息经过加密后存放到session中,并且产生一个唯一的session_id,再存入cookie返回给本地,下一次再访问的时候cookie数据自动的携带给服务器,服务器

去除cookie中的session_id,然后找到session,去除其中数据并解密

 

###  flask中的session工作机制

1. Flask中的session机制是:把敏感数据经过加密后放入session中,然后再把session存放到cookie中 ,下次请求的时候, 再从浏览器发送过来的cookie中读取session, 然后再从session中读取数据,进行解密,获取最终的用户数据

2. Flask的这种session机制,可以节省生服务器的开销,因为吧所有的信息都存储到了客户端(浏览器)

3. 安全是相对的,把session放到cookie中,经过加密,也是比较安全的

 

 

 

### 操作session

1. Session 的操作方式

* 使用session需要从flask中导入session,以后所有和session相关的操作都是这个变量来的

* 使用session需要设置secret_key,用来做为加密用,并且这个secret_key 如果每次服务器启动后都变化的话,那么之前’session’ 就不能在通过当前这个secret_key进行解密了

* 操作session 的时候,跟操作字典一样

* 设置session的过期时间

from flask import Flask,session
import os
from datetime import timedelta

app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
# 默认31天过期,此时指定7天后过期
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)

# 添加数据到session中
# 操作session的时候,跟操作字典是一样的
# secret_key
@app.route('/')
def index():
    session['username']='zhiliao'
    # 如果没有指定session的过期时间,那么默认是浏览器关闭后就自动结束

    # 如果设置了session的permanent属性为True,那么过期时间是31天
    session.permanent = True
    return 'index!'

@app.route('/get/')

def get():
    # session['username']
    # session.get('username')
    return session.get('username')

@app.route('/delete/')
def delete():
    print(session.get('username'))
    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请求传参不是放在url中,是通过form data的形式发送给服务器的

 

 

### get和post请求获取参数

1. get请求是通过 request.args 来获取

2. Post请求是通过 request.form 来获取

from flask import Flask,render_template,request
app = Flask(__name__)
@app.route('/')
def index():
    return render_template('index.html')
@app.route('/search/')
def search():
    # print(request.args)
    q=request.args.get('q')
    return '用户提交的查询参数是: %s' %q
# 默认的视图函数,只能采用get请求
# 如果你想采用post请求,那么要写明
@app.route('/login/',methods=['GET','POST'])
def login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        username=request.form.get('username')
        password=request.form.get('password')
        print(username)
        print(password)
        return 'post'
if __name__ == '__main__':

    app.run(debug=True)

Login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="{{ url_for('login') }}" method="post">
        <table>
            <tbody>
                <tr>
                    <td>用户名:</td>
                    <td><input type="text" placeholder="请输入用户名" name="username"/></td>
                </tr>
                <tr>
                    <td>密码:</td>
                    <td><input type="text" placeholder="请输入密码" name="password"/></td>
                </tr>
                <tr>
                    <td></td>
                    <td><input type="submit" value="登录"/></td>
                </tr>
            </tbody>
        </table>
    </form>
</body>
</html>

Search.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <a href="{{ url_for('search',q='hello') }}">跳转到搜索页面</a>
</body>
</html>

### g:global

1. g对象是专门用来保存用户的数据的

2. g对象再一次请求中的所有的代码的地方,都是可以使用的

 

### 钩子函数

from flask import Flask,g,render_template,request
from utils import  login_log
app = Flask(__name__)
@app.route('/')
def index():
    return 'index'
@app.route('/login/',methods=['GET','POST'])

def login():
    if request.method == 'GET':
        return render_template('login.html')
    else:
        username=request.form.get('username')
        password=request.form.get('password')
        if username == 'zhiliao' and password == '123':
            # 就认为当前这个用户的用户名和密码正确
            g.username=username
            g.ip = 'xx'
            login_log()

            return '恭喜登录成功'
        else:

            return '您的用户名或密码错误'
if __name__ == '__main__':

    app.run(debug=True)

Utils.py

from flask import g
def login_log():
    print('当前登录用户是:%s' %g.username)

def login_ip_log(ip):
    pass

### 钩子函数 (hook):

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():
    print('index')
    return 'index'
@app.route('/login/',methods=['GET','POST'])

def login():
    print('login')
    if request.method == 'GET':
        return render_template('login.html')
    else:
        username=request.form.get('username')
        password=request.form.get('password')
        if username == 'zhiliao' and password == '123':
            # 就认为当前这个用户的用户名和密码正确
            session['username'] = username
            return '恭喜登录成功'
        else:

            return '您的用户名或密码错误'
@app.route('/edit/')

def edit():
    if hasattr(g,'username'):
        return '修改成功'
    else:

        return redirect(url_for('login'))

# before_request: 在请求之前执行
# before_request是在视图函数执行之前执行的
# before_request这个函数只是一个装饰器,它可以把需要设置为钩子函数的代码放到视图函数执行之前来执行
@app.before_request
def my_before_request():
    if session.get('username'):
        g.username=session.get('username')
if __name__ == '__main__':
    app.run(debug=True)

 

2. Context_processor

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

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

@app.context_processor
def my_context_processor():
    return {'username':'zhiliao'}

 

原文地址:https://www.cnblogs.com/JimKing/p/8615173.html