Python学习:Django开发_01

Python学习:Django开发_01

来源:白月黑羽教Python http://www.python3.vip/tut/webdev/django/01/

常用命令/配置

安装

pip install django

运行

python manage.py runserver 0.0.0.0:80

使用其他的网址登陆

在setting中修改设置

ALLOWED_HOSTS = ['192.168.1.100','localhost','127.0.0.1']

创建一个APP

进入项目根目录,执行下面的命令

python manage.py startapp APP名称 

创建数据库

python manage.py migrate

创建数据库脚本

python manage.py makemigrations APP名称

执行数据库脚本

python manage.py migrate

创建一个超级管理员账号

进入到项目的根目录,执行如下命令,依次输入你要创建的管理员的 登录名、email、密码

python manage.py createsuperuser

安装与运行

安装

pip install django

创建项目

django-admin startproject bysms

目录结构

  • 最外层 bysms/ 就是项目根目录 d:\projects\bysms\ , 项目文件都放在里面。

  • manage.py 是一个工具脚本,用作项目管理的。以后我们会使用它执行管理操作。

  • 里面的 bysms/ 目录是python包。 里面包含项目的重要配置文件。这个目录名字不能随便改,因为manage.py 要用到它。

  • bysms/settings.py 是 Django 项目的配置文件. 包含了非常重要的配置项,以后我们可能需要修改里面的配置。

  • bysms/urls.py 里面存放了 一张表, 声明了前端发过来的各种http请求,分别由哪些函数处理. 这个我们后面会重点的讲。

  • bysms/wsgi.py
    要了解这个文件的作用, 我们必须明白wsgi 是什么意思

    python 组织制定了 web 服务网关接口(Web Server Gateway Interface) 规范 ,简称wsgi。参考文档 https://www.python.org/dev/peps/pep-3333/

    遵循wsgi规范的 web后端系统, 我们可以理解为 由两个部分组成

    wsgi web serverwsgi web application

    它们通常是运行在一个python进程中的两个模块,或者说两个子系统。

    wsgi web server 接受到前端的http请求后,会调用 wsgi web application 的接口( 比如函数或者类方法)方法,由wsgi web application 具体处理该请求。然后再把处理结果返回给 wsgi web serverwsgi web server再返回给前端。

    如下图所示

    白月黑羽Python3教程

    为什么要搞出两个子系统,这么麻烦呢?

    因为这两个子系统有各自负责的重点。

    wsgi web server 负责 提供高效的http请求处理环境,可以使用多线程、多进程或者协程的机制。

    http 请求发送到 wsgi web serverwsgi web server 分配 线程或者进程或者 轻量级线程(协程),然后在 这些 线程、进程、或者协程里面,去调用执行 wsgi web application 的入口代码。

    wsgi web application 被调用后,负责 处理 业务逻辑。 业务逻辑的处理可能非常复杂, wsgi web application 需要精心的设计来正确处理。

    django是 wsgi web application 的框架,它只有一个简单的单线程 wsgi web server。 供调试时使用。

    产品正式上线运行的时候,通常我们需要高效的 wsgi web server 产品,比如 gunicorn,uwsgi,cherrypy等,结合Django ,组成一个高效的 后端服务。

    所以这个 wsgi.py 就是 提供给wsgi web server调用 的接口文件,里面的变量application对应对象实现了 wsgi入口,供wsgi web server调用 。

运行

python manage.py runserver 0.0.0.0:80

运行 Django web服务

刚才我们说了, django虽然只是 wsgi web application 的框架,但是它也有一个简单的 wsgi web server。 供调试时使用。

所以也构成一个完整的后端web服务。 本地调试代码的时候,完全可以运行起来。

运行开发web 服务只需要在命令行窗口里面,

首先进入到项目根目录 ,比如,我们这里就是 d:\projects\bysms\

然后执行如下命令

python manage.py runserver 0.0.0.0:80

