Python Web框架Flask快速入门

文章中需要的代码下载地址:https://download.csdn.net/download/weixin_42881588/12542564
flask中文文档地址:http://docs.jinkan.org/docs/flask/

一、Flask框架

1、什么是Flask框架

Flask是一个基于python并且依赖于Jinja2模板引擎和Werkzeug WSGI服务的一个微型框架
WSGI :Web Server Gateway Interface(web服务网关接口)

Flask是采用 MTV 的框架模式

2、安装Flask

  1. 查看已安装的flask版本
    在python的交互模式中

    1. import flask
      没报错已经安装flask,可以继续查看版本
    2. flask.version
      已安装情况下,查看版本。
  2. 安装flask
    sudo pip3 install flask

3、Flask 初始化

见代码

from flask import Flask

# 将当前请求的主程序建成Flask应用,已接收用户的
# 请求(request)并给出响应(response)
app = Flask(__name__)

# @qpp.route() Flask中的路由定义,主要定义用户的访问路径. '/' 表示整个网站的根路径
# def index(),表示的是匹配上@app.route()路径后的处理程序 - 视图函数
# 所有的视图函数必须要有return,return后面可以是一个字符串也可以是一个独立的响应对象
@app.route('/')
def index():
    return "<h1>我的第一个Flask程序</h1>"


# 访问地址 http:localhost:5000/show/xxx
@app.route('/show/<name>')
def show(name):
    return "<h1>传递进来的参数为:%s</h1>"%name


# 访问路径http://localhost:5000/show/name/age
@app.route('/show/<name>/<int:age>')
def show_name_age(name,age):
    return '<h1>姓名:%s,年龄:%d</h1>'%(name,age)


@app.route('/category')
@app.route('/cate')
def category():
    return '<h1>商品分类页面</h1>'

if __name__ == "__main__":
    # 运行Flask应用(启动Flask服务),默认是在本机开启的端口是5000
    # debug = True ,将启动模式改为调试模式(开发环境推荐写true,生产环境必须写false)
    app.run(debug=True,port=5555) #port 修改端口号
练习:
访问路径:http://localhost:5000/login:
在网页中显示:欢迎访问登录界面

二、Flask - 路由(route)

1、什么是路由

客户端发送请求给web服务器,web服务器再将请求发送给Flask程序实例
程序实例需要知道每个URL请求所对应的运行代码是谁。
程序中必须要创建一个url请求地址,到python运行函数的一个映射。处理url和函数之间的关系的程序叫路由

2、路由的体现

在flask中,路由是由@app.route 装饰器来表示的

1、路由的基本表示

# http://localhost:5000
@app.route(/)
def index():
	Return “xxxx”

# http://localhost:5000/admin/login
@app.route(/admin/login ’)
def admin_login():
	Return “xxxx”

2、带参数的路由

路由中可以携带参数表示不同的数据

http://localhost:5000/show/laowang
http://localhost:5000/show/wangwc
http://localhost:5000/show/laowang.gebi

3、基本带参的路由

@app.route('/show/<name>')
def show(name):    //name 表示从地址栏上传递来的参数
	return ‘xxx’

4、带多个参数的路由

# http://localhost:5000/show/laowang/36
@app.route('/show/<name>/<age>')
def show(name, age):
	return ‘xxx’

5、指定参数类型的路由

@app.route('/show/<name>/<int:age>')
def show(name, age):
	return ‘xxx’
name:字符串
age:整型
int:类型转换器
Flask中所支持的类型转换器
类型转换器作用
缺省字符串,不能有斜杠(‘ / ’)
int整型
float浮点型
path字符串,可以有斜杠(‘ / ’)

6、多url的路由配置

为多个访问地址匹配同一个视图处理函数
@app.route(/地址1)
@app.route(/地址2)
def index():
	return “ ”
练习:
当访问路径是以下任何一个的时候:
http:localhost:5000
http:localhost:5000/index
http:localhost:5000/数字
http:localhost:5000/index/数字
将程序交给index()视图处理函数
判断路由中到底有没有数字传进来,
如果有
响应:您当前看的页数为:xxx
如果没有
响应:您当前看的页数为:1

代码如下:

from flask import Flask

app = Flask(__name__)



