python(Flask_web框架)

什么是flask?

  • Flask是python编写的, Web应用框架;微内核的web框架;
  • Django:全能型框架;
  • Flask用于编写小型网站,Django用于编写大型网站(ERP)
  • flask框架的创建:
    在pycharm中创建项目project,选择flask,创建成功后程序目录中会自动生成相应的文件和目录
  • flask框架里面包含有三种文件或目录;
    • static目录:里面存储的是静态文件css样式、js样式,字体格式等
    • templates目录:里面存储的是html文件
    • app.py文件:用于编写业务逻辑(定义视图函数)
需要掌握:
  • 如何实现简单的web服务网站?
    1). 导入Flask类
    2). 创建Flask类
    3). 编写视图函数
    4). 编写视图函数需要返回的html文件
    5). 启动运行Flask应用
  • 什么是路由?
    在Flask框架中,路由表示用户请求的url,用来寻找相对应的视图函数
  • 什么是视图函数?
    根据用户请求的路由,服务器使用相应的视图函数处理用户请求,并给用户返回一个html页面
# 1. 导入Flask类
from flask import Flask
# 2.创建Flask类,输入参数__name__表示指定当前Flask框架所处的路径,以便获取模版目录和静态文件的目录
app = Flask(__name__)

# 实现主页
@app.route('/')
def index():
    return  "这是网站的主页"

# 设置基本路由   /login/---访问路径
@app.route('/login/')
# 视图函数   告诉app当用户访问/login/这个路径时, 执行login函数的内容, 最终将return的内容返回给客户端;
def login():
    return  '

login......

' if __name__ == '__main__': # 运行Flask应用 # 127.0.0.1----回环地址IP, 每台主机都有====localhost # 如何设置, 使得服务奇特主机的浏览器可以访问? '0.0.0.0'开放所有的IP, 使得可以访问 # 如何修改端口? # 可能会报错:Address already in use app.run(host='0.0.0.0',port=8080)

python(Flask_web框架)_第1张图片

路由与变量规则

在访问豆瓣电影网站时,我们会发现url有一定的规律
格式为 http://www.douban.org/xxxxx/comments/
如下:

  • http://www.douban.org/123457677/comments/
  • http://www.douban.org/123457673/comments/
  • http://www.douban.org/123457674/comments/
  • http://www.douban.org/123457675/comments/

在Flask中有动态路由,格式为:http://www.douban.org/<>/comments/

常用动态路由的规则:
  • url路由的一部分可以标记为变量, <变量名>;
  • flask中路由变量可以指定的类型: int, string, float, uuid
  • 格式为:<类型:变量>
# request叫做请求上下文
from flask import  Flask, request
app = Flask(__name__)


@app.route("//comments/")
def comments(id):
    return "这是一个%s评论页面" %(id)


# 字符串
@app.route("/welcome//")
def welcome(username):
    return  "

欢迎用户%s登陆网站

" %(username)

在这里插入图片描述
python(Flask_web框架)_第2张图片

请求上下文:request

重点request:
  • Flask 从客户端收到请求时,要让视图函数能访问一些对象,这样才能处理请求。
  • 请求对象就是一个很好的例子,它封装了客户端发送的 HTTP 请求。即request;
当服务器需要获取用户的账户密码来验证用户的权限时需要用到请求上下文
# 以百度搜索引擎为例:http://www.baidu.com/query?id=123&name=westos
from flask import  Flask, request
app = Flask(__name__)

@app.route('/query')
def query():
    # 获取客户端的用户代理;
    user_agent = request.user_agent
    # 获取客户端的IP地址;
    req_addr = request.remote_addr
    # 获取用户请求url地址里面key值对应的value值;
    id = request.args.get('id')
    name = request.args.get('name')

    # 查看客户端的HTTP请求方式;
    reqMethod = request.method

    # 将字符串信息返回给客户端浏览器/其他, 默认以html方式显示, 如果需要换行, 加html的标签