这样服务就会被启动。 我们就可以在浏览器访问web服务了。

其中 0.0.0.0:80 是指定 web服务绑定的 IP 地址和端口。

0.0.0.0 表示绑定本机所有的IP地址, 就是可以通过任何一个本机的IP (包括 环回地址 127.0.0.1) 都可以访问我们的服务。

80 表示是服务启动在80端口上。

请打开浏览器,地址栏输入 ‘127.0.0.1’ ,就可以看到如下的界面,表示Django服务搭建成功,启动成功。

白月黑羽Python3教程

注意,启动web服务的命令行窗口不能关闭,如果关闭,web服务就停止了。

使用其他的网址登陆

在setting中修改设置

ALLOWED_HOSTS = ['192.168.1.100','localhost','127.0.0.1']

HTTP请求和URL路由

Django 中创建app 可以 通过执行命令,创建一个app目录,并在里面自动创建app常用的文件。

比如,现在我们需要一个app 专门处理 白月医药系统中销售员的 添加、修改、查询、删除请求。

我们就进入项目根目录,执行下面的命令。

python manage.py startapp sales 

比如,我们 设计 凡是浏览器访问的http 请求的 url 地址 是 /sales/orders/ , 就由 views.py 里面的函数 listorders 来处理, 返回一段字符串给浏览器。

请大家 打开 views.py , 在里面加入如下内容

from django.http import HttpResponse

def listorders(request):
    return HttpResponse("下面是系统中所有的订单信息。。。")

注意

  • 这里面最终的返回结果是 HttpResponse 对象的参数字符串 ,也就是这句话

    下面是系统中所有的订单信息。。。

  • listorders的参数request是Django中的 HttpQuest对象,包含了请求中的信息。

    它的用法后面会讲。这里暂时用不到该参数。

光是定义了这样一个函数不行的,我们需要 告诉 Django

当前端发送过来的HTTP请求 url地址 是 /sales/orders/ , 就由 views.py 里面的函数 listorders 来处理

怎么告诉Django呢?

这就是 Django中的 url路由设置。

创建数据库和表

## 创建数据库

项目中数据库的配置在 bysms/settings.py 中,这里

# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

大家可以发现,我们使用命令创建的项目, 缺省就是使用 sqlite。 而且对于的数据库文件,缺省的文件名是 db.sqlite3 , 就在项目的根目录下面。

python manage.py migrate

就会在 项目的根目录下面 生成一个配置文件中指定的数据库文件 db.sqlite3

并且 会在其中创建一些表。

定义我们的 数据库表

我们开发系统,需要定义我们需要的数据库表。

首先,我们再创建一个名为common的应用目录, 里面存放我们项目需要的一些公共的表的定义。

大家还记得创建应用的命令吗?

对了, 进入项目根目录,执行下面的命令。

python manage.py startapp common 

就会创建一个目录名为 common, 对应 一个名为 common 的app,里面包含了如下自动生成的文件。

common/
    __init__.py
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

前面已经说过,Django是通过定义类来定义数据库表的。

所以,我们要定义数据库的表,无需执行sql语句,只需要在app目录下面 定义特殊的类就可以了。

数据库表的定义,一般是放在app目录中的 models.py里面的。

打开 common/models.py,发现里面是空的,因为我们还没有定义我们的业务所需要的表。

我们修改它,加入如下内容

from django.db import models

class Customer(models.Model):
    # 客户名称
    name = models.CharField(max_length=200)

    # 联系电话
    phonenumber = models.CharField(max_length=200)

    # 地址
    address = models.CharField(max_length=200)

这个 Customer 类继承自 django.db.models.Model, 就是用来定义数据库表的。

里面的 name、phonenumber、address 是该表的3个字段。

定义表中的字段 就是定义一些静态属性,这些属性是 django.db.models 里面的各种 Field 对象,对应不同类型的字段。

比如这里的3个字段 都是 CharField 对象,对应 varchar类型的数据库字段。

