week11 day3 django入门2

一、静态文件配置

1.1 什么是静态文件

静态文件(static):js、css、img,第三方前端框架
	网站写好的js文件
	网站写好的css文件
	网站用到的图片文件
	第三方前端框架
	...
	提示:只要已经写好功能的文件,可以拿来直接就用的文件就属于静态文件

补充:django默认是不会自动帮你创建static文件夹的,需要要你自己手动创建
一般情况下我们在static文件夹内还会做进一步的目录划分处理:
	static/
	|--js
	|--css
	|--img
	|--bootstrap-3.3.7-dist
	|--......

1.2 静态文件配置

如果在浏览器中输入url能够看到对应的资源,是因为后端提前开设了该资源的接口,如果访问不到资源,说明后端没有开设该资源的接口

提示:django项目不会帮你创建静态文件,需要手动创建,约定俗成的文件名是static

路径:到settings.py配置文件中找到STATIC_URL在其下面加上以下内容

"""
静态文件的查找步骤:
1.先找到STATIC_URL中拿到/static/令牌
2.再到STATICFILES_DIR中拼接访问静态文件资源的路径,os.path.join(BASE_DIR, 'static')
3.拿到路径后再到我们创建的static静态文件中寻找,一层层查找,第一个static文件夹中没有,则到第二个种找,都没有则报错。
"""
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
    os.path.join(BASE_DIR, 'static1'),
    os.path.join(BASE_DIR, 'static2')
]

补充:当你在写django项目的时候,坑会出现后端代码修改了但是前端页面没有变化的情况

1.你在同一个端口开了好几个django项目 
    一直在跑的其实是第一个django项目: 因为默认设置的django端口是8000, 端口已经被第一个占用, 后面无论开启多个个django项目端口都不能够分配, 也就无法启动.
        
2. 浏览器缓存的问题
    打开浏览器 -> settings -> network -> disable cache 勾选上

1.3 静态文件动态解析

"""
在templates管理的html文件中,在head引用外部资源之前应如下书写方式:
{% load static %}    # load static类似于导入python模块
<script src='{% static '静态文件中的文件路径' %}'></script>
"""