; return """ 请求的用户代理: %s
请求的客户端Ip: %s
请求的id号: %s
用户名: %s
请求方式: %s """ %(user_agent, req_addr, id, name, reqMethod) if __name__ == '__main__': app.run(host='0.0.0.0',port=8080)

python(Flask_web框架)_第3张图片

登录验证之http请求方法

HTTP请求的方法:

  • GET:
    1). 获取页面信息;
    2). 可以提交数据信息;但是数据不安全;会显示用户的密码。
    http://127.0.0.1:5000/login2/?username=westos&password=westos

  • POST:
    提交服务端需要的请求信息;url不会显示用户的相关信息;有利于数据的安全性;

  • PUT:
    用户端向服务器往指定url上上传资源

  • DELETE:
    用户端往服务器上删除指定url上的资源

常用的请求方法为GET、POST方法

render_template和redirect的区别

  • render_template:参数为html的文件名,返回值是html文件的内容
  • redirect:参数为视图函数的函数名,返回值是视图函数执行后的返回值(返回的也是一个html文件)

GET实现案例

from flask import Flask, render_template, request, redirect

app = Flask(__name__)
@app.route('/')
def index():
    return  "

主页

" @app.route('/login/') def login(): # 一般情况, 不会直接把html文件内容直接返回; # 而是将html文件保存到当前的templates目录中; # 1). 通过render_template方法调用; # 2). 默认情况下,Flask 在程序文件夹中的 templates 子文件夹中寻找模板。 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 "登录失败" if __name__ == '__main__': app.run()
login.html:



    
    Title





用户登录

用户:
密码:

POST方法并实现自定义错误页面案例

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


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


# 默认路由只支持get方法, 如何指定接受post方法?
@app.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # 难点: post请求提交的数据如何获取?
        print(request.form)
        username = request.form.get('username', None)

        password = request.form.get('password', None)
        # 如果用户名和密码正确, 跳转到主页;
        if username == 'root' and password == 'redhat':
            return  redirect('/')
        # 如果登录不正确, 则警告红色信息;还是在登录页面;
        else:
            # 可以给html传递变量
            # errMessages(根据用户自己定义)表示的html中的变量名
            return  render_template('login_post.html',
                                    errMessages="用户名或者密码错误"
                                    )
    else:
        return  render_template('login_post.html')

# 在应用对象中有错误处理的装饰器.errorhandler
@app.errorhandler(404)
# 定义页面错误处理的视图函数时,需要传递参数e
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()

login_post.html:



    
    Title




用户登录

用户:
密码:
{{ errMessages }}
404.html:



    
    Title


404

500.html:



    
    Title



服务器正忙, 请稍后再试

模板引擎Jinja2

1. 什么是Jinja2模板引擎?

  • python的Web开发中, 业务逻辑(实质就是视图函数的内容)和页面逻辑(html文件)分开的, 使得代码的可读性增强, 代码容易理解和维护;
  • 模板渲染: 在html文件中,通过动态赋值 ,将重新翻译好的html文件(模板引擎生效) 返回给用户的过程。
  • 其他的模板引擎: Mako, Template, Jinja2

2. 语法

1. Jinja2变量显示语法: {{ 变量名 }}

完整的过滤器查看位置: http://jinja.pocoo.org/docs/templates/#builtin-filters
Jinja2变量内置过滤器:

  • safe: 渲染值时不转义,即将html格式的字符串转换成html文件
  • capitalize: 把值的首字母转换成大写,其他字母转换成小写
  • lower: 把值转换成小写形式
  • upper: 把值转换成大写形式
  • title: 把值中每个单词的首字母都转换成大写
  • trim: 把值的首尾空格去掉
  • striptags: 渲染之前把值中所有的 HTML 标签都删掉

自定义过滤器:

  • 定义一个函数,用来处理传入html的数据
  • 将该函数添加到默认过滤器中,第一个参数时定义好的函数名,第二个参数为用于html文件中的过滤器别名
    app.add_template_filter(参数1, 参数2)
from flask import  Flask, render_template
app = Flask(__name__)