后面的参数 max_length 指明了该 varchar字段的 最大长度。

Djanog 有很多字段对象类型, 对应不同的类型的数据库字段。

创建数据库表

定义好表以后,我们怎么真正去创建数据库表呢?

首先我们需要告诉Django: 我们的 common 应用中 需要你关注, 因为其中包含了 数据库Model的定义。

怎么告诉它? 在项目的配置文件 settings.py中, INSTALLED_APPS 配置项 加入如下内容

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # 加入下面这行
    'common.apps.CommonConfig',
]

‘common.apps.CommonConfig’ 告诉 Django , CommonConfig 是 common/apps.py 文件中定义的一个应用配置的类。

是这样的

class CommonConfig(AppConfig):
    name = 'common'

CommonConfig 是 AppConfig的 子类, 就表示这个是应用的配置类。

这里 name = ‘common’ , name 是用来定义 应用的python模块路径的。 这里就是说 应用 模块路径为 common 。

关于 其他的配置参数, 大家可以参考官方文档

https://docs.djangoproject.com/en/dev/ref/applications/#configurable-attributes

现在Django知道了我们的 common 应用, 我们可以在项目根目录下执行命令

python manage.py makemigrations common

得到如下结果

Migrations for 'common':
  common\migrations\0001_initial.py
    - Create model Customer

这个命令,告诉Django , 去看看common这个app里面的models.py ,我们已经修改了数据定义, 你现在去产生相应的更新脚本。

执行一下,会发现在 common\migrations 目录下面出现了0001_initial.py, 这个脚本就是相应要进行的数据库操作代码。

随即,执行如下命令

python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, common, contenttypes, sessions
Running migrations:
  Applying common.0001_initial... OK

就真正去数据库创建表了。

用 sqlitestudio 查看数据库,发现创建了一张名为 common_customer的表,如下

白月黑羽Python3教程

其中 3 个字段就是我们上面定义的 Customer 类里面的 name、phonenumber、address 属性名。

多出来的 id 字段是该表的主键, 是Django自动帮我们添加的。

这个不需要我们在类中显式的定义。

注意

如果以后我们修改了Models.py 里面的库表的定义,都需要再次运行 python manage.py makemigrations common 和 python manage.py migrate 命令,使数据库同步该修改结果

Django Admin 管理数据

Django提供了一个管理员操作界面可以方便的 添加、修改、删除你定义的 model 表数据。

首先,我们需要创建 一个超级管理员账号。

进入到项目的根目录,执行如下命令,依次输入你要创建的管理员的 登录名、email、密码。

python manage.py createsuperuser
d:\projects\bysms>python manage.py createsuperuser
Username (leave blank to use 'byhy'): byhy
Email address: byhy@163.com
Password:
Password (again):
Superuser created successfully.

注意密码至少8个字符。 这里,我们设置密码为 88888888

然后我们需要修改应用里面的 管理员 配置文件 common/admin.py,注册我们定义的model类。这样Django才会知道

from django.contrib import admin

from .models import Customer

admin.site.register(Customer)

好了,现在就可以访问 http://127.0.0.1/admin/,输入刚才注册的用户密码登录。

登录后可以看到如下界面。这里面是目前系统中可以修改的表。

点击我们的定义的Customers表

白月黑羽Python3教程

点击下面的 ADD CUSTOMER 按钮来添加一条客户记录

白月黑羽Python3教程

在跳出的界面中输入客户信息后,点击SAVE按钮

白月黑羽Python3教程

完成上面操作后,我们使用数据库查看工具,就发现数据库中确实有了添加的数据信息。

白月黑羽Python3教程

如果你是中文的操作系统,想使用中文的admin界面,应该在配置文件 settings.pyMIDDLEWARE 最后加入如下配置

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    # admin界面语言本地化
    'django.middleware.locale.LocaleMiddleware',
]

要注意上面的界面 Django 内置的给管理员使用的。只是实现了一些通用的功能,而且界面语言偏英语的。

