python进阶之Flask入门(一)

目录

一、架构简介

1、什么是Flask?

二、Flask表单操作 

三、什么是Flask-SQLAlchemy?

1、如何配置数据库?

2、定义模型

3、模型列类型

4、模型列属性

5、数据查询

6、分页实现

7、Flask-Migrate数据库迁移

1、模型定义

2、一对多关系

3、多对多关系

4、Flask-Migrate数据库迁移

1、为什么使用Flask-Migrate?

2、实现步骤

3、数据库迁移命令行操作 (创建迁移仓库)

5、什么是Flask-Script?

1、为什么使用Flask-Script?

6、Flask常用钩子函数

1、什么是钩子函数?

1、基础概念

2、常用的钩子函数

6、案例

1、路由和变量规则

2、登录验证之http请求方法GET实现案例

3、登录验证值http请求值POST

4、Flask日志记录


一、架构简介

Nginx (engine x) 是一个高性能的 HTTP 反向代理 web 服务器,同时也提供了 IMAP/POP3/SMTP 服务
uWSGI 是一个 Web 服务器 ,它实现了 WSGI 协议、 uwsgi http 等协议。
Framework 即架构,它是一个语言开发 软件 ,提供了软件开发的框架,使开发更具工程性、简便性和稳定性。
 
 

1、什么是Flask?

Flask是一个Web框架,就是提供一个工具,库和技术来允许你构建一个Web应用程序.这个Web应用程序。

可以是一些Web页面,博客, wiki ,基于 Web 的日历应用或商业网站。

1)Flask依赖模块:
 
web服务网关接口( Python Web Server Gateway Interface, 缩写为 WSGI
Werkzeug 一个 WSGI 工具包, 是为 python 语言定义的 web 服务器和 web 应用程序或框架之间的一
种简单而通用的借口 , 其他语言也有类似的接口)
jinja2 模板引擎
 
2)Flask 的优势
 
Flask 属于微框架( micro - framework ) 这一类别 , 微架构通常是很小的不依赖外部库的框架 .
框架很轻量。
更新时依赖小。
专注于安全方面的 bug。
 
如下,实现一个简单的flask框架:(File:01_flask第一个网站.py)
 
from flask import Flask
app = Flask(__name__)

#实现首页:http://172.25.254.197:9999/
@app.route('/')   #路由
def index():       #视图函数,一定不能重复;
    return '这是一个网站的首页'

@app.route('/login/')
def login():
    return '正在登陆......'

@app.route('/logout/')
def logout():
    return '正在登出......'

if __name__ == '__main__':
    #运行flask项目,默认ip和端口是127.0.0.1:5000
    #如何特色化指定?host='0.0.0.0' 开放本机的所有IP port=5000 端口必须是整形数
    #debug=True:是否开启调试模式,测试环境中一般开启,生产环境一定要关闭。
    app.run(host='127.0.0.1',port=9999,debug=True)

运行结果如下:

点击那行网址之后,就进入浏览器了:

二、Flask表单操作 

 
Form 表单,在 Web 应用中无处不在。比如 : 用户登录表单 , 用户注册表单。 所有的表单项都有共性,比如有文字输入框,单选框,密码输入框等;
表单的验证也有共性,比如有非空验证,长度限制,类型验证等。 如果有个框架,能把这些共性抽象出来,那就能大量简化我们的工作。
Python WTForms 就提供了这 些功能,这里我们就要结合Flask WTForms 扩展, Flask - WTF ,来介绍如何在 Web 应用中制作表单。
 
 
1、安装和启用
pip install Flask-WTF
2、表单文件
WTForms 让我们在后端代码中定义表单类,并列出表单的字段和相应的验证规则。现在让我们先定义一
MyForm 类:
from flask_wtf import Form 
from wtforms import StringField 
from wtforms.validators import DataRequired 