@app.route('/')
@app.route('/index')
@app.route('/<int:page>')
@app.route('/index/<int:page>')
def index(page=None):
    if page is None:
        return "您当前页面为:1"
    return "您当前页面为:%d" % page


@app.route('/post',methods=["POST"])
def post():
    return "这里只接受POST请求"


if __name__ == "__main__":
    app.run(debug=True)

7、路由中设置http的请求法

Flask路由也允许设置对应的请求方法(post/get),只将匹 配上请求方法的路径才能交给对应的视图处理函数去处 理。所有的路由,默认只接受get请求。

@app.route(/xxx/xxx’,methods=[‘POST’])
def xxx:
	# 只接受POST请求
	Pass
@app.route(/xxx/xxx’,methods=[‘GET’,‘POST’])
def xxx:
	# 该函数及接受GET请求也接受POST请求
	Pass

8、url的反向解析

  • 正向解析:程序自动解析,根据@app.route()中的访问路径,来匹配处理函数
  • 反向解析:通过视图处理函数的名称自动生成对应的访问路径
  • 在flask中要实现反向解析的话需要使用:
    • url_for(funName,args)
    • funName:要生成地址的函数名
    • args:该地址中需要的参数

详细代码如下:

from flask import Flask,url_for

app = Flask(__name__)


@app.route('/index')
def index():
    return "<h1>这是首页</h1>"


@app.route('/admin/login/form/show/<name>')
def show(name):
    return "参数的值为:%s" % name


@app.route('/url')
def url():
    # 通过index()解析出对应的访问路径
    url_index = url_for('index')
    print("index():"+url_index)
    # 通过show(name) 解析出对应的访问路径
    url_show = url_for('show',name="wangwc")
    print("show(name):"+url_show)
    return "<a href = '%s'>访问show(name)</a>" % url_show


if __name__ == "__main__":
    app.run(debug=True)

三、模板 - Templates

1、什么是模板

模板 ,在flask中就是允许响应给用户看的网页
在模板中允许包含 “占位变量” 来表示动态的内容
模板最终也会被解析成字符串在响应给客户端,这一过程通常称为 “渲染”

Flask 中的模板是依赖于Jinja2的模板系统

2、模板的设置

默认情况下,Flask会在程序文件夹中的templates的文件夹中 搜索模板
默认情况下需要手动创建templates文件夹

3、模板的渲染