在实际的工作项目中, 还是需要我们自己开发前端界面给他们使用。

读取数据库数据

获取全部记录

前面,我们已经创建了数据库和 Customer表。

现在我们来实现一个功能:浏览器访问 sales/customers/ ,我们的服务端就返回系统中所有的客户记录给浏览器。


我们先实现一个函数,来处理浏览器发出的URL为 sales/customers/ 的访问请求, 我们需要返回 数据库中 customer 表 所有记录。

Django 中 对数据库表的操作, 应该都通过 Model对象 实现对数据的读写,而不是通过SQL语句。

比如,这里我们要获取 customer 表 所有记录, 该表是和我们前面定义的 Customer 类管理的。

我们可以这样获取所有的表记录:

在文件sales/views.py 中,定义一个listcustomers 函数,内容如下:

# 导入 Customer 对象定义
from  common.models import  Customer

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    # 每条表记录都是是一个dict对象,
    # key 是字段名,value 是 字段值
    qs = Customer.objects.values()

    # 定义返回字符串
    retStr = ''
    for customer in  qs:
        for name,value in customer.items():
            retStr += f'{name} : {value} | '

        # <br> 表示换行
        retStr += '<br>'

    return HttpResponse(retStr)

Customer.objects.values() 就会返回一个 QuerySet 对象,这个对象是Django 定义的,在这里它包含所有的Customer 表记录。

QuerySet 对象 可以使用 for 循环遍历取出里面所有的元素。每个元素 对应 一条表记录。

每条表记录元素都是一个dict对象,其中 每个元素的 key 是表字段名,value 是 该记录的字段值

上面的代码就可以将 每条记录的信息存储到字符串中 返回给 前端浏览器。

我们还需要修改路由表, 加上对 sales/customers/ url请求的 路由。

前面,我们在bysms\urls.py 主路由文件中,已经有如下的记录了

    # 凡是 url 以 sales/  开头的,
    # 都根据 sales.urls 里面的 子路由表进行路由
    path('sales/', include('sales.urls')),

这条URL记录,指明 凡是 url 以 sales/ 开头的,都根据 sales.urls 里面的 子路由表进行路由。

我们只需修改 sales/urls.py 即可,添加如下记录

path('customers/', views.listcustomers),

大家可以使用 admin 登录, 再添加一些 客户记录。

然后可以在浏览器输入如下 网址: http://127.0.0.1/sales/customers/

回车后,浏览器显示结果类似如下

白月黑羽Python3教程

和我们数据库中的记录信息一致

白月黑羽Python3教程

过滤条件

有的时候,我们需要根据过滤条件查询部分客户信息。

比如,当用户在浏览器输入 /sales/customers/?phonenumber=13000000001 ,要求返回电话号码为 13000000001 客户记录。

我们可以通过filter方法加入过滤条件,修改view里面的代码,如下所示

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Customer.objects.values()

    # 检查url中是否有参数phonenumber
    ph =  request.GET.get('phonenumber',None)

    # 如果有,添加过滤条件
    if ph:
        qs = qs.filter(phonenumber=ph)

    # 定义返回字符串
    retStr = ''
    for customer in  qs:
        for name,value in customer.items():
            retStr += f'{name} : {value} | '
        # <br> 表示换行
        retStr += '<br>'

    return HttpResponse(retStr)

看到函数定义的参数 request了吗?

Django 框架在 url 路由匹配到函数后, 调用函数时,会传入 一个 HttpRequest 对象给参数变量 request,该对象里面 包含了请求的数据信息。

HTTP 的 Get 请求url里面的参数(术语叫 querystring 里面的参数), 可以通过 HttpRequest对象的 GET 属性获取。这是一个类似dict的对象。

比如要获取querystring里面的 phonenumber 参数 ,就可以像这样

ph =  request.GET.get('phonenumber',None)