class LoginForm(FlaskForm): 
    email = StringField(u'邮箱', validators=[ 
                DataRequired(message= u'邮箱不能为空'), Length(1, 64), 
                Email(message= u'请输入有效的邮箱地址,比如:username@domain.com')]) 
    password = PasswordField(u'密码', 
                validators=[Required(message= u'密码不能为空')]) 
    submit = SubmitField(u'登录')

3、常见的表单域类型

 
                                         
4、常见验证规则
 
                    
5、视图函数文件
@app.route('/login/', methods=['GET', 'POST']) 
def login(): 
    form = LoginForm() 
    if form.validate_on_submit(): 
        email = form.email.data 
        ... 
    return render_template('login.html', form=form)
6、验证数据
点击了表单上的提交按钮时, form.validate_on_submit() 判断会做下面两件事情:
通过 is_submitted() 通过判断 HTTP 方法来确认是否提交了表单
通过 WTForms 提供的 validate() 来验证表单数据
validate() 验证未通过时,会在表单字段下面显示我们传进去的错误提示(例如 message= u'
箱不能为空 ' )。
7、自定义验证
你可以在表单类创建自定义的验证函数,一个简单的例子:
def validate_username(self, field): 
    # field.data是用户输入的数据。 
    if field.data == 'admin': 
        # ValidationError从wtforms导入,用来向用户显示错误信息, 
        # 验证函数的名称由validate_fieldname组成。 
        raise ValidationError(u'超级管理员已被注册,换一个吧。')

也可以在这里对用户数据进行预处理:

# 这个函数对用户输入的网址进行处理(字段名为website)。 
def validate_website(self, field): 
    if field.data[:4] != "http": 
        field.data = "http://" + field.data

8、获取数据

验证通过后,
使用 form.email.data 来获得数据,
form.email.data
WTForms 提供的静态方法 .data 返回一个以字段名( fifield name )和字段值( fifield value )作为键
值对的字典。
form.data['email']
9、前端文件
form.hidden_tag() 会生成一个隐藏的
标签,其中会渲染任何隐藏的字段,最主要的是 CSRF 字段。
CSRF Cross-Site Request Forgery 跨站请求伪造)是一种通过伪装来自受信任用户的请求,来
发送恶意攻击的方法 , WTForms 默认开启 CSRF 保护。
<form method="POST" action="/login/"> 
    {{ form.hidden_tag() }} 
    {{ form.user.label }}: {{ form.user(size=20) }} 
    <input type="submit" value="Submit"> 
</form>

10、Python数据库连接方式

python 中的数据库连接有两种方式 :
Python 标准数据库接口 , 使用 SQL 语句正常操作数据库 , e.g:
MySQL 关系型数据库的 pymsql 模块
ORM 来进行数据库连接 , Python 中使用 sqlalchemy , flflask 中典型的 flask_sqlalchemy , 已面向
对象的方式进行数据库的连接与操作
ORM 是什么 ? 有什么优势 ?
ORM ,即 Object - Relational Mapping (对象关系映射),它的作用是在关系型数据库和业务实体对
象之间作一个映射,这样,我们在具体的操作业务对象的时候,就 不需要再去和复杂的 SQL 语句打交
,只需 简单的操作对象的属性和方法
 
                   
 

三、什么是Flask-SQLAlchemy?

Flask - SQLAlchemy 是一个 Flask 扩展 , 简化了在 Flask 程序中使用 SQLAlchemy 的操作。
SQLAlchemy 是一个很强大的关系型数据库框架 , 支持多种数据库后台。 SQLAlchemy
供了高层 ORM , 也提供了使用数据库原生 SQL 的低层功能。
 
                     

1、如何配置数据库?

1)安装第三方模块
 
pip install flask-sqlalchemy

2)数据库配置

 
# app.py文件 
from flask_sqlalchemy 
import SQLAlchemy 
# 获取当前绝对路径 basedir = os.path.abspath(os.path.dirname(__file__)) 
app = Flask(__name__)

# SQLALCHEMY_DATABASE_URI: 用于连接数据的数据库。 
app.config['SQLALCHEMY_DATABASE_URI'] =\ 
               'sqlite:///' + os.path.join(basedir, 'data.sqlite') 