class User(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return  "" %(self.name)

@app.route('/')
def index():
    message = " this is a Message "
    li = ['fentiao', 'fensi', 'fendai']
    info = {
        'name': 'fentiao',
        'age':10
    }
    fentiao = User(name="粉条", age=5)
    tags = "

hello world

" return render_template('index.html', message=message, names = li, info=info, fentiao=fentiao, tags = tags ) def format_data(s): return "这是一个过滤器:" + s app.add_template_filter(format_data, 'fmt')
index.html:



    
    Title



{{ message | fmt}}

{{ message | lower}}

{{ message | upper}}

{{ message | title}}

{{ message | capitalize}}

{{ names }}

{{ info }}

{{ fentiao }}

{{ tags | striptags }}

{{ tags | safe }}
2. for循环:
  • {% for i in li%}

  • {% endfor %}

3. if语句
  • {% if user == ‘westos’%}

  • {% elif user == ‘hello’ %}

  • {% else %}

  • {% endif%}

4. 宏的操作(相当于函数)
  • 如何定义宏?

{%  macro render(id) %}
    

hello world {{ id }}

{% endmacro %}
  • 如何调用宏?

{{ render(1) }}
{{ render(2) }}
{{ render(3) }}
5. include包含操作
  • 如何使用:
    {% include “06_inclued.html”%}
6. 模板的继承

一般网站的导航栏和底部不会变化, 为了避免重复编写导航栏信息;

  • 如何定义模板?
    block所占的位置的内容是可以改变的,当继承该模板时,可通过block填写内容
    • {% block title %}

    • {% endblock %}


    
    
        
        {% block title %}  {% endblock %}
    
    
    
这是导航栏
{% block body %} hello {% endblock %}
这是底部
  • 如何继承基模板?
{% extends  '06_base.html'%}

{% block title %}
   继承案例
{% endblock %}

{% block body %}
这是最新填的block内容

{% endblock %}

bootstrap框架

什么是Bootstrap框架?

Bootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作基于HTML、CSS、JavaScript 开发的简洁、直观、强悍的前端开发框架,使得 Web 开发更加快捷。Bootstrap提供了优雅的HTML和CSS规范,它即是由动态CSS语言Less写成。

学习网站:

  • 官方中文文档: https://v3.bootcss.com/
    下载bootstrap压缩包
  • 菜鸟教程案例: http://www.runoob.com/bootstrap/bootstrap-tutorial.html

flask项目静态文件的导入

在导入前,需要将下载好的bootstrap压缩包内的js、css、font目录移动到static目录下
除了导入下载好的本地静态文件,还可以根据官方中文文档导入url地址

# 两种方法: 任选一种
#通过路径导入
- 
# 通过url_for函数导入,
- 

flask链接的导入

两种方法:
    - 注册
    - 登录
    # 根据视图函数动态的去查找路径;
    - 删除  === /delete/root/

消息闪现

1. 如何实现闪现?

1). flash消息这种功能,是Flask的核心特性。用于在下一个响应中显示一个消息,让用户知道状态发生了变化。可以使确认消息,警告或者错误提醒。

  • flash(“闪现的消息”)

2). 工作原理:
闪现系统使得在一个请求结束的时候记录一个信息,然后在且仅仅在下一个请求中访问这个数据。

2. html代码中如何调用闪现内容?

仅调用flash()函数并不能把消息显示出来,程序使用的模板要渲染这些消息。Flask把get_flashed_messages()函数开放给模板,用来获取并渲染消息

