#从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‘) }}" />
2. 静态文件 flask 会从static 文件夹中开始寻找,所以不需要再写’static’这个路径了
3. 可以加载 css js image文件
Flask-SQLAlchemy的安装介绍
- ORM:object Relationship Mapping(模型关系映射)
- Flask-sqlalchemy 是一套ORM框架
- 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:[email protected]: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‘}