# sqlchemy将会追踪对象的修改并且发送信号 
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 

# 每次请求结束之后都会提交数据库的变动 
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True 

# 数据库与app项目关联, 返回SQLAlchemy实例对象,后面可以使用对象调用数据 
db = SQLAlchemy(app)

流行的数据库引擎采用的数据库 URL格式

                

连接 mysql 数据库报错解决
import pymysql 
pymysql.install_as_MySQLdb()

2、定义模型

 
模型 (Model) 这个术语表示程序使用的持久化实体。
模型列类型
模型列属性
 
class Role(db.Model): 
    # __tablename__类变量定义数据库中表的名称。不指定默认为模型名称。 
    # Flask-SQLAlchemy需要给所有的模型定义主键列,通常命名为id。 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(64), unique=True) 

# repr()显示一个可读字符串,用于调试和测试
    def __repr__(self): 
        return '<Role %r>' % self.name 

class User(db.Model): 
    __tablename__ = 'users' 
    id = db.Column(db.Integer, primary_key=True) 
    username = db.Column(db.String(64), unique=True, index=True) 

def __repr__(self): 
    return '<User %r>' % self.username

3、模型列类型

 

4、模型列属性

 

5、数据查询

查询过滤器
 
查询执行函数
 

6、分页实现

分页对象拥有的属性
 
 

7、Flask-Migrate数据库迁移

分页对象拥有的方法

数据库关系
数据库实体间有三种对应关系:一对一,一对多,多对多。
一对一关系
一个学生对应一个学生档案材料,或者每个人都有唯一的身份证编号。
 
 

1、模型定义

# one_to_one.py文件 

from app import db 
import pymysql 
pymysql.install_as_MySQLdb() 

class People(db.Model): 
    __tablename__ = 'peoples' 
    id = db.Column(db.Integer, primary_key=True, autoincrement=True) 
    name = db.Column(db.String(20), nullable=False) 

""" 
关系使用 relationship() 函数表示; 
        'Card': People类对应的表与Card类对应的表关联; 
        backref='people': 反向引用, 在Card类中添加新属性people; 
        uselist=False: 默认为True, 如果为False代表一对一关系; 
        lazy='select': 决定了 SQLAlchemy 什么时候从数据库中加载数据; 还可以设 定:'joined', 'subquery' , 'dynamic' 
    可能报错: SAWarning: Multiple rows returned with uselist=False for lazily- loaded
""" 

    card = db.relationship('Card', backref='people', uselist=False) 

    def __init__(self, name): 
        self.name = name 

    def __repr__(self): 
        return '<People: %s>' % (self.name) 


class Card(db.Model): 
    __tablename__ = 'cards' 
    id = db.Column(db.Integer, primary_key=True, autoincrement=True) 
    cardID = db.Column(db.String(30), nullable=False) 
    # 外键必须用类 sqlalchemy.schema.ForeignKey 来单独声明; 
    people_id = db.Column(db.Integer, db.ForeignKey('peoples.id')) 

    def __repr__(self): 
        return "<Card: %s>" % (self.cardID)
2)基本操作
 
# one_to_one.py文件

if __name__ == '__main__': 
    db.drop_all() 
    db.create_all() 
# 增元素 
    p1 = People(name="西部开源") 
    p2 = People(name="粉条") 

    db.session.add_all([p1, p2]) 
    db.session.commit() 

    card1 = Card(cardID='001', people_id=p1.id) 
    card2 = Card(cardID='002', people_id=p2.id) 

    db.session.add_all([card1, card2]) 
    db.session.commit() 

# 查找 
    card_people1 = Card.query.filter_by(cardID='001').first().people people_card1 =                 People.query.filter_by(id=1).first().card 
    print(card_people1) print(people_card1) 