{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>

二、request对象方法初识

2.1 知识储备:form表单

from表单的功能:在该form标签内部书写的获取用户的数据都会被form标签提交到后端。

属性:action控制数据提交到后端的路径(给哪个服务端提交数据)
	1.什么都不写,默认就是朝当前页面所在的url提交数据
	2.写全路径:http://www.baidu.com 朝百度服务端提交数据
	3.只写路径后缀action='/index/',自动识别出当前服务端的ip和port拼接在前面。host:port/index/

属性:method通过method指定提交请求的方式
	1.get:form表单默认提交数据的方式是get请求,数据是直接放在url后面的,以?分割url和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456.
	2.post:把提交的数据放在HTTP包的请求体内(注意:这里指定post,flask服务器才可以通过request.files,request.form获取文件,表单数据)
	提示:GET方式提交数据,会带来安全问题,比如一个登陆页面,在以GET方式提交了数据后,用户名和密码会明文出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码。

属性:enctype="multipart/form-data"指定数据提交的编码格式
	1.默认是urlencoded只能提交普通的文本数据,不能发送文件
	2.form-data就可以支持提交文件数据

2.2 注意:在使用form表单开启post功能之前必须先到settings.py下面找到MIDDLEWARE注释一行代码

在这里插入图片描述

2.3 request用法介绍(重中之重)

在这里插入图片描述
参数功能介绍:

"""
提示:get请求携带的数据是有大小限制的,而post请求则没有限制。
chrome的URL长度限制不能超过8182个字符。
"""

request.method			返回大写字符串的当前请求方式
request.GET				返回URL中问号?后面携带的参数。QueryDict对象:: <QueryDict: {'username': ['egon'], 'hobbies': ['play', 'study']}>
request.POST			返回POST请求提交过来的普通键值对(不包含文件)

request.GET.get()		返回对象列表中的最后一个值 -> str
request.POST.get()

request.GET.getlist()	返回对象列表中的所有的值  -> list
REQUEST.POST.getlist()
from django.shortcuts import HttpResponse, render, redirect


# Create your views here.
def login(request):
    """request对象方法初识"""
    print(request.method, type(request.method))  # GET <class 'str'>

    print(request.GET, type(request.GET))
    '''
    <QueryDict: {'username': ['egon'], 'password': ['123']}> 
    <class 'django.http.request.QueryDict'>
    '''
    print(request.GET.get('username'))      # egon
    print(request.GET.get('password'))      # 123

    print(request.GET.getlist('username'))  # ['egon']
    return render(request, 'login.html')


def register(request):
    print(request.method, type(request.method))  # POST <class 'str'>

    print(request.POST, type(request.POST))
    '''
    <QueryDict: {'username': ['egon'], 'password1': ['123'], 'password2': ['123'], 'hobbies': ['吃', '喝']}> 
    <class 'django.http.request.QueryDict'>
    '''
    print(request.POST.get("username"))     # egon
    print(request.POST.get('hobbies'))      # 喝

    print(request.POST.getlist("hobbies"))  # ['吃', '喝']
    return render(request, 'register.html')

三、pycharm链接数据库

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可能出现的错误
在这里插入图片描述

四、django链接数据库()

第一步:配置数据库:到配置文件settings.py中找到DATABASES配置
在这里插入图片描述

第二步代码声明:使用pymysql替换django自带的数据库MySQLdb

'''
没有配置第二步则会抛出异常: django.core.exceptions.ImproperlyConfigured: Error loading MySQLdb module: No module named 'MySQLdb'.
Did you install mysqlclient or MySQL-python?

django默认用的是mysqldb模块链接MySQL
但是该模块的兼容性不好 需要手动改为用pymysql链接
你需要告诉django不要用默认的mysqldb还是用pymysql
'''

# 在项目名下的__init__.py或者任意应用名下书写以下代码:
import pymysql
pymysql.install_as_MySQLdb()

五、django ORM

5.1 ORM简介

在这里插入图片描述
ORM全称object relational mapping 对象关系映射

功能:通过ORM实现对操作对象的操作模式来操作数据库中的数据。

实现:通过medels中的类来对应数据库中的一个表,一个对象对应一个数据行,一个属性对应数据库中的一个字段。

缺陷:封装程度太高,有时候SQL语句的效率偏低,需要你自己书写SQL语句。

5.2 ORM基本使用

from django.db import models

# Create your models here.
class User(models.Model):
    """
    charfield   必须要制定max_length参数,不指定会直接报错。因为python默认字符格式是varchar
    verbose_name该参数是所有字段都有的,就是用来对字段的解释
    """
    # id int primary key auto_increment
    id = models.AutoField(primary_key=True, verbose_name='主键id')
    # username varchar(32)
    username = models.CharField(max_length=32, verbose_name='用户名')
    # age int
    age = models.IntegerField(verbose_name='年龄')
    # password varchar(32)
    password = models.CharField(max_length=32, verbose_name='密码')
    
    
class Author(models.Model):
    """
    由于一张表中必须要有一个主键字段,并且一般情况下都叫做id字段
    所以orm当你不定义主键字段的时候,orm会自动帮你创建一个名为id的主键字段
    也就意味着,后续我们在创建模型表的时候如果主键字段名没有额外的叫法,那么主键字段可以省略不写
    """
    # username varchar(32)
    username = models.CharField(max_length=32)
    # password varchar(255)
    password = models.CharField(max_length=255)

5.3 数据库迁移命令

# 前提: 在执行命令之前要切换到项目文件夹下
python3.6 manage.py makemigrations  # 生成数据库同步脚本(将操作记录, 记录到migrations中)
python3.6 manage.py migrate  # 数据迁移(将操作真正的同步到数据库中)

只要你修改了models.py中跟数据库相关的代码,就必须重新执行上述的两条命令

在这里插入图片描述

5.4 字段的增删改查

1.在执行了生成数据库迁移记录命令之后在终端命令行中输入默认值
	2.字段设置可以为空(默认不为空)
	info = models.Charfield(max_length=32, verbose_name='个人简介', null=True)
	3.直接给字段指定默认值
	info = models.Charfield(max_length=255, verbose_name='个人简介', default='喜欢吃桃')

删
	直接注释对应的字段然后执行数据库迁移的两条命令即可
	# password = models.CharField(max_length=255, verbose_name='密码')
    注意(危险):  删除的字段对应的数据也将会删除

改
	直接修改代码然后执行数据库迁移的两条命令即可
    # password = models.CharField(max_length=255, verbose_name='密码')
    password = models.IntegerField(verbose_name='密码')

查:略

5.5 数据的增删改查

5.5.1 方法介绍
增
	方式一:使用models自动创建
		user_obj = models.User.objects.create(**kwargs)
	方式二:手动创建
		user_obj = models.User(**kwargs)
		user_obj.save()

查
	user_queryset = models.User.objects.filter(**kwargs)
	user_queryset是一个QuerySet对象,他是一个列表套对象的格式: <QuerySet [<User: User object>, <User: User object>, ...]>
	# 查询单个数据的两种方式
		方式一:索引取值,不能使用负数
			user_obj = user_queryset[0]
		方式二:推荐使用.first()。但是其内部使用的也是通过索引取值
			user_obj = user_queryset.first()
	# 查询所有数据的两种方式
		方式一:
			data_queryset = models.User.objects.filter()
			print(data_queryset)  # <QuerySet:[<User: object1>, <User: object2>, ...]>
		方式二:更加见名知意
			data_queryset = models.User.objects.all()

改
	方式一:
		"""
		批量操作对象
		只会更新指定的,将filter查询出来的列表中的所有的对象全部更新
		批量更新操作只修改被修改的字段
		"""
		models.User.objects.filter(id=edit_id).update(**kwargs)
	方式二:
		"""
		单独操作对象
		无论有没有数据选中就是执行更新。因此字段特别多的时候效率就会非常低
		它会从头到尾将所有的字段全部更新一遍,无论该字段有没有被修改
		"""
		edit_obj = models.User.objects.filter(id=edit_id).first*()
		edit_obj.username = username
		edit_obj.password = password
		edit_obj.save()"""
	真正删除功能应该需要二次确认,我们这里先不做。
	平常的删除数据内部其实并不是真正的删除,我们会给数据添加一个标识字段来表示当前数据是否被删除了,如果数据被删了仅仅只是将字段修改了一个状态,
		表示状态有is_delete, is_alive, is_status。这里我们用is_delete示例

	username        password        is_delete
	jason             123               0
	egon              123               1
	"""
	不能二次确认的删除:直接删除
	models.User.objects.filter(id=delete_id).delete()
5.5.2 利用数据的查询和增加实现登陆注册功能实例
# 数据的查询: 登录功能例子
    from app01 import models
    username = request.POST.get('username')
    res = models.User.objects.filter(username=username)
    '''
    res=[数据对象1, 数据对象2]  列表取值不能使用负数
    补充: filter括号内可以带多个参数. 内部默认用and链接
    '''
    res = models.User.objects.filter(username=username).first()  # 获取数据对象方式一: 推荐. 内部使用的是下面索引取值的的方式
    user_obj = res[0]      # 获取数据对象方式一: 推荐. 内部使用的是下面索引取值的的方式
    user_obj = res.first() # 获取数据对象方式二: 与上面等同
    print(user_obj.id)  # 支持对象操作获取对应对象的id
    print(user_obj.username)
    print(user_obj.password)

    
# 数据的增加: 注册功能的例子
    1. 准备注册页面
    2. 获取用户输入
        # 第一种: 利用models自动帮你保存
            username = request.POST.get('username')
            password = request.POST.get('password')
            res = models.User.objects.create(username=username, password=password)
                # res 返回值就是当前被创建的对象本身
        # 第二种: 自己手动保存数据
            user_obj = models.User(username=username, password=password)
            user_obj.save()
5.5.3 利用数据的查改删实现对数据的编辑和删除功能实例

步骤流程:

 - 在模型类中创建数据
 - 准备数据展示HTMl页面.
    2.1 使用模型类语法查询数据库中的数据
    2.2 将查询到的数据传递到HTML页面中, 使用模板语法进行渲染
    提示: 都默认get提交数据
    2.3 在HTML页面准备编辑按钮:
        数据定位: 使用/edit_data/?user_id={{ user.id }}. 提交到后端, 可以通过获取user_id进行数据的定位.
    2.4 准备删除按钮
 - 后端处理用户请求
    3.1 通过GET提交方式拿到用户的user_id, 再定位到数据对象, 将数据对象传入HTML页面返回一个编辑页面
    3.2 用户编辑表单, 通过POST请求, 判断如果是POST请求, 那么用户就是编辑页面了.
    3.3 再对数据对象进行修改/删除
    3.4 修改完毕以后重定向返回用户数据展示页面

代码部分:

  • models

    from django.db import models
    
    
    # Create your models here.
    class User(models.Model):
        # id = models.AutoField(primary_key=True, verbose_name='主键')
        username = models.CharField(max_length=66, verbose_name='用户名')
        password = models.CharField(max_length=255, verbose_name='用户密码')
        age = models.IntegerField(verbose_name='年龄')
        sex = models.CharField(max_length=1, default='男', verbose_name='性别')
        phone = models.BigIntegerField(verbose_name='电话号码')
    
  • views.py

    from django.shortcuts import render, redirect
    from app01 import models
    
    """
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^user_table/', views.user_table),
        url(r'^edit_data/', views.edit_data),
        url(r'^del_data/', views.del_data),
    ]
    """
    
    
    # Create your views here.
    def user_table(request):
        """查看功能"""
        # 查询出用户表里面所有的数据
        # user_list_obj = models.User.objects.filter()  # 方式一
        user_queryset = models.User.objects.all()       # 方式二: 更加见名知意
        # print(user_list_obj)
        return render(request, 'user_table.html', locals())
    
    
    def edit_data(request):
        """编辑功能"""
        edit_id = request.GET.get('user_id')
        edit_obj = models.User.objects.filter(id=edit_id).first()
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            age = request.POST.get('age')
            sex = request.POST.get('sex')
            phone = request.POST.get('phone')
            models.User.objects.filter(id=edit_id)
            # 去数据库中修改对应的数据内容
            # 修改数据方式一:
            '''
            当字段特别多的时候效率会非常的低,
            它会从头到尾将数据的所有字段全部更新一边 无论该字段是否被修改
            '''
            edit_obj.username = username
            edit_obj.username = password
            edit_obj.username = age
            edit_obj.username = sex
            edit_obj.phone = phone
            edit_obj.save()
            # 修改数据方式二:
            '''
            将filter查询出来的列表中所有的对象全部更新
            批量更新操作只修改被修改的字段
            '''
            models.User.objects.filter(id=edit_id).update(username=username, password=password, age=age, sex=sex,
                                                          phone=phone)
    
            return redirect('/user_table/')
        return render(request, 'edit_data.html', locals())
    
    
    def del_data(request):
        """删除功能"""
        del_id = request.GET.get('user_id')
        '''
        真正的删除功能应该需要二次确认, 我们这里先不做.
        平常的删除数据内部其实并不是真正的删除 我们会给数据添加一个标识字段用来表示当前数据是否被删除了,如果数据被删了仅仅只是讲字段修改一个状态
        username     password	    is_delete
        jason			123				0
        egon			123				1
        '''
        models.User.objects.filter(id=del_id).delete()
        return redirect('/user_table/')
    
    

总结

# 静态文件
	# 什么是静态文件?
		已经写好的功能,可以拿来直接就用的文件static
		例如:js、css、img、前端第三方框架
	# django静态文件配置。如何配置
		提示:django项目默认不会帮你创建静态文件,需要手动创建,约定俗成的文件名为static
		到settings.py中找到STATIC_URL,并在其下面加上
		STATICFILSE_DIR={
			os.path.join(BASE_DIR,'静态创建的文件'),
			os.path.join(BASE_DIR,'静态创建的文件2'),
		}
	# 如何在解决接口前缀不断变化,html页面上路径的引用需要反复修复的问题
		在templates管理的html文件内,在head引用外部资源之前以如下书写方式:
		{% load static %}
		<script src="{% static '静态文件中的路径' %}"></script>

# form表单如果请求post请求,需要注释一行代码
	settings.py -> MIDDLEWARE
	# 'django.middleware.csrf.CsrfViewMiddleware',

# request 对象的方法
	request.method			返回大写字符串的当前请求方式
	request.GET				返回以get请求方式获得的URL中?后面的所有数据
	request.POST			返回以post请求方式提交的所有普通数据,非文件数据
	request.GET.get()       返回列表对象中的最后一个值 -> str
	request.POST.get()				
	request.GET.getlist()	返回通过get提交方式获得的所有数据
	request.POST.getlist()	返回通过post提交方式获得的所有数据

# django链接数据库
	# django自带的数据库:db.sqlite3
	# 配置更换
		1.配置数据库:找到settings.py文件中的DATABASES输入如下:
			DATABASES={
				'default':{
					'ENGINE':'django.db.backends.mysql',
					'NAME':'选择的数据库名称',
					'HOST':'IP地址',
					'PORT':端口号
					'USER':'用户名',
					'PASSWORD':'用户名对应的密码',
					'CHARSET':'选择数据库的字符编码格式'
				}
			}
		2.代码声明:使用pymysql替换dajngo自带的数据库模块MySQLdb
			前提:在项目文件夹下或者任意的应用文件夹下__init__.py种书写代码声明
			import pymysql
			pymysql.install_as_MySQLdb()
		
# django orm
	# 什么是django orm
		ORM全称是对象关系映射
		功能:通过ORM实现对操作对象的操作模式来操作数据库中的数据
		实现:通过medels中的类来对应数据库中的一个表,一个对象对应一个数据行,一个属性对应数据库中的一个字段
		缺陷:封装程度太高,有时候会出现创建SQL语句效率的问题

	# 使用django orm:进入models.py中书写模型类
		"""
		1.不指定默认创建id主键
		2.CharField必须指定max_length
		3.verbose_name所有字段都有对字段的描述
		"""
		# id int primary key auto_increment
        models.AutoField(primary_key=True, verbose_name='主键')
        # username varchar(32)
        models.CharField(max_length=32, verbose_name='用户名')
        # password varchar(255)
        models.charField(max_length=255, verbose_name='密码')
        # age int
        models.IntegerField(verbose_name='年龄')
        
    # 数据库迁移指令
    	前提:执行终端命令行当前路径一定要在项目文件夹下,且配置了python的环境变量
    		生成数据库迁移记录,记录到migrations文件夹下:
    			python manage.py makemigrations
    		将数据迁移提交:
    			python manage.py migrate

# ORM字段的增删改查
	增:
		1.在执行了生成数据库迁移记录命令之后在终端命令行输入默认值
		2.直接为字段指定可以为空
			username = models.CharField(max_length=32,null=True)
		3.为新字段指定默认值
			username = models.CharField(max_length-255,default='我是默认值')
	删:
		只要将需要被删除的字段注释掉后,提交两个数据库迁移指令即可
		注意:删除的字段对应的数据也会被删除
	改:
		直接在原来字段的基础之上进行修改即可

# 数据的增查删
	增:
		方式一:使用models自动创建
			models.表名.objects.create(属性与值对应)
		方式二:手动创建
			obj = models.表名(**kwargs)
			obj.save()
	查:
		models.表名.objects.filter(过滤条件)
		产生的是一个QuerySet对象,是一个列表套数据的对象,使用.first()调用
	删:
		models.表名.objects.filter(过滤条件).delete() 批量操作
	改:
		models.表名.objects.filter(过滤条件).update(对应修改的字段) 批量操作

六、django orm中如何建立表联系

6.1 表关系分析

表与表之间的关系: 一对多 多对多 一对一 没有关系
判断表关系的方法: 换位思考

用4张表举例: 图书表 出版社表 作者表 作者详情表
图书和出版社是一对多的关系 外键字段建在多的那一方
图书和作者是多对多的关系 需要创建第三张表来专门存储
作者与作者详情表是一对一

提示: 创建表关系 先将基表创建出来 然后再添加外键字段. 这里建表可以没有先后顺序, 不同于mysql中建立外键的创建表以及插入记录的先后顺序.

6.2 建立表

book

idtitlepricepublish_id
1python从入门到入土123.121
2生蚝的吃法大全666.661
3说不是渣男本质其实就是444.442

author

idnameage
1jason84
2egon73

book2author

idbook_idauthor_id
111
212
322
433

publish

idnameadd
1北方出版社北京
2南方出版社南京

author2detail

idphoneinfo
180080088我喜欢跑步, 所以我是跑王
288888888我喜欢吃生蚝和装逼

6.3 建立外键表关系基本语法

# django orm中建立表关系
	一对一:
		author_detail = models.OneToOneField(to='AuthorDetail')
	一对多:
		publish = models.ForeignKey(to='Publish')
	多对多:
		authors = models.ManyToManyField(to='Book')
	拓展:还可以有一种书写方式,不过这种方式必须放在被关联的类后面,这里必须放在Publish之后
		publish = models.ForeignKey(to=Publish)

# 特点和注意事项:
	1.先建立基表最后再建立外键关系,没有SQL中建立外键必须先建立被关联表,加入记录先插入被关联表这么一说,直接建立就可以了
	2.django 1.x 版本无需指定级联更新和级联删除,默认会帮你指定
	3.一对多,一对一的关系需要在关联字段后面加_id,默认会帮你加上,例如 publish -> publish_id
	4.一对多的表关系外键字段建立在多的一方
	5.多对多的表关系无需类似于SQL语句那种需要建立中间表,django会自动帮你建立虚拟的中间表
	6.一对一,多对多的表关系外键字段建立在查询频率比较高的地方

6.4 在models.py中创建以上的模型类

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=255, verbose_name='书名')
    price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格')  # 总共八位 小数点后面占两位

    # 一. 建立一对多关系: 图书和出版社是一对多 并且书是多的一方 所以外键字段放在书表里面
    """
    如果字段对应的是ForeignKey 那么会orm会自动在字段的后面加_id
    如果你自作聪明的加了_id那么orm还是会在后面继续加_id

    后面在定义ForeignKey的时候就不要自己加_id
    """
    publish = models.ForeignKey(to='Publish')  # 默认就是与出版社表的主键字段做外键关联

    # 二. 建立多对多关系: 图书和作者是多对多的关系 外键字段建在任意一方均可 但是推荐你建在查询频率较高的一方
    """
    authors是一个虚拟字段 主要是用来告诉orm 书籍表和作者表是多对多关系
    让orm自动帮你创建第三张关系表
    """
    authors = models.ManyToManyField(to='Author')


class Publish(models.Model):
    name = models.CharField(max_length=255, verbose_name='出版社名称')
    addr = models.CharField(max_length=255, verbose_name='出版社地址')


class Author(models.Model):
    name = models.CharField(max_length=255, verbose_name='作者姓名')
    age = models.IntegerField(verbose_name='作者年龄')
    # 三. 建立一对一关系: 作者与作者详情是一对一的关系 外键字段建在任意一方都可以 但是推荐你建在查询频率较高的表中
    """
    OneToOneField也会自动给字段加_id后缀
    所以你也不要自作聪明的自己加_id
    """
    author_detail = models.OneToOneField(to='AuthorDetail')


class AuthorDetail(models.Model):
    phone = models.BigIntegerField(verbose_name='作者电话号码')
    addr = models.CharField(max_length=255, verbose_name='作者家庭住址')

七、django请求生命周期流程图

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值