python web开发 django

django简介

 

web应用框架

 Django 本身基于 MVC 模型,即 Model(模型)+ View(视图)+ Controller(控制器)设计模式

用户操作流程图

创建第一个项目

django-admin startproject HelloWorld


目录结构

|-- HelloWorld
|   |-- __init__.py
|   |-- asgi.py
|   |-- settings.py
|   |-- urls.py
|   `-- wsgi.py
`-- manage.py

目录说明:

  • HelloWorld: 项目的容器。
  • manage.py: 一个实用的命令行工具,可让你以各种方式与该 Django 项目进行交互。
  • HelloWorld/__init__.py: 一个空文件,告诉 Python 该目录是一个 Python 包。
  • HelloWorld/asgi.py: 一个 ASGI 兼容的 Web 服务器的入口,以便运行你的项目。
  • HelloWorld/settings.py: 该 Django 项目的设置/配置。
  • HelloWorld/urls.py: 该 Django 项目的 URL 声明; 一份由 Django 驱动的网站"目录"。
  • HelloWorld/wsgi.py: 一个 WSGI 兼容的 Web 服务器的入口,以便运行你的项目。

命令启动服务器

python3 manage.py runserver 0.0.0.0:8000

 视图和url配置

在views. py  视图文件中操作

from django.http import HttpResponse
 
def hello(request):
    return HttpResponse("Hello world ! ")

在url.py文件中操作

from django.conf.urls import url
 
from . import views
 
urlpatterns = [
    url(r'^$', views.hello),
]

启动服务器并访问

 我们也可以在url文件中修改

from django.urls import path
 
from . import views
 
urlpatterns = [
    path('hello/', views.hello),
]

通过访问“http://127.0.0.1:8000/hello

path函数

django模板

在上一章节中我们使用 django.http.HttpResponse() 来输出 "Hello World!"。该方式将数据与视图混合在一起,不符合 Django 的 MVC 思想。

本章节我们将为大家详细介绍 Django 模板的应用,模板是一个文本,用于分离文档的表现形式和内容。

模板应用实例templates  里面放的是模板  也就是html文件

目录结构

runoob.html文件代码如下:

<h1>{{ hello }}</h1>

 向django说明模板的文件路径:

修改HelloWorld/settings.py,修改 TEMPLATES 中的 DIRS 为 [os.path.join(BASE_DIR, 'templates')]

如果你是在应用中引用模板,那么就不用修改路径,默认的就行

settings.py  代码文件块

...
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],       # 修改位置
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
...

重要,,,  记得在配置文件中引用os  import os

from pathlib import Path
import os

修改views.py 文件

from django.shortcuts import render
 
def runoob(request):
    context          = {}
    context['hello'] = 'Hello World!'
    return render(request, 'runoob.html', context)

用字典去提交数据

return render(request."runoob.html",context)

配置urls.py文件

from django.urls import path
 
from . import views
 
urlpatterns = [
    path('runoob/', views.runoob),
]

访问http://127.0.0.1:8000/runoob

django模板标签

模板语法:

view:{"HTML变量名" : "views变量名"}
HTML:{{变量名}}

views.py 文件

from django.shortcuts import render

def runoob(request):
  views_name = "菜鸟教程"
  return  render(request,"runoob.html", {"name":views_name})

runoob.html文件

<p>{{ name }}</p>

列表

重要  可以用.索引下标来取出对应的元素

views.py文件

from django.shortcuts import render

def runoob(request):
    views_list = ["菜鸟教程1","菜鸟教程2","菜鸟教程3"]
    return render(request, "runoob.html", {"views_list": views_list})

传入一个列表进去,就那么简单

在runoob.html中取列表:

<p>{{ views_list }}</p>   # 取出整个列表
<p>{{ views_list.0 }}</p> # 取出列表的第一个元素

可以取出全部的列表

也可以通过索引来取出对应的元素

效果:

 字典

重要 可以用 .键 取出对应的值。

views.py文件

from django.shortcuts import render