第二个参数传入 None 表示,如果没有 phonenumber 参数在 querystring中 ,就会返回 None。

然后通过调用 QuerySet 对象的filter方法,就可以把查询过滤条件加上去

qs = qs.filter(phonenumber=ph)

有了这个过滤条件,Django 会在底层执行数据库查询的SQL语句 加上相应的 where 从句,进行过滤查询。

注意,参数名 phonenumber 是和 定义的表 model 的属性名 phonenumber 一致的。

filter的过滤条件可以有多个,只要继续在后面的参数添加过滤条件即可。

比如

qs = qs.filter(phonenumber=ph,address='安徽芜湖')

这样就 除了 根据电话号码字段过滤,还有根据 地址字段过滤。

现在在浏览器输入如下 url

http://127.0.0.1/sales/customers/?phonenumber=13000000001

访问结果如下

白月黑羽Python3教程

可以发现过滤条件生效了。

前后端分离的架构

前面,我们的数据展示在界面上是这样的

白月黑羽Python3教程

很不好看。

因为我们返回的其实就是字符串,并不是HTML。

要好看一些,我们可以使用HTML来展示数据。

代码直接生成HTML

HTML本身其实也是字符串,只是这个字符串里面的内容是符合HTML语言规范的。

既然它也是字符串,我们可以使用Python直接构建出 HTML 字符串内容。

修改

# 先定义好HTML模板
html_template ='''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
table {
    border-collapse: collapse;
}
th, td {
    padding: 8px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}
</style>
</head>
    <body>
        <table>
        <tr>
        <th>id</th>
        <th>姓名</th>
        <th>电话号码</th>
        <th>地址</th>
        </tr>
        
        %s
        
        
        </table>
    </body>
</html>
'''

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Customer.objects.values()

    # 检查url中是否有参数phonenumber
    ph =  request.GET.get('phonenumber',None)

    # 如果有,添加过滤条件
    if ph:
        qs = qs.filter(phonenumber=ph)

    # 生成html模板中要插入的html片段内容
    tableContent = ''
    for customer in  qs:
        tableContent += '<tr>'

        for name,value in customer.items():
            tableContent += f'<td>{value}</td>'

        tableContent += '</tr>'

    return HttpResponse(html_template%tableContent)

我们用一个变量 html_template 存储html模板, 然后 代码中生成html 里面需要插入的表格记录的内容,这个内容是html片段,也就是 html 表格的每行 。

最后填入到 html_template 模板里面,就产生了完整的HTML 字符串。

最后返回该 html 文档 字符串 即可。

修改后,再次访问 http://127.0.0.1/sales/customers/

得到如下内容

白月黑羽Python3教程

使用模板

上面我们是用Python代码直接拼接出html内容。

但是这种方式,我们代码处理比较麻烦。特别是,如果html里面有多处内容需要填入,使用Python代码直接拼接就显得很繁杂,不好维护。

很多后端框架都提供了一种 模板技术, 可以在html 中嵌入编程语言代码片段, 用模板引擎(就是一个专门处理HTML模板的库)来动态的生成HTML代码。

比如JavaEE 里面的JSP。

Python 中有很多这样的模板引擎 比如 jinja2 、Mako, Django也内置了一个这样的模板引擎。

我们修改一下代码,使用Django的模板引擎

# 先定义好HTML模板
html_template ='''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
table {
    border-collapse: collapse;
}
th, td {
    padding: 8px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}
</style>
</head>
    <body>
        <table>
        <tr>
        <th>id</th>
        <th>姓名</th>
        <th>电话号码</th>
        <th>地址</th>
        </tr>

        {% raw  %}

        {% for customer in customers %}
            <tr>

            {% for name, value in customer.items %}            
                <td>{{ value }}</td>            
            {% endfor %}
            
            </tr>
        {% endfor %}

        {% endraw %}
                
        </table>
    </body>
</html>
'''

from django.template import engines
django_engine = engines['django']
template = django_engine.from_string(html_template)