# 删除 
    print("删除前: ", Card.query.all(), People.query.all()) 
    card = Card.query.filter_by(cardID='001').first() 
    db.session.delete(card) 
    db.session.commit() 
    print("删除后: ", Card.query.all(), People.query.all())

2、一对多关系

 

一个学生只属于一个班,但是一个班级有多名学生。
 
                 
设计数据库表:只需在 学生表 中多添加一个班级号的 ID
通过添加主外键约束,避免删除数据时造成数据混乱!

1)模型定义

# one_to_many.py文件 

from app import db 
import pymysql 
pymysql.install_as_MySQLdb()

# 一对多: 外键写在多的一端; Grade:Stdudents== 1:n 
class Student(db.Model): 
    __tablename__ = 'students' 
    id = db.Column(db.Integer, primary_key=True, autoincrement=True) 
    name = db.Column(db.String(20), nullable=False) 
# 外键 
    grade_id = db.Column(db.Integer, db.ForeignKey('grades.id')) 

    def __repr__(self): 
        return "<Student: %s %s %s>" % (self.id, self.name, self.grade_id) 
class Grade(db.Model): 
    __tablename__ = 'grades' 
    id = db.Column(db.Integer, primary_key=True, autoincrement=True) 
    name = db.Column(db.String(20), nullable=False) 
    # 反向引用, 让Student类中添加属性grade; 
    students = db.relationship('Student', backref='grade') 

def __repr__(self): 
    return "<Grade: %s %s %s>" % (self.id, self.name, self.students)
2)基本操作
 
if __name__ == '__main__': 
    db.drop_all() 
    db.create_all() 
# 增元素 
    s1 = Student(name="西部开源") 
    s2 = Student(name="粉条") 

    db.session.add_all([s1, s2]) 
    db.session.commit() 

    grade1 =Grade(name='Python开发') 
    grade1.students.append(s1) 
    grade1.students.append(s2) 

    db.session.add_all([grade1]) 
    db.session.commit() 
    print("添加成功: ", Student.query.all(), Grade.query.all()) 

# 查找 
    student_grade1 = Student.query.filter_by(name='粉条').first().grade
    grade_students = Grade.query.filter_by(name="Python开发").first().students         print(student_grade1) 
print(grade_students) 

# 删除 
    print("删除前: ", Student.query.all(), Grade.query.all()) 
    grade1 = Grade.query.filter_by(name='Python开发').first()

    db.session.delete(grade1) 
    db.session.commit() 
    print("删除后: ", Student.query.all(), Grade.query.all())

3、多对多关系

一个学生可以选择多门课,一门课也有多名学生。
                          
对于多对多表,通过关系表就建立起了两张表的联系!多对多表时建立主外键后,要先删除约束表
内容再删除主表内容。
 
             
1)模型定义
 
# many_to_many.py文件 
from app import db 
import pymysql 
pymysql.install_as_MySQLdb() 

# 第三方表 
tags=db.Table('tags',     db.Column('student_id',db.Integer,db.ForeignKey('math_students.id')),
db.Column('course_id',db.Integer,db.ForeignKey('courses.id'))) 

class MathStudent(db.Model): 
    __tablename__ = 'math_students' 
    id = db.Column(db.Integer, primary_key=True, autoincrement=True) 
    name = db.Column(db.String(20), nullable=False) 
    courses = db.relationship('Course', secondary=tags) 

    def __repr__(self): 
        return "<MathStudent: %s >" % (self.name) 

class Course(db.Model):

__tablename__ = 'courses' 
id = db.Column(db.Integer, primary_key=True, autoincrement=True) 
name = db.Column(db.String(20), nullable=False) 
students = db.relationship('MathStudent', secondary=tags) 
def __repr__(self): 
    return "<Course: %s >" % (self.name)
2)基本操作
 
# many_to_many.py文件 
if __name__ == '__main__': 
    db.drop_all() 
    db.create_all() 