def runoob(request):
    views_dict = {"name":"菜鸟教程"}
    return render(request, "runoob.html", {"views_dict": views_dict})

runoob.html 文件

<p>{{ views_dict }}</p>
<p>{{ views_dict.name }}</p>

可以通过.键的方式 来取出对应的元素

效果:

过滤器

语法

{{ 变量名 | 过滤器:可选参数 }}

 文档大写转换为小写

{{ name|lower }}

第一个元素

{{ my_list|first|upper }}

以上实例将第一个元素并将其转化为大写。

有些过滤器是带有参数的

{{ bio|truncatewords:"30" }}

这个将显示变量 bio 的前30个词。

date : 按指定的格式字符串参数格式化 date 或者 datetime 对象

{{ pub_date|date:"F j, Y" }}

default

default 为变量提供一个默认值。

from django.shortcuts import render

def runoob(request):
    name =0
    return render(request, "runoob.html", {"name": name})

如果 views 传的变量的布尔值是 false,则使用指定的默认值。

下值为 false:

0  0.0  False  0j  ""  []  ()  set()  {}  None

runoob.html文件

{{ name|default:"菜鸟教程666" }}

length

返回对象的长度,适用于字符串和列表。

views.py文件

from django.shortcuts import render

def runoob(request):
    name ="菜鸟教程"
    return render(request, "runoob.html", {"name": name})

runoob.html文件

{{ name|length}}

页面效果:

filesizeformat 

data

truncatechars

 if else 标签

语法

{% if condition %}
     ... display
{% endif %}

{% if condition1 %}
   ... display 1
{% elif condition2 %}
   ... display 2
{% else %}
   ... display 3
{% endif %}

 支持逻辑运算和非运算

{% if %} 标签接受 and , or 或者 not 关键字来对多个变量做判断 ,或者对变量取反( not )

{% if %} 标签接受 and , or 或者 not 关键字来对多个变量做判断 ,或者对变量取反( not )

views.py文件

from django.shortcuts import render

def runoob(request):
    views_num = 88
    return render(request, "runoob.html", {"num": views_num})

html文件:

{%if num > 90 and num <= 100 %}
优秀
{% elif num > 60 and num <= 90 %}
合格
{% else %}
一边玩去~
{% endif %}

页面效果:

 for标签

重要 模板系统会渲染在 {% for %} 和 {% endfor %} 之间的所有内容

语法

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>

views.py文件

from django.shortcuts import render

def runoob(request):
    views_list = ["菜鸟教程","菜鸟教程1","菜鸟教程2","菜鸟教程3",]
    return render(request, "runoob.html", {"views_list": views_list})

html文件

{% for i in views_list %}
{{ i }}
{% endfor %}

页面效果

反向迭代

给标签增加一个 reversed 使得该列表被反向迭代:

{% for athlete in athlete_list reversed %}
...
{% endfor %}

遍历字典    遍历字典

直接用字典 .items 方法,用变量的解包分别获取键和值。

views.py文件

from django.shortcuts import render

def runoob(request):
    views_dict = {"name":"菜鸟教程","age":18}
    return render(request, "runoob.html", {"views_dict": views_dict})

html文件

{% for i,j in views_dict.items %}
{{ i }}---{{ j }}
{% endfor %}

页面效果

{% empty %}

可选的 {% empty %} 从句:在循环为空的时候执行

views.py文件

from django.shortcuts import render

def runoob(request):
  views_list = []
  return render(request, "runoob.html", {"listvar": views_list})

html文件:

{% for i in listvar %}
    {{ forloop.counter0 }}
{% empty %}
    空空如也~
{% endfor %}

列表为空的时候执行

ifequal标签

{% ifequal %} 标签比较两个值,当他们相等时,显示在 {% ifequal %} 和 {% endifequal %} 之中所有的值。

下面的例子比较两个模板变量 user 和 currentuser :

{% ifequal user currentuser %}
    <h1>Welcome!</h1>
{% endifequal %}
{% ifequal section 'sitenews' %}
    <h1>Site News</h1>
{% else %}
    <h1>No News Here</h1>
{% endifequal %}