def listcustomers(request):
    # 返回一个 QuerySet 对象 ,包含所有的表记录
    qs = Customer.objects.values()

    # 检查url中是否有参数phonenumber
    ph =  request.GET.get('phonenumber',None)

    # 如果有,添加过滤条件
    if ph:
        qs = qs.filter(phonenumber=ph)

    # 传入渲染模板需要的参数
    rendered = template.render({'customers':qs})

    return HttpResponse(rendered)

然后,访问浏览器,可以得到一样的结果。

对比 Python直接产生 HTML,大家可以发现,使用模板引擎的好处,就是产生HTML的代码更简单方便了。

因为我们可以直接把要生成的 HTML片段 写在 HTML模板 里面。

然后,只需要传入渲染模板所需要的参数就可以了,模板引擎会自动化帮我们生成的HTML

上面只是一种模板用法的简单演示。

关于Django模板的详细用法,大家可以参考官方文档

前后端分离架构

有了模板引擎,对我们后端开发来说,简化了程序员后端生成HTML的任务,提高了开发效率。

但是,通常后端开发人员的核心任务不是开发前端界面, 而且大部分后端开发人员对前端界面开发还是不熟悉的。

前端界面的开发还是得由前端人员去做。

如果动态的界面内容都是由后端模板生成, 就意味着前端开发人员要接触后端的模板。

比如这里,就需要他们了解Django的HTML模板。

或者需要前端人员提供他们做好的HTML, 交给后端人员,再由后端人员把它修改成Django模板。

这样有什么问题?

  • 不利于前后端开发任务的分离,前后端开发人员要做额外的沟通。

  • 如果前端除了web浏览器,还有手机APP的话, APP 不需要服务端返回HTML, 就得再开发一套数据接口

  • 渲染任务在后端执行,大大的增加了后端的性能压力。

    尤其是有的HTML页面很大, 当有大量的用户并发访问的时候, 后端渲染工作量很大,很耗费CPU 资源。


现在随着 浏览器中javascript 解释器性能的突飞猛进,以及一些前端模板库和框架的流行。很多架构师将 页面的html 内容生成 的任务放到前端。

这样 服务端就只负责提供数据, 界面的构成全部在前端(浏览器前端或者手机前端)进行,称之为前端渲染。

只是这个工作在前端执行, 使用前端的 框架库去完成,比如angular,react,vue。

这样 界面完全交给前端开发人员去做, 后端开发只需要提供前端界面所需要的数据就行了。

前端 和 后端 之间的交互就完全是 业务数据了。

这样需要 定义好 前端和后端 交互数据 的接口。

目前通常这样的接口设计最普遍的就是使用 REST 风格的 API 接口。

前端通过 API 接口 从后端获取数据展示在界面上。

前端通过 API 接口 告诉后端需要更新的数据是什么。

通常 前后端的 API 接口 是由 架构师 设计的, 有时也可以由经验丰富的前端开发者、或者后端开发者设计。

接下来我们就聚焦在后端,我们的系统前端由另外的团队开发,我们只负责后端业务数据的维护

现在我们的系统,API接口 已经由架构师定义好了, 点击这里查看

我们只需要根据这个接口文档,实现后端系统的部分。


注意:需要Django返回的信息,通常都是所谓的 动态 数据信息。 比如:用户信息,药品信息,订单信息,等等。

这些信息通常都是存在数据库中,这些信息是会随着系统的使用发生变化的。

静态 信息,比如: 页面HTML文档、css文档、图片、视频等,是不应该由 Django 负责返回数据的。

这些数据通常都是由其他的 静态资源服务软件,比如 Nginx、Varnish等等,返回给前端。这些软件都会有效的对静态数据进行缓存,大大提高服务效率。在实际的项目中,往往还会直接使用 静态文件 云服务( OSS + CDN )提供静态数据的访问服务。

总之,Django处理并返回的应该是动态业务数据信息。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值