{#让每个页面都可以获取闪现信息闪现,需要将这条代码放在基模板中#}
{% for item in get_flashed_messages() %}

    
{% endfor %}

用户session信息保存

  • cookie: 客户端浏览器的缓存;
  • session: 服务端缓存;

1.session的作用是什么?

Session 对象存储特定用户会话所需的属性及配置信息。这样,当用户在应用程序的 Web 页之间跳转时,存储在 Session 对象中的变量将不会丢失,而是在整个用户会话中一直存在下去。当用户请求来自应用程序的Web 页时,如果该用户还没有会话,则 Web 服务器将自动创建一个 Session 对象。当会话过期或被放弃后,服务器将终止该会话。Session 对象最常见的一个用法就是存储用户的首选项。

判断用户是否登录的装饰器

def is_login(f):
    """用来判断用户是否登录成功"""

    @wraps(f)
    def wrapper(*args, **kwargs):
        # 判断session对象中是否有seesion['user'],
        # 如果包含信息, 则登录成功, 可以访问主页;
        # 如果不包含信息, 则未登录成功, 跳转到登录界面;;
        if session.get('user', None):
            return f(*args, **kwargs)
        else:
            flash("用户必须登录才能访问%s" % (f.__name__))
            return redirect(url_for('login'))

    return wrapper

判断用户是否为管理员的装饰器

def is_admin(f):
    """用来判断用户是否登录成功"""

    @wraps(f)
    def wrapper(*args, **kwargs):
        # 判断session对象中是否有seesion['user']等于root,
        # 如果包含信息, 则登录成功, 可以访问主页;
        # 如果不包含信息, 则未登录成功, 跳转到登录界面;;
        if session.get('user', None) == 'root':
            return f(*args, **kwargs)
        else:
            flash("只有管理员root才能访问%s" % (f.__name__))
            return redirect(url_for('login'))

    return wrapper

简单制作的网站的总体效果

业务逻辑(app.py):

import os
# url_for函数通过视图函数查找并返回对应的路由
from flask import Flask, render_template, request, redirect, url_for, flash, session
from functools import wraps

users = [
    {
        'username': 'root',
        'password': 'root'
    },
    {
        'username': 'hello',
        'password': 'root'
    },

]

# 实现用户注册, 用户登录, 用户注销, 用户查看;
app = Flask(__name__)
# 在服务器存储flash数据时,会将flash数据加上这个密钥值进行加密
# 密钥值越长,安全性越高
app.config['SECRET_KEY'] = 'westos'
# flash可以保存多个信息

def is_login(f):
    """用来判断用户是否登录成功"""
	# 装饰wrapper将函数名改回原本的函数名f
    @wraps(f)
    def wrapper(*args, **kwargs):
        # 判断session对象中是否有seesion['user'],
        # 如果包含信息, 则登录成功, 可以访问主页;
        # 如果不包含信息, 则未登录成功, 跳转到登录界面;;
        if session.get('user', None):
            return f(*args, **kwargs)
        else:
            flash("用户必须登录才能访问%s" % (f.__name__))
            return redirect(url_for('login'))

    return wrapper


def is_admin(f):
    """用来判断用户是否为root用户"""
	# 装饰wrapper将函数名改回原本的函数名f
    @wraps(f)
    def wrapper(*args, **kwargs):
        # 判断session对象中是否有seesion['user']等于root,
        # 如果包含信息, 则登录成功, 可以访问主页;
        # 如果不包含信息, 则未登录成功, 跳转到登录界面;;
        if session.get('user', None) == 'root':
            return f(*args, **kwargs)
        else:
            flash("只有管理员root才能访问%s" % (f.__name__))
            return redirect(url_for('login'))

    return wrapper



# 主页
# 必须是is_login装饰器在下,app.route('/')装饰器在上
# 根据多个装饰器的调用过程,装饰器从下往上调用
# 但装饰器里面的wrapper函数是从上往下执行
# 所以首先根据路由找到视图函数,再根据is_login判断用户是否登录
@app.route('/')
@is_login
def index():
    return render_template('index.html')

# 用户注册
@app.route('/register/', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form.get("username", None)
        password = request.form.get('password', None)

        # 当所有的信息遍历结束, 都没有发现注册的用户存在, 则将注册的用户添加到服务器, 并跳转登录界面;
        for user in users:
            if user['username'] == username:
                return render_template('register.html', message="用户%s已经存在" % (username))
        else:
            users.append(dict(username=username, password=password))
            # return redirect('/login/')

            # 出现一个闪现信息;
            flash("用户%s已经注册成功, 请登录....." % (username), category='info')
            return redirect(url_for('login'))
    return render_template('register.html')

# 用户登录
@app.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get("username", None)
        password = request.form.get('password', None)

        # 当所有的信息遍历结束, 都没有发的用户存在, 则将注册的用户添加到服务器, 并跳转登录界面;
        for user in users:
            if user['username'] == username and user['password'] == password:
                #  将用户登录的信息存储到session中;
                session['user'] = username
                return redirect(url_for('index'))
        else:
            # 出现一个闪现信息;
            flash("用户%s密码错误, 请重新登录....." % (username))
            return redirect(url_for('login'))
    return render_template('login.html')

# 注销用户
@app.route('/logout/')
def logout():
    #  将用户存储到session中的信息删除;
    session.pop('user')
    flash("注销成功........")
    return redirect(url_for('login'))

# 删除用户信息
@app.route('/delete//')
def delete(username):
    for user in users:
        # 用户存在, 则删除;
        if username == user['username']:
            users.remove(user)
            flash("删除用户%s成功" % (username))
    else:
        flash("用户%s不存在" % (username))

    # 删除成功, 跳转到/list/路由中.....
    return redirect(url_for('list'))

# 列出用户信息
@app.route('/list/')
@is_login
@is_admin
def list():
    return render_template('list.html',
                           users=users)


# 上传图片
@app.route('/upload/', methods=['POST', 'GET'])
def upload():
    if request.method == 'POST':
        # 获取用户上传的文件对象
        f = request.files['faceImg']
        # 获取上传文件的文件名
        # print(f.filename)

        # 获取当前项目的目录位置;
        basepath = os.path.dirname(__file__)
        # print(__file__)       # /root/PycharmProjects/day34/app.py
        # print(basepath)       # /root/PycharmProjects/day34

        # /root/PycharmProjects/day34/static/img/face/xxx.png
        # 拼接路径, 保存到本地的位置;
        filepath = os.path.join(basepath, 'static', 'img', 'face', f.filename)

        # 保存文件
        f.save(filepath)
        flash("上传文件%s成功" %(f.filename))
        return  redirect(url_for('upload'))
    else:
        return  render_template('upload.html')


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

页面逻辑:

基模板(base.html):



    
    Myhtml-{% block title %} {% endblock %}
    
    
    








{#让每个页面都可以获取闪现信息闪现#}
{% for item in get_flashed_messages() %}

    
{% endfor %}



{#中间的部分需要修改#}
{% block content %}
{% endblock %}

{##}







index.html:
{% extends 'base.html' %}


{% block title %} 主页 {% endblock %}



{% block content %}

这是主页

{% endblock %}
list.html:
{% extends 'base.html' %}


{% block title %}  用户显示{% endblock %}



{% block content %}
    

用户信息显示




{% for user in users %} {# user是一个字典, 获取字典的key值, user.keyname #} {# 寻找删除的按钮 #} {% endfor %}
用户名 密码 删除
{{ user.username }} {{ user.password }} {# 删除#} 删除
{% endblock %}
login.html:
{% extends 'base.html' %}


{% block title %} 登录页面{% endblock %}



{% block content %}




    
    
    

登录 没有账号? {# 注册#} 注册

{% endblock %}
register.html:
{% extends 'base.html' %}


{% block title %} 注册页面{% endblock %}


{% block content %}
    
    
    

注册 已有帐号 {# 登录#} 登录

{# action : 将表单填写的数据提交到那个URL里面进行处理, #} {# url_for('register') : 根据视图函数寻找对应的url地址,/register/ #} {# method =['post', 'get'] , 这种是错误的, 提交数据只能选择一种HTTP请求方法; #}
{# name="username" ====> 将name里面的值username作为key值, 表单里面填写的内容作为value值, 提交到request.form #} {# type="text" : 要求填写的是一个字符串; #}
{% if message %}
{{ message }}
{% endif %}
{% endblock %}
upload.html:
{% extends 'base.html' %}
{% block title %} 上传文件 {% endblock %}
{% block content %}
    

上传头像


{# enctype="multipart/form-data"用于接收特殊的数据, 包括视频, 图片, 音乐....., 默认只能接收text/plain #}

{% endblock %}

你可能感兴趣的:(python(Flask_web框架))