注释标签

{# 这是一个注释 #}

include 标签    标签允许在模板中包含其它的模板的内容。

{% include "nav.html" %}

csrf_token

csrf_token 用于form表单中,作用是跨站请求伪造保护。

如果不用{% csrf_token %}标签,在用 form 表单时,要再次跳转页面会报403权限错误。

用了{% csrf_token %}标签,在 form 表单提交数据时,才会成功。

自定义标签和过滤器  略

配置静态文件 statics

 settings 文件的最下方配置添加以下配置:

STATIC_URL = '/static/' # 别名 
STATICFILES_DIRS = [ 
    os.path.join(BASE_DIR, "statics"), 
]

文件引用

<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7/dist/css/bootstrap.css">

模板引用

在模板中使用需要加入 {% load static %} 代码

模板继承

网页的头部和尾部内容一般都是一致的,我们就可以通过模板继承来实现复用。

父模板用于放置可重复利用的内容,子模板继承父模板的内容,并放置自己的内容。

父模板

标签 block...endblock: 父模板中的预留区域,该区域留给子模板填充差异性的内容,不同预留区域名字不能相同。

{% block 名称 %} 
预留给子模板的区域,可以设置设置默认内容
{% endblock 名称 %}

子模板

子模板使用标签 extends 继承父模板:

{% extends "父模板路径"%} 

子模板设置父模板预留区域的内容:

{ % block 名称 % }
内容 
{% endblock 名称 %}

例子

我们先创建之前项目的 templates 目录中添加 base.html 文件

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
    <h1>Hello World!</h1>
    <p>菜鸟教程 Django 测试。</p>
    {% block mainbody %}
       <p>original</p>
    {% endblock %}
</body>
</html>

unoob.html 中继承 base.html,并替换特定 block,runoob.html 修改后的代码如下:

{%extends "base.html" %}
 
{% block mainbody %}
<p>继承了 base.html 文件</p>
{% endblock %}

页面效果:

django模型 -----mysql数据库

Django 对各种数据库提供了很好的支持,包括:PostgreSQL、MySQL、SQLite、Oracle。

django orm

对象关系映射(Object Relational Mapping,简称 ORM )用于实现面向对象编程语言里不同类型系统的数据之间的转换。

ORM 在业务逻辑层和数据库层之间充当了桥梁的作用。

ORM 是通过使用描述对象和数据库之间的映射的元数据,将程序中的对象自动持久化到数据库中。

ORM 对应关系表:

数据库配置

django如何使用mysql数据库

创建 MySQL 数据库( ORM 无法操作到数据库级别,只能操作到数据表)语法:

create database 数据库名称 default charset=utf8; # 防止编码问题,指定为 utf8

例如我们创建一个名为 runoob 数据库,编码指定为 utf8:

create database runoob default charset=utf8;   

我们在项目的 settings.py 文件中找到 DATABASES 配置项,将信息修改为

DATABASES = { 
    'default': 
    { 
        'ENGINE': 'django.db.backends.mysql',    # 数据库引擎
        'NAME': 'runoob', # 数据库名称
        'HOST': '127.0.0.1', # 数据库地址,本机 ip 地址 127.0.0.1 
        'PORT': 3306, # 端口 
        'USER': 'root',  # 数据库用户名
        'PASSWORD': '123456', # 数据库密码
    }  
}

上面包含数据库名称和用户的信息,它们与 MySQL 中对应数据库和用户的设置相同。Django 根据这一设置,与 MySQL 中相应的数据库和用户连接起来。

连接数据库

接下来,告诉 Django 使用 pymysql 模块连接 mysql 数据库:

# 在与 settings.py 同级目录下的 __init__.py 中引入模块和进行配置
import pymysql
pymysql.install_as_MySQLdb()

创建app

Django 规定,如果要使用模型,必须要创建一个 app。我们使用以下命令创建一个 TestModel 的 app:

语法

django-admin.py startapp TestModel
 python manage.py startapp 名字

目录结构

HelloWorld
|-- HelloWorld
|-- manage.py
...
|-- TestModel
|   |-- __init__.py
|   |-- admin.py
|   |-- models.py
|   |-- tests.py
|   `-- views.py

我们修改 TestModel/models.py 文件

# models.py
from django.db import models
 
class Test(models.Model):
    name = models.CharField(max_length=20)

重要   以上的类名代表了数据库表名,且继承了models.Model,类里面的字段代表数据表中的字段(name),数据类型则由CharField(相当于varchar)、DateField(相当于datetime), max_length 参数限定长度。

类名代表数据库表名   类里的字段代表数据库表的字段

接下来在 settings.py 中找到INSTALLED_APPS这一项,如下:

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'TestModel',               # 添加此项
)

在命令行中运行:

$ python3 manage.py migrate   # 创建表结构

$ python3 manage.py makemigrations TestModel  # 让 Django 知道我们在我们的模型有一些变更
$ python3 manage.py migrate TestModel   # 创建表结构

看到几行 "Creating table…" 的字样,你的数据表就创建好了。

Creating tables ...
……
Creating table TestModel_test  #我们自定义的表
……

常见报错信息

原因是 MySQLclient 目前只支持到 Python3.4

l略

数据库操作

接下来我们在 HelloWorld 目录中添加 testdb.py 文件(下面介绍),并修改 urls.py:

from django.urls import path
 
from . import views,testdb
 
urlpatterns = [
    path('runoob/', views.runoob),
    path('testdb/', testdb.testdb),
]

添加数据

添加数据需要先创建对象,然后再执行 save 函数,相当于SQL中的INSERT:

# -*- coding: utf-8 -*-
 
from django.http import HttpResponse
 
from TestModel.models import Test
 
# 数据库操作
def testdb(request):
    test1 = Test(name='runoob')
    test1.save()
    return HttpResponse("<p>数据添加成功!</p>")

效果:

获取数据

testdb.py:

# -*- coding: utf-8 -*-
 
from django.http import HttpResponse
 
from TestModel.models import Test
 
# 数据库操作
def testdb(request):
    # 初始化
    response = ""
    response1 = ""
    
    
    # 通过objects这个模型管理器的all()获得所有数据行,相当于SQL中的SELECT * FROM
    list = Test.objects.all()
        
    # filter相当于SQL中的WHERE,可设置条件过滤结果
    response2 = Test.objects.filter(id=1) 
    
    # 获取单个对象
    response3 = Test.objects.get(id=1) 
    
    # 限制返回的数据 相当于 SQL 中的 OFFSET 0 LIMIT 2;
    Test.objects.order_by('name')[0:2]
    
    #数据排序
    Test.objects.order_by("id")
    
    # 上面的方法可以连锁使用
    Test.objects.filter(name="runoob").order_by("id")
    
    # 输出所有数据
    for var in list:
        response1 += var.name + " "
    response = response1
    return HttpResponse("<p>" + response + "</p>")

更新数据

修改数据可以使用 save() 或 update():

# -*- coding: utf-8 -*-
 
from django.http import HttpResponse
 
from TestModel.models import Test
 
# 数据库操作
def testdb(request):
    # 修改其中一个id=1的name字段,再save,相当于SQL中的UPDATE
    test1 = Test.objects.get(id=1)
    test1.name = 'Google'
    test1.save()
    
    # 另外一种方式
    #Test.objects.filter(id=1).update(name='Google')
    
    # 修改所有的列
    # Test.objects.all().update(name='Google')
    
    return HttpResponse("<p>修改成功</p>")

删除数据

# -*- coding: utf-8 -*-
 
from django.http import HttpResponse
 
from TestModel.models import Test
 
# 数据库操作
def testdb(request):
    # 删除id=1的数据
    test1 = Test.objects.get(id=1)
    test1.delete()
    
    # 另外一种方式
    # Test.objects.filter(id=1).delete()
    
    # 删除所有数据
    # Test.objects.all().delete()
    
    return HttpResponse("<p>删除成功</p>")

django模型 ---sqlite

数据库配置       settings配置  就是默认就好

创建模型

模型==一个数据库表       里面的字段是数据库表里面的字段

在appzhong的models.py模块中   应用的模型都存 在这里

常用字段  约束

关系

例子

在底层数据表中创建

python manage.py migrate   # 创建表结构

python manage.py makemigrations TestModel  # 让 Django 知道我们在我们的模型有一些变更
python manage.py migrate TestModel   # 创建表结构

数据驱动

添加数据 

获取对象

条件查询对象

例子  重要   将数据库的文件显示在页面

app中models.py文件

class Category(models.Model):
    name=models.CharField(max_length=128,unique=True)
    count=models.IntegerField(default=0)

    def __str__(self):
        return self.name

views.py

from blog(app名字) import models
from django.shortcuts import render

def Category(request):
    categories=models.Category.objects.all()
    return render(request, "category.html", {"categories": categories})

category.html

{% extends 'base.html' %}
{% block title %}文章列表{% endblock %}
{% block content%}
<div class="post">
    <h2 class="title">文章列表</h2>

    <div class="entry">
        <table>
            <tr>
                <th>分类</th>
                <th>文章数量</th>
            </tr>
            {% for category in categories %}
            <tr>
                <td>{{ category.name }}</td>
                <td>{{category.count}}</td>
            </tr>
            {% endfor %}
        </table>
    </div>
</div>
{% endblock %}

页面效果:

详情页面

利用url接受不同的参数,让视图接受参数进行查询

优雅地址方式

案例

         

这个不懂

获得可读性高的url地址

pip install django-uuslug

 model操作

 给模型添加slug属性

导入from uuslug import slugify 包

重写save方法

from django.db import models
from uuslug import slugify

# Create your models here.

class Category(models.Model):
    name=models.CharField(max_length=128,unique=True)
    count=models.IntegerField(default=0)
    slug=models.SlugField(blank=True)
    



    def save(self,*args,**kwargs):
        self.slug=slugify(self.name)
        super(Category,self).save(*args,**kwargs)

    def __str__(self):
        return self.name

python manage.py makemigrations这个命令是记录我们对models.py的所有改动,并且将这个改动迁移到migrations这个文件下生成一个文件例如:0001文件,如果你接下来还要进行改动的话可能生成就是另外一个文件不一定都是0001文件,但是这个命令并没有作用到数据库,这个刚刚我们在上面的操作过程之后已经看到了,而当我们执行python manage.py migrate 命令时 这条命令的主要作用就是把这些改动作用到数据库也就是执行migrations里面新改动的迁移文件更新数据库,比如创建数据表,或者增加字段属性

为分类页的视图函数添加一个参数 

 views.py

def Page(request,slug):
    category=models.Category.objects.get(slug=slug)
    page=models.Page.objects.filter(category_id=category.id)
    return render(request, "page.html", {"pages": page})

urls.py

from django.contrib import admin
from django.urls import path
from blog import views as blog_vw

urlpatterns = [
    path('admin/', admin.site.urls),
    path('home/',blog_vw.home),
    path('homeinclude/',blog_vw.home_include),
    path('usetemplate/',blog_vw.use_template),
    path('category/',blog_vw.Category,name="category"),
    path('pages/<str:slug>/',blog_vw.Page,name="page"),
]

models.py

class Page(models.Model):
    category=models.ForeignKey(Category,on_delete=models.CASCADE)
    title=models.CharField(max_length=128)
    content=models.CharField(max_length=1024,blank=True)
    url=models.URLField()
    views=models.IntegerField(default=0)

    def __str__(self):
        return self.title

这是what

django表单

本章将介绍如何用Django对用户提交的表单数据进行处理。

http请求

HTTP协议以"请求-回复"的方式工作。客户发送请求时,可以在请求中附加数据。服务器通过解析请求,就可以获得客户传来的数据,并根据URL来提供特定的服务。

通过表单 from 来提交数据到服务器进行处理

html的表单

 

 

表单属性

 

action属性:定义在提交表单是执行的目标url。向服务器提交数据一般用  提交按钮

django的from类

django构建表单

 

 在app下 建立forms.py文件

from django import forms

class UserForm(forms.Form):
    user_name = forms.CharField(label='姓名', max_length=100)
    user_age = forms.IntegerField(label='年龄')
    email=forms.EmailField(label='邮箱', max_length=100)

视图类

视图

def FormExample(request):
    if request.method == 'POST':        
        form = UserForm(request.POST)        
        if form.is_valid(): 
            username = form.cleaned_data['user_name']
            userage = form.cleaned_data['user_age']
            email = form.cleaned_data['email']          
            return render(request, 'formexample.html', {'result': username+" "+str(userage)+"岁 邮箱:"+email})  
    else:
        form = UserForm()

    return render(request, 'formexample.html', {'form': form})

模板中插入form

{% extends 'base.html' %}
{% block title %}简单表单例子{% endblock %}
{% block content%}
<div class="post">
    <div class="entry">
        <form action="/formexample/" method="post">
            {% csrf_token %}
            {{ form }}
            <input type="submit" value="提交">
        </form>
        {{result}}
    </div>
</div>

{% endblock %}

post方法

在 templates 创建 post.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
    <form action="/search-post/" method="post">
        {% csrf_token %}
        <input type="text" name="q">
        <input type="submit" value="搜索">
    </form>
 
    <p>{{ rlt }}</p>
</body>
</html>

在模板的末尾,我们增加一个 rlt 记号,为表格处理结果预留位置。

表格后面还有一个{% csrf_token %}的标签。csrf 全称是 Cross Site Request Forgery。这是Django提供的防止伪装提交请求的功能。POST 方法提交的表格,必须有此标签。

在HelloWorld目录下新建 search2.py 文件并使用 search_post 函数来处理 POST 请求:

# -*- coding: utf-8 -*-
 
from django.shortcuts import render
from django.views.decorators import csrf
 
# 接收POST请求数据
def search_post(request):
    ctx ={}
    if request.POST:
        ctx['rlt'] = request.POST['q']
    return render(request, "post.html", ctx)

urls.py 

from django.conf.urls import url
from . import views,testdb,search,search2
 
urlpatterns = [
    url(r'^hello/$', views.hello),
    url(r'^testdb/$', testdb.testdb),
    url(r'^search-form/$', search.search_form),
    url(r'^search/$', search.search),
    url(r'^search-post/$', search2.search_post),
]

访问 http://127.0.0.1:8000/search-post/

目录结构为

HelloWorld
|-- HelloWorld
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- search.py
|   |-- search.pyc
|   |-- search2.py
|   |-- search2.pyc
|   |-- settings.py
|   |-- settings.pyc
|   |-- testdb.py
|   |-- testdb.pyc
|   |-- urls.py
|   |-- urls.pyc
|   |-- views.py
|   |-- views.pyc
|   |-- wsgi.py
|   `-- wsgi.pyc
|-- TestModel
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- admin.py
|   |-- admin.pyc
|   |-- apps.py
|   |-- migrations
|   |   |-- 0001_initial.py
|   |   |-- 0001_initial.pyc
|   |   |-- __init__.py
|   |   `-- __init__.pyc
|   |-- models.py
|   |-- models.pyc
|   |-- tests.py
|   `-- views.py
|-- db.sqlite3
|-- manage.py
`-- templates
    |-- base.html
    |-- hello.html
    |-- post.html
    `-- search_form.html

Request 对象

每个视图函数的第一个参数是一个 HttpRequest 对象,就像下面这个 runoob() 函数:

from django.http import HttpResponse

def runoob(request):
    return HttpResponse("Hello world")

添加数据

 、

 

 

表单渲染

简单渲染

 

 

手动渲染

 

 form类字段的详细定义

 

 

钩子函数 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值