作用:在视图中,将模板文件(xx.html)渲染成字符串之后,再响应给客户端浏览器
函数:render_template( ‘xxx.html’ )
return render_template( ’ xxx.html ')

4、模板中的语法(重难点)

1、变量 FlaskDome2-run01

变量是一种特殊的占位符,告诉模板引擎该位置的值是从渲染模板的数据中获取出来的。

  • 在视图中:
@app.route(' / ')
def index():
	# return render_template(' xxx.html ',变量值1 = 值1,	变量值2 = 值2)
	return render_template(' xxx.html ',name = 'laowang',age = '35')
  • 在模板中:
{{变量名}}
	<h1>{{name}}</h1>
  • locals()将当前函数内所有的局部变量封装成一个字典

  • 练习:
    在01-templates.html 基础上,完成下列效果显示
    歌曲 :《绿光》
    作词 :宝强
    作曲 :乃亮
    演唱 :羽凡

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        h1{
            color: red;
        }
    </style>
</head>
<body>
    <h1>{{name}}</h1>
    <h1>歌名:{{params.music}}</h1>
    <h1>作词:{{params.author}}</h1>
    <h1>作曲:{{params.qu}}</h1>
    <h1>演唱:{{params.singer}}</h1>

</body>
</html>

2、过滤器

1、什么是过滤器

过滤是允许在变量输出前改变变量的值

2、语法
{{变量|过滤器}}

Jinja2 模板中常见的过滤器
过滤器名        			说明
capitalize				首字符变大写,其他变小写
lower					将值转换为小写
upper					将值转换为大写
title					将值中的每个单词首字母变大写
trim					去掉值两边的空格
3、标签
  1. 什么是标签
    每个标签表示的是不同的服务器端的功能
  2. 常用的标签
    1. if 标签

      1. 基本if结构
        {% if 条件 %}
        {% endif %}
      2. if … else…结构
        {% if 条件 %}
        满足条件时运行的代码
        {% else %}
        不满足条件时要运行的代码
        {% endif %}
      3. if…elif …elif…else
        {% if 条件1 %}
        满足条件1运行的代码
        {% elif 条件2 %}
        满足条件2运行的代码
        {% elif 条件3 %}
        满足条件3运行的代码
        {% else %}
        以上条件都不满足的时候,运行的代码
        {% endif %}
    2. for标签
      {% for 变量 in 元组|列表|字典 %}
      {% endfor %}

      在Jinja2模板的循环中,支持内部变量 - loop
      loop作用:记载当前循环中的一些相关信息
      loop常用属性:

      1. index
        用法:loop.index
        作用:记录当前循环的次数,以1开始记 录
      2. index0
        用法:loop.index0
        作用:同上,从0开始记录
      3. first
        用法:loop.first
        作用:值为True,则表示当前循环是第一 次循环
      4. last
        用法:loop.last
        作用:值为True,则表示当前循环为最后 一次循环
    3. macro标签(宏)

      1. 作用:
        相当于在模板当中声明函数
      2. 语法:
        使用{% macro %}声明宏
        {% macro 名称(参数列表) %}
        {% endmacro %}
      3. 在独立的文件中声明宏
        1. 创建macro.html 模板文件
          作用:定义项目中要用到的所有的宏
        2. 在使用的网页中,导入macro.html
          {% import ’ macro.html ’ as macro %}
    4. include 标签
      将其他的模板文件包含到当前的模板文件中
      语法:{% include ‘xxx.html’ %}

4、静态文件处理
  1. 什么是静态文件
    在Flask中不能与服务器交互的文件都是静态文件
    如:图片,css文件,js文件,音视频文件. . .
  2. 静态文件的处理
    1. 所有的静态文件必须放在 static 的目录中
      static目录要放在项目的根目录处
    2. 所有的静态文件必须通过/static/路径访问
      /static 要到静态资源目录中继续搜索
5、静态文件地址的反向解析
url_for('static',filename = '<file_path>')
例:
url_for('static',filename ='images/b041/b05.jpg')
6、模板的继承
  1. 什么是模板的继承
    模板的继承类似于类的继承,如果一个模板中出现的内容来自于另一个模板的话,那么就可以使用模板继承的方式 来简化开发
  2. 语法:
    1. 父模板
      需要定义出那些东西在子模板中是可以被重写的
      {% block 块名 %}
      父模板中正常现实的内容
      {% endblock %}
      block:
      1. 在父模板中是可以正常显示的,没有任何影响
      2. 在子模板中是可以被重写的
    2. 子模板
      1. 需要指定继承自那个父模板
        {% extends ‘父模板名称’ %}
      2. 重写父模板中对应的内容
        {% block 块名 %}
        此处编写的内容会覆盖掉父模板中同名的block的内容
        允许通过{{super()}},来调用父模板中的内容
        {% endblock %}
7、修改配置
  1. 在构建Flask应用时允许指定的配置信息
app = Flask(__name__,
	template_folder = 'xxx',
	static_url_path =/s’,
	static_folder =/sta’)
  • template_folder:指定存放模板的文件夹名称
  • static_url_path:访问静态资源的路径
  • static_folder:存放静态文件目录的名称
  1. 启动程序的运行配置
app.run(debug = True,
			port = 5000,
			host = '0.0.0.0'
			)
  • host:指定访问地址,0.0.0.0 表示局域网内的任何机器都可以访问网站
    以上详细代码见 :FlaskDemo2

四、请求(request)和响应(response)

1、HTTP协议

Request Headers — 请求消息头
Response Headers — 响应消息头

2、请求对象 - request

request - 请求对象,封装了所有与请求相关的信息。
如:请求数据,请求消息头,请求路径…
在Flask中,要使用request的话必须先导入
from flask import request

1、request的常用成员

	scheme :获取请求方案(协议)
	method :获取本次请求的请求方式(重点)
	args :获取使用get请求方式提交的数据
	from :获取使用post请求方法提交的数据
	cookies :获取cookies的相关信息
	headers :获取请求消息头的相关信息
	files :获取上传的文件
	path :获取请求的url地址(进入到主机后的请求资源地址,不包含请求参数)
	full_path :获取请求的url地址(进入到主机后的请求资源地址,包含请求参数)
	url :获取完整的请求地址,从协议开始的地址

2、获取请求提交的数据

1、get请求方式
  1. 表单允许实现get请求
	<form action="/06-get" method="get">
	    姓名:<input  name="uname">
	</form>
	http://localhost:5000/06-get?uname=123&upwd=123
  • ?:后边是请求参数
  1. 在请求地址后拼请求提交的参数
    http://localhost:5000/06-get?uname=xxx&upwd=xxx
  2. 获取 get 请求方式提交的数据
    request.args封装的是get请求的数据
    request.args[‘uname’] 没有uname报错
    request.args.get(‘uage’) 可以返回空
2、post请求方式
	post请求只有在表单中才可以被触发
	<from method = "post">
	
	获取post请求提交的数据:
		request.form封装的就是post请求的数据,类型为字典
		request.form[‘name’] : 获取name对应的值
		request.form.get('name') :获取name对应的值
		request.form.getlist('name') :获取name列表数据(如:复选框、下拉列表)
  • 练习:
    1. 访问地址为;http://localhost:5000/07-form-post 能够去往07- form-get.html 模板
    2. 在07-form-get.html模板中包含一个表单,post提交方式,提交地址为/07-post,控件如下
    文本框—用户名
    密码框—用户密码
    文本框—用户邮箱
    文本框—用户姓名
    提交 —按钮
    3. 在07-post中获取所有提交的 数据并打印在终端

详细代码见:FlaskDemo03

3、响应(response)

1、什么是响应

响应就是有服务器端带给客户端的内容,对应的请求。
响应可以是普通的字符串,模板 或 重定向。
return “普通字符串”

2、响应对象:

将响应的内容封装到一个对象中,可以完成更多的响应的行为(如:增加cookies,…)

在Flask中可以使用make_response()构建响应对象

form flask import make_response
@app.route(‘/xxx’)
def xxx():
	resp = make_response(‘响应内容’)
	#允许实现其他的响应行为
	return resp

3、重定向

1、什么是重定向

由服务器端通知客户端,重新向一个新的地址发送请求

2、语法:
	from flask import redirect
	return redirect('重定向地址')
	resp = redirect('重定向地址')
	# 借助resp实现其他的响应行为
	return resp

在这里插入图片描述

4、文件上传

注意问题

  1. 表单中如果有文件上传的话,必须遵守以下两个要求
    1. 提交方式method 必须为 post
    2. 表单的enctype 属性值必须为mutipart/form-data
  2. 服务器端
    1. 通过request.file获取上传文件
      f = request.files[‘文件框的name值’]
    2. 通过f.save(‘保存路径’) 将文件保存至指定目录下
      通过f.filename 获取文件名称
      f.save(‘static/’+f.filename)

详细代码见:FlaskDemo04

五、模型 Models

1、什么是模型

模型,是根据数据库中表的结构而创建出来的class。
每一张表对应到编程语言中,就是一个class
表中的每一个列对应到编程语言中,就是class中的一个属性

2、模型的框架 – ORM

1、什么是ORM Object Relational Mapping

ORM :Object Relational Mapping
简称 :ORM O/RM O/R Mapping
中文名:对象关系映射

2、ORM的三大特征

1、数据表(table)到编程类(class)的映射

数据库中的每一张表 对应到编程语言中 都有一个类
在ORM中:
允许将数据表 自动 生成一个类
允许将类 自动 生成一张数据表

2、数据类型的映射

将数据库表中的字段以及数据类型对应到编程语言中类的属性
在ORM中:
允许将表中的字段和数据类型自动映射到编程语言中,也允许将类中的属性和数据类型也自动映射到表中

3、关系映射

将数据库中表与表之间的关系对应到编程语言中类与类之间的关系

  • 数据库中表与表之间的关系
  1. 一对一
    外键 主键 唯一约束
    A表中的一条数据只能与B表中的一条数据相关联

  2. 一对多
    外键 主键
    A表中的一条数据可以与B表中的多条数据相关联,反之,B表中的一条数据只能与A表中的一条数据相关联

  3. 多对多
    通过第三张关联表去关联两张表
    A表中的一条数据可以与B表中的任意多条数据相关联,反之,B表中的一条数据也可以与A表中的任意多条数据

3、ORM优点

  1. 封装了数据库中所有的操作,大大提高了开发效率
  2. 可以省略庞大的数据访问层,即便不用SQL编码也能完成对数据的CRUD的操作

4、Flask中的 ORM框架

1、数据库 和 框架配置
	在python和Flask中,使用的ORM框架是 - SQLAlchemy
	在flask中想使用SQLAIchemy的话,需要 进行安装:
	pip3 install sqlalchemy
	pip3 install flask-sqlalchemy
2、创建数据库
	create database flask default charset utf8 collate 	utf8_general_ci;
3、定义模型
	模型:数据库中的表在编程语言中的体现,其本质就是一个python类(模型类 或 实体类)
	数据库中的一行:实体
	实体的完整性:表中的实体不能完全重复 - 主键

语法:
	class MODELNAME(db.Model):
	__tablename__ = “TABLENAME”
	COLUME_NAME = db.Column(db.TYPE, OPTIONS)
	1、MODELNAME :定义模型的名称,根据表名来设定
	2、TABLENAME :映射到数据库中表的名称
	3、COLUMN_NAME :属性名,映射到数据库表中就是列								名
	4、TYPE :映射到列的数据类型
	5、OPTIONS :列选项

db.TYPE 列的类型如下:
	类型名               python类型          说明
	Integer     		    int          普通整数,32位
	SmallInteger            int 		 小范围的整数,通常为16位
	BigInteger           int或long       不限精度整数
	Float			         float       浮点数
	Numeric		       decimal.Decimal   定点数
	String				    str     	 变长字符串
	Text			        str      	 变长字符串,优化
	Unicode		          unicode        变长Unicode字符串
	UnicodeText	          unicode        优化后的变长Unicode字符串
	Boolean		          bool  	   	 布尔值
	Date			    datetime.date      日期
	Time			    datetime.time      时间
	DateTime            datetime.datetime  日期和时间
	
OPTIONS 列选项:
	选项名                   说明
	primary_key	        	如果设置为True表示该列为主键
	unique					如果设置为True表示该列值唯一
	index					如果设置为True表示该列要创建索引
	nullable				如果设置为True表示该列允许为空
							默认是允许为空(True)
	default					表示该列的默认值

3、数据库操作 - 插入

  1. 创建实体对象
  2. 完成插入
    db.session.add(实体对象)
    db.session.commit()
    自动提交
    app.config[‘SQLALCHEMY_COMMIT_ON_TEARDOWN’] = True

4、数据库操作 - 查询

1、基于db.session进行查询

1、db.session.query()

该函数会返回一个query对象,类型为BaseQuery
该对象中包含了实体类对应的表中的所有数据

该函数可以接收一个或多个参数,参数们表示的是要查询的实体对象是谁

2、查询执行函数
  • 目的:在query()的基础上得到最终想要的结果
  • 语法:db.session.query(…) .查询执行函数()
函数说明
all()列表的方式返回query()中所有查询函数结果
first()返回查询结果的第一个结果,如果没有结果则返回None
first_or_404()返回查询结果的第一个结果,如果没有结果的话,则终止并返回404
count()返回查询结果的数量
3、查询过滤器函数
  • 作用:在查询的基础上,筛选部分行数据
  • 语法:db.session.query(…).过滤器函数().查询执行函数
过滤器函数说明
filter()按指定条件进行过滤(多表,单表,点值,不定值)
filter_by()按等值条件过滤时使用(只支持单表查询)
limit()按限制行数查询
order_by()根据指定条件进行排序
group_by()根据指定条件进行分组

过滤器函数详解

  1. filter()
    注意:条件必须由 模型类.属性 构成
    查询年纪大于30的User信息
    db.session.query(User).filter(User.age>30).all()

    查询年龄大于30并且id大于1的User的信息
    db.session.query(User).filter(User.age>30,User.id>1).all()
    “逗号” 表示条件关联 相当于 and

    查询年龄大于30或者id大于1的User的信息
    注意:查询 或 操作,要借助 or_,需要导入
    from sqlalchemy import or_
    db.session.query(User).filter
    (or_(User.age>30,User.id>1)).all()

    查询 id 为2的User的信息
    注意:等值判断必须用 ==
    db.session.query(User).filter(User.id==1).all()

    查询email中包含 ‘w’ 的User的信息 - 模糊查询
    注意:模糊查询like需要使用实体类中属性提供的like()
    db.session.query(User).filter
    (User.email.like(‘%w%’)).all()

    查询id 在[2,3]之间的User的信息
    In需要使用实体类中属性提供的in_([])
    db.session.query(User).filter
    (User.id.in_([2,3])).all()

  2. 聚合函数
    db.session.query(func.聚合函数(列名).label(‘别名’)).all()

  3. filter_by()
    查询 id=5 的User的信息
    db.session.query(User).filter_by(id=5).all()

  4. limit()
    result = db.session.query(Users).limit(2).all()
    result = db.session.query(Users).limit(2).offset(1).all()

  5. order_by()
    按照id列的值降序排序
    db.session.query(Users).order_by(“id desc”)

  6. 按照age列的值降序排序,二级排序按照id升序 排序
    db.session.query(Users).order_by(“age desc,id asc”).all()

  7. group_by()
    db.session.query(Users).group_by(‘age’).all()

  8. 基于 Models 类进行查询
    Models.query.查询过滤器函数(条件参数).查询执行函数()

4、数据库操作 - 删除

1、查询出要删除的实体对象

u = db.session.query(Models).filter_by(xxx).first()

2、根据提供的 删除方法进行删除

db.session.delete(u)

注意:
真正的删除操作并不是通过删除操作完成的,而是通过修改完成的

5、数据库操作 - 修改


  1. 将修改的信息查询出来

  2. 实体对象.属性 = 值
  3. 保存
    db.session.add(实体对象)

详细代码见:FlaskDemo05

六、关系映射

1、一对多

语法:
1、在 多 的实体中
	增加一个列,引用自 ”一” 表的主键列
	外键列名 = db.Column(db.Integer, db.ForeignKey('主表.主键'))
2、在 ”一” 的实体中增加关联属性以及反向引用关系
	例:
	关联属性:
		在course对象中,通过一个属性能够得到对应的所有teacher们,关联属性加在Course的实体类中
	反向引用:
		在teacher对象中,通过一个属性能够得到对应的course
		反向引用关系属性模式应该加在Teacher的实体类中。
	
	增加关联属性和反向引用关系:
		属性名 = db.relationship('多表的实体类名',关系选项)

关系选项:
选项名					说明
backref			在关系的另一个模型中添加的反向引用名(准备在'多'的实体中增加对’一’的实体引用的属性名)

lazy				指定如何加载当前的相关记录
					select:首次访问时加载记录
					immediate:源对象加载后马上加载相关数据
					subquery:效果同上,利用子查询方式加载
					noload:永不加载记录
					dynamic:默认不加载记录,但会提供加载记录的查询

uselist				如果设置为False,表示不使用列表表示关联记录,而使用标量

secondary			指定多对多关系映射中的关联表的名字

2、一对一

1、什么是一对一

A表中的一条记录只能与B表中的一条记录相关联
B表中的一条记录只能与A表中的一条记录相关联

2、在SQLAlchemy中的体现

  1. 在任意一个类中增加
    外键列名 =db.Column(db.Integer,db.ForeignKey(‘主键.主列名’))
  2. 在另外一个类中增加 关联属性 和 反向引用 关系属性
    属性 = db.relationship(‘关联的实体类’,backref=‘反向引用属性名’,‘uselist=false’)

3、多对多

1、什么是多对多

A表中的一条数据可以与B表中的任意多条数据相关联
B表中的一条数据可以与A表中的任意多条数据相关联

2、实现

在数据库中使用第三张表(关联表)
在编程语言中,可以不编写对应的实体类

创建第三张表

student_course = db.Table(
	'student_course',      #在数据库中的表名
	db.Column(‘id’,db.Integer,primary_key = True),
	db.Column(‘student_id’,db.Integer,db.ForeignKey(‘student.id’)),
	db.Column(‘course_id’,db.Integer,db.ForeignKey(‘course.id’))
)

详细代码见:FlaskDemo06

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值