# 创建 
    s1 = MathStudent(name="拉格朗日") 
    s2 = MathStudent(name="麦克劳林") 
    s3 = MathStudent(name="罗尔") 

    course1 = Course(name="高等数学") 
    course2 = Course(name="线性代数") 

    s1.courses.append(course1) 
    s1.courses.append(course2) 
    s2.courses.append(course1) 
    s3.courses.append(course2) 

    db.session.add_all([s1, s2, s3, course1, course2]) 
    db.session.commit() 

# 删除 
    courseObj = Course.query.filter_by(name="线性代数").first() 
    studentObj = MathStudent.query.filter_by(name="罗尔").first() 
    print("删除前选择线性代数的学生: ", courseObj.students) 
    courseObj.students.remove(studentObj) print("删除后择线性代数的学生: ",     

    courseObj.students) 

# 其他操作相同

4、Flask-Migrate数据库迁移

1、为什么使用Flask-Migrate?

 
在我们用 sqlchemy 模块创建完几个表时,如果在实际生产环境中,需要对表结构进行更改,应该怎么
办呢?总不能把表删除了吧,这样数据就会丢失了。
更好的解决办法是使用数据库迁移框架,它可以追踪数据库模式的变化,然后把变动应用到数据库中。
Flask 中可以使用 Flask-Migrate 扩展,来实现数据迁移。并且集成到 Flask-Script 中,所有操作通过命
令就能完成。
 

2、实现步骤

安装 flflask-migrate flflask-script 模块。
 
pip3 install flask-migrate 
pip3 install flask-script
配置代码
 
manager = Manager(app) 
db = SQLAlchemy(app) #第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例 
migrate = Migrate(app,db) 
#manager是Flask-Script的实例,添加一个db命令 
manager.add_command('db',MigrateCommand)

3、数据库迁移命令行操作 (创建迁移仓库)

 
这个命令会创建 migirations 文件夹,所有迁移文件都放在里面
 
python3 xxx.py db init
1)自动创建迁移脚本
数据库迁移工作由迁移脚本完成。这个脚本有两个函数,分别叫做 upgrade() downgrade()
upgrade() 函数实施数据库更改,是迁移的一部分, downgrade() 函数则删除它们。通过添加和删除数
据库变化的能力, Alembic 可以重新配置数据库从历史记录中的任何时间点。
 
python3 xxx.py db migrate -m "版本名(注释)"
2)更新数据库
一旦迁移脚本被审查且接受,就可以使用 db upgrade 命令更新到数据库中:
 
python3 xxx.py db upgrade
当我们需要修改表结构时,如何实现数据库迁移呢 ?
直接在 xxx.py 里直接增删相应的代码 ,
修改完成后,继续创建新的迁移脚本
 
python 文件 db migrate -m"新版本名(注释)"
更新数据库
python3 xxx.py db upgrade
更新完之后,其实就是提交操作,类似于 git 添加一个新的版本。但是,如果我们想返回历史的版本,
应该怎么操作呢?
先查看版本号
python xxx.py db history

想要返回的版本号。返回指定的版本

python xxx.py db downgrade(upgrade) 版本号
然后打开你的代码,可以发现他自动复原了!
 

5、什么是Flask-Script?

 
Flask-Script 用来生成 shell 命令;为在 Flask 里编写额外的脚本提供了支持。
 
这包括运行一个开发服务器,一个定制的 Python 命令行,用于执行初始化数据库、定时任务和其
他属于 web 应用之外的命令行任务的脚本。
Flask-Script Flask 本身的工作方式类似。只需要定义和添加能从命令行中被 Manager 实例调用的
命令即可。
 

1、为什么使用Flask-Script?

Flask 的开发 Web 服务器支持很多启动设置选项,但只能在脚本中作为参数传给 app.run() 函数。这种方
式很不方便,传递设置选项的理想方式是使用命令行参数。
Flask-Scrip 就是这么一个 Flask 扩展,为 Flask 程序 添加一个命令行解析器
Flask-Script 自带了一组 常用选项 ,而且还 支持自定义命令
 
1)安装 Flask-Script?
pip install flask_script
2)如何配置 Flask-Script?
 
创建文件 manage.py 作为项目的入口文件。
无需把所有的命令都放在同一个文件里,例如,在一个大型项目中,可以把相关联的命令放在 不同的文件里。
# **** manage.py文件 
from flask_script import Manager 
app = Flask(__name__) 
# Manager类将追踪所有的在命令行中调用的命令和处理过程的调用运行情况; 
# configure your app 
manager = Manager(app) if __name__ == "__main__": 
    # 将启动Manger实例接收命令行中的命令。 
    manager.run()
实现功能
python manage.py 
python manage.py runserver 
python manage.py runserver -h 
python manage.py runserver -h '0.0.0.0' -p 8089
3)添加自定义命令的 3 种方式 :
 
网站参考 : https://flflask-script.readthedocs.io/en/latest/
使用 command 装饰器
定义 Command 的子类 ;
使用 option 装饰器
 
# **** manage.py文件 
# 方法一: 
@manager.command def hello(): 
    return "hello" 

# 方法二: 
from flask_script import Command 
class Hello(Command): 
    "prints hello world" 

def run(self): 
    return "hello world" 
manager.add_command('hello', Hello()) 

# 方法三: 
@manager.option('-n', '--name', help='Your name') 
def hello(name): 
    return "hello", name
4) 命令行拓展开发
 
Extension developers can easily create convenient sub-manager instance within their
extensions to make it easy for a user to consume all the available commands of an
extension.
Here is an example how a database extension could provide (ex. database.py):
 
# 添加其他的命令到manager里面来 
from app.managerUtil.database import database_manager 
# 自定义的数据库操作 
manager.add_command('database', database_manager) 
# flask-script集成的数据库操作 
manager.add_command('db', MigrateCommand)

6、Flask常用钩子函数

1、什么是钩子函数?

在正常执行的代码前中后,强行插入执行一段你想要实现的功能的代码,这种函数就叫做钩子函数。钩
子函数就是等同于高速公路上的收费站,进高速之前给你一个卡,并检查你是否超重。离开之前收你,
也可以拦住你安检一下。

1、基础概念

request: Flask 的请求上下文,包含请求变量如 : method args form values endpoint
headers remote_addr 都是比较常用的。
session:Flask 的请求上下文,用于存放用户的会话信息。
current_app:Flask 的应用上下文,返回当前 app 的方法和属性,可以勉强理解为类全局变量。

2、常用的钩子函数

before_first_request 处理第一次请求之前执行
只在第一次请求之前执行,也就是启动项目,不会执行,只会在第一次有人发起请求时,才会触发这个
钩子中的代码。
全局场景 : 可以带动一个异步执行的函数,进行一些健康指标的检查,如果发现有异常,则截断后续的请
求,将整个 Flask 应用停止。
 
# 服务器被第一次访问执行的钩子函数 
@app.before_first_request 
def first_request(): 
    print("Hello World")
before_request 在每次请求之前执行 . 通常使用这个钩子函数预处理一些变量 , 视图函数可以更
好调用
这是最重要的一个钩子,在每次请求之前可以注入你要的逻辑的钩子。在 app 下的 before_request ,过
滤的是全部请求。结合 Blueprint before_request ,则是过滤该蓝图下的请求。所以我们就可以进行
分层过滤,定制化过滤。
全局的场景包含:共享 session 的鉴权函数、请求黑白名单过滤、根据 endpoint 进行请求等。
 
# 在服务器接收的请求还没分发到视图函数之前执行的钩子函数 
@app.before_request 
def before_request(): 
    # print("我勾住了每次请求") 
    user_id = session.get("user_id") 
        if user_id: g.user = "DaYe"
  • teardown_appcontext APP 上下文被移除之后执行的函数, 可以进行数据库的提交或者回滚
@app.teardown_appcontext 
def teardown(exc=None): 
    if exc is None: 
        db.session.commit() 
else:
        db.session.rollback() 
    db.session.remove()
template_filter , 增加模板过滤器
@app.template_filter 
def upper_filter(s): 
    return s.upper()
context_processor 上下文处理器 , 返回的字典可以在全部模板中使用
 
@app.context_processor() 
def context(): 
    # 必须返回一个字典 
    # hasattr(obj, attr) 判断obj是否有attr属性, 注意此时的attr应该是字符串 
    if hasattr(g, "user"): 
        return {"current_username": "DaYe"} 
    else:
        # 注意: 必须返回一个字典 
        return {}
errorhander , 在发生一些异常时 , 比如 404 错误 , 就会自动调用对应的钩子函数
发生请求错误时 , 框架会自动调用相对钩子函数 , 并向钩子函数传入 error 参数
如果钩子函数没有定义 error 参数 , 就会报服务器错误
开发者可以通过 flask.abort 方法手动抛出异常 , 比如发现输入的参数错误可以使用
abort(404) 来解决
 
@app.errorhander(404) 
def page_not_found(error): 
    return render_template("error400.html"), 404 

@app.errorhander(500) 
def server_error(error): 
    return render_template("error505.html"), 500

6、案例

1、路由和变量规则


from flask import Flask,request

app = Flask(__name__)

@app.route('/<int:userid>/')
def userinfo(userid):
    return '正在查看用户%s的详细博客......'%(userid)

@app.route('/welcome/<string:username>')
def welcome(username):
    return '欢迎访问%s用户的主页'%(username)

"""
https://movie.douban.com/top250?start=25&filter=
"""
@app.route('/top250')
def top250():
    users = ['user%s' %(i) for i in range(100)]
    #request存储用户请求页面的所有头部信息
    print('客户端的用户代理:',request.user_agent)
    print('请求页面的头部信息:',request.headers)
    print('客户端的IP:',request.remote_addr)         #127.0.0.1
    print('客户端请求的参数详细信息:',request.args)
    print('客户端HTTP请求方法:',request.method)    #GET
    #获取用户请求的url地址里面可以对应的value值;
    start = int(request.args.get('start'))         #25
    user = request.args.get('user')                #westos
    #return 'top 250 显示数据开始:%s条  用户名:%s' %(start,user)
    import json
    return json.dumps(users[start:start+10])

if __name__ == '__main__':
    app.run()

 

2、登录验证之http请求方法GET实现案例



"""
# 1.Http请求中常见的请求方式: GET POST
    1). url可见性:
        get,参数url可见;
        post,url参数不可见
    2). 数据传输上:
        get,通过拼接url进行传递参数;
        post,通过body体传输参数
    3). 缓存性:
        get请求是可以缓存的
        post请求不可以缓存
    4). 后退页面的反应
        get请求页面后退时,不产生影响
        post请求页面后退时,会重新提交请求
    5). 传输数据的大小
        get一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)
        post请求传输数据可以无限大。
    6). 安全性: 原则上post肯定要比get安全。
# 2. 模版渲染
    hello {{ name }}
    name = westos    hello westos
    Flask和Django一样都配备了Jinja2模版引擎,可以使用render_template()租用模板方法来渲染模版。
# 3. 重定向和错误(redirect,error)
    使用redirect()函数把用户重定向到其他地方。 '/bbs' ---> '/login'
    使用abort()函数,放弃请求并返回错误代码。  # HTTP状态码: 404(4开头客户端错误), 200, 304, 500(5开头服务端错误)
"""

from flask import Flask, render_template, request, redirect

app = Flask(__name__)
@app.route('/')
def index():
    return  "<h1>主页</h1>"

@app.route('/login/')                   #表单
def login():
    """
    一般情况, 不会直接把html文件内容直接返回;
    而是将html文件保存到当前的templates目录中;
          1). 通过render_template方法调用;
          2). 默认情况下,Flask 在程序文件夹中的 templates1 子文件夹中寻找模板。
    """
    return  render_template('login.html')


@app.route('/login2/')
def login2():
    # 获取用户输入的用户名
    username = request.args.get('username', None)
    password = request.args.get('password', None)
    # 逻辑处理, 用来判断用户和密码是否正确;
    if username == 'root' and password == 'redhat':
        # 重定向到指定路由;
        # 如果登录成功, 进入主页.
        return  redirect('/')
        # return "登录成功"
    else:
        # return  "登录失败"
        # 如果登录失败, 重定向到登录界面重新登录;
        return  redirect('/login/')

if __name__ == '__main__':
    app.run()

3、登录验证值http请求值POST


"""
# 1.自定义错误页面:
    1). 为什么要自定义错误页面?
    如果你在浏览器的地址栏中输入了不可用的路由,那么会显示一个状态码为 404 的错误页
    面。现在这个错误页面太简陋、平庸.
    2). 如何自定义错误页面?
    像常规路由一样,Flask 允许程序使用基于模板的自定义错误页面。
    最常见的错误代码有两个:
            - 404,客户端请求未知页面或路由时显示;
            - 500,有未处理的异常时显示。
"""

from flask import Flask, request, render_template, redirect, abort

app = Flask(__name__)

@app.route('/')
def index():
    return "这是主页"


# 默认路由只支持get方法, 如何指定接受post方法?
@app.route('/login/', methods=['GET', 'POST'])
def login():
    """
    1. 用户访问网址: http://xxxx/login, 返回登录的html页面;
        方法method: GET
    2. 用户在表单中填写信息,
        <form action="/login/" method="POST">
    3. 执行post提交的逻辑;
    :return:
    """
    if request.method == 'POST':
        # 难点: post请求提交的数据如何获取?  request.form
        # 难点: get请求提交的数据如何获取?   request.args
        print(request.form)
        username = request.form.get('username')
        password = request.form.get('password')
        # 如果用户名和密码正确, 跳转到主页;
        if username == 'root' and password == 'redhat':

            return redirect('/')
        # 如果登录不正确, 则警告红色信息;还是在登录页面;
        else:
            # 可以给html传递变量
            return render_template('login_post.html',
                                   errMessages="用户名或者密码错误"
                                   )
    else:
        # abort(500)
        return render_template('login_post.html')


@app.route('/welcome/<string:username>')
def welcome(username):
    app.logger.error("欢迎界面......")
    return render_template('welcome.html', name=username)


@app.errorhandler(404)
def page_not_found(e):
    return render_template("404.html"), 404


@app.errorhandler(500)
def internal_server_error(e):
    return render_template("500.html"), 500


if __name__ == '__main__':
    app.run()

4、Flask日志记录


"""
格式化中的常用参数如下:
%(name)s                Logger的名字
%(levelno)s         数字形式的日志级别
%(levelname)s   文本形式的日志级别
%(pathname)s        调用日志输出函数的模块的完整路径名,可能没有
%(filename)s         调用日志输出函数的模块的文件名
%(module)s
调用日志输出函数的模块名
%(funcName)s
调用日志输出函数的函数名
%(lineno)d
调用日志输出函数的语句所在的代码行
%(created)f
当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d
输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s
字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d
线程ID。可能没有
%(threadName)s
线程名。可能没有
%(process)d
进程ID。可能没有
%(message)s
用户输出的消息
"""

from flask import Flask
import logging

app = Flask(__name__)

# 日志系统配置, 设置文件存放位置;
handler = logging.FileHandler('app.log', encoding='UTF-8')
# 设置日志文件存储格式
logging_format = logging.Formatter(
            '%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(lineno)s - %(message)s')
# 将日至文件处理对象和日至格式绑定,
handler.setFormatter(logging_format)
handler.setLevel('DEBUG')
# 将日志格式和app绑定;
app.logger.addHandler(handler)


@app.route('/')
def index():
    app.logger.debug('hello')
    app.logger.error('error')
    app.logger.exception('exception')
    app.logger.info('hello')
    return  'index'

if __name__ == '__main__':
    app.run(debug=True, port=8000)

其中,app.log会自动生成

 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值