【Django笔记】md文档第6篇:Django视图、Cookie和session状态、模板和过滤器

举报
程序员一诺112 发表于 2023/11/24 20:39:18 2023/11/24
【摘要】 Django的主要目的是简便、快速的开发数据库驱动的网站。它强调代码复用,多个组件可以很方便的以"插件"形式服务于整个框架,Django有许多功能强大的第三方插件,你甚至可以很方便的开发出自己的工具包。这使得Django具有很强的可扩展性。它还强调快速开发和DRY(DoNotRepeatYourself)原则

Django的主要目的是简便、快速的开发数据库驱动的网站。它强调代码复用,多个组件可以很方便的以"插件"形式服务于整个框架,Django有许多功能强大的第三方插件,你甚至可以很方便的开发出自己的工具包。这使得Django具有很强的可扩展性。它还强调快速开发和DRY(DoNotRepeatYourself)原则


Django全套笔记请自取: 请移步这里


共 4 章,47 子模块





视图




重点


  • HttpRequest

    • 位置参数和关键字参数

    • 查询字符串

    • 请求体:表单数据,JSON数据

    • 请求头

  • HttpResponse

    • HttpResponse

    • JsonResponse

    • redirect

  • 类视图

    • 类视图的定义和使用

    • 类视图装饰器(难点)



HttpRequest对象


回想一下,利用HTTP协议向服务器传参有几种途径?

  • 提取URL的特定部分,如/weather/beijing/2018,可以在服务器端的路由中用正则表达式截取;

  • 查询字符串(query string),形如key1=value1&key2=value2;

  • 请求体(body)中发送的数据,比如表单数据、json、xml;

  • 在http报文的头(header)中。


1 URL路径参数


  • 如果想从URL中值,需要在正则表达式中使用分组

  • 值分为两种方式

    • 位置参数

      • 参数的位置不能错

    • 关键字参数

      • 参数的位置可以变,跟关键字保持一致即可

  • 注意:两种参数的方式不要混合使用,在一个正则表达式中只能使用一种参数方式

  • 分别使用以上两种URL值的方式提取出18 188

    • http://127.0.0.1:8000/18/188/



位置参数


  • 应用中urls.py

url(r'^(\d+)/(\d+)/$', views.index),


  • 视图中函数: 参数的位置不能错

def index(request, value1, value2):
      # 构造上下文
      context = {'v1':value1, 'v2':value2}
      return render(request, 'Book/index.html', context)




关键字参数


  • 应用中urls.py

    • 其中?P<value1>部分表示为这个参数定义的名称为value1

    • 可以是其它名称,起名要做到见名知意

    url(r'^(?P<value1>\d+)/(?P<value2>\d+)/$', views.index),


  • 视图中函数: 参数的位置可以变,跟关键字保持一致即可

def index(request, value2, value1):
      # 构造上下文
      context = {'v1':value1, 'v2':value2}
      return render(request, 'Book/index.html', context)




2 Django中的QueryDict对象


HttpRequest对象的属性GET、POST都是QueryDict类型的对象

与python字典不同,QueryDict类型的对象用来处理同一个键带有多个值的情况

  • 方法get():根据键值

如果一个键同时拥有多个值将最后一个值

如果键不存在则返回None值,可以设置默认值进行后续处理

get('键',默认值)


  • 方法getlist():根据键值,值以列表返回,可以指定键的所有值

如果键不存在则返回空列表[],可以设置默认值进行后续处理

getlist('键',默认值)




3. 查询字符串Query String


请求路径中的查询字符串参数(形如?k1=v1&k2=v2),可以通过request.GET属性,返回QueryDict对象。

  
  
# /get/?a=1&b=2&a=3
  
  
​
def get(request):
    a = request.GET.get('a')
    b = request.GET.get('b')
    alist = request.GET.getlist('a')
    print(a)  # 3
    print(b)  # 2
    print(alist)  # ['1', '3']
    return HttpResponse('OK')


重要:查询字符串不区分请求方式,即假使客户端进行POST方式的请求,依然可以通过request.GET请求中的查询字符串数据。


4 请求体


请求体数据格式不固定,可以是表单类型字符串,可以是JSON字符串,可以是XML字符串,应区别对待。

可以发送请求体数据的请求方式有POSTPUTPATCHDELETE

Django默认开启了CSRF防护,会对上述请求方式进行CSRF防护验证,在测试时可以关闭CSRF防护机制,方法为在settings.py文件中注释掉CSRF中间件,如:


4.1 表单类型 Form Data


前端发送的表单类型的请求体数据,可以通过request.POST属性,返回QueryDict对象。

def post(request):
    a = request.POST.get('a')
    b = request.POST.get('b')
    alist = request.POST.getlist('a')
    print(a)
    print(b)
    print(alist)
    return HttpResponse('OK')



4.2 非表单类型 Non-Form Data


非表单类型的请求体数据,Django无法自动解析,可以通过request.body属性最原始的请求体数据,自己按照请求体格式(JSON、XML等)进行解析。request.body返回bytes类型。

例如要请求体中的如下JSON数据

{"a": 1, "b": 2}


可以进行如下方法操作:

import json
​
def post_json(request):
    json_str = request.body
    json_str = json_str.decode()  # python3.6 无需执行此步
    req_data = json.loads(json_str)
    print(req_data['a'])
    print(req_data['b'])
    return HttpResponse('OK')



5 请求头


可以通过request.META属性请求头headers中的数据,request.META为字典类型

常见的请求头如:

  • CONTENT_LENGTH– The length of the request body (as a string).

  • CONTENT_TYPE– The MIME type of the request body.

  • HTTP_ACCEPT– Acceptable content types for the response.

  • HTTP_ACCEPT_ENCODING– Acceptable encodings for the response.

  • HTTP_ACCEPT_LANGUAGE– Acceptable languages for the response.

  • HTTP_HOST– The HTTP Host header sent by the client.

  • HTTP_REFERER– The referring page, if any.

  • HTTP_USER_AGENT– The client’s user-agent string.

  • QUERY_STRING– The query string, as a single (unparsed) string.

  • REMOTE_ADDR– The IP address of the client.

  • REMOTE_HOST– The hostname of the client.

  • REMOTE_USER– The user authenticated by the Web server, if any.

  • REQUEST_METHOD– A string such as"GET"or"POST".

  • SERVER_NAME– The hostname of the server.

  • SERVER_PORT– The port of the server (as a string).

具体使用如:

def get_headers(request):
    print(request.META['CONTENT_TYPE'])
    return HttpResponse('OK')



6 其他常用HttpRequest对象属性


  • method:一个字符串,表示请求使用的HTTP方法,常用值包括:'GET'、'POST'。

  • user:请求的用户对象。

  • path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。

  • encoding:一个字符串,表示提交的数据的编码方式。

    • 如果为None则表示使用浏览器的默认设置,一般为utf-8。

    • 这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。

  • FILES:一个类似于字典的对象,包含所有的上传文件。



HttpResponse对象


视图在接收请求并处理后,必须返回HttpResponse对象或子对象。HttpRequest对象由Django创建,HttpResponse对象由开发人员创建。


1 HttpResponse


可以使用django.http.HttpResponse来构造响应对象。

HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码)


也可通过HttpResponse对象属性来设置响应体、响应体数据类型、状态码:

  • content:表示返回的内容。

  • status_code:返回的HTTP响应状态码。

响应头可以直接将HttpResponse对象当做字典进行响应头键值对的设置:

response = HttpResponse()
response['itcast'] = 'Python'  # 自定义响应头Itcast, 值为Python


示例:

from django.http import HttpResponse
​
def response(request):
    return HttpResponse('itcast python', status=400)
    或者
    response = HttpResponse('itcast python')
    response.status_code = 400
    response['itcast'] = 'Python'
    return response



2 HttpResponse子类


Django提供了一系列HttpResponse的子类,可以快速设置状态码

  • HttpResponseRedirect 301

  • HttpResponsePermanentRedirect 302

  • HttpResponseNotModified 304

  • HttpResponseBadRequest 400

  • HttpResponseNotFound 404

  • HttpResponseForbidden 403

  • HttpResponseNotAllowed 405

  • HttpResponseGone 410

  • HttpResponseServerError 500


3 JsonResponse


若要返回json数据,可以使用JsonResponse来构造响应对象,作用:

  • 帮助我们将数据转换为json字符串

  • 设置响应头Content-Typeapplication/json

from django.http import JsonResponse
​
def response(request):
    return JsonResponse({'city': 'beijing', 'subject': 'python'})



4 redirect重定向


from django.shortcuts import redirect
​
def response(request):
    return redirect('/get_header')



状态保持


  • 浏览器请求服务器是无状态的。

  • 无状态:指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。

  • 无状态原因:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。

  • 有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等

  • 实现状态保持主要有两种方式:

    • 在客户端存储信息使用Cookie

    • 在服务器端存储信息使用Session



Cookie


Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份、进行session跟踪而储存在用户本地终端上的数据(通常经过加密)。Cookie最早是网景公司的前雇员Lou Montulli在1993年3月的发明。Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie名称和值可以由服务器端开发自己定义,这样服务器可以知道该用户是否是合法用户以及是否需要重新登录等。服务器可以利用Cookies包含信息的任意性来筛选并经常性维护这些信息,以判断在HTTP传输中的状态。Cookies最典型记住用户名。

Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用。


Cookie的特点


  • Cookie以键值对的格式进行信息的存储。

  • Cookie基于域名安全,不同域名的Cookie是不能互相访问的,如访问itcast.cn时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到itcast.cn写的Cookie信息。

  • 当浏览器请求某网站时,会将浏览器存储的跟网站相关的所有Cookie信息提交给网站服务器。


1 设置Cookie


可以通过HttpResponse对象中的set_cookie方法来设置cookie。

HttpResponse.set_cookie(cookie名, value=cookie值, max_age=cookie有效期)


  • max_age单位为秒,默认为None 。如果是临时cookie,可将max_age设置为None。

示例:

def cookie(request):
    response = HttpResponse('ok')
    response.set_cookie('itcast1', 'python1')  # 临时cookie
    response.set_cookie('itcast2', 'python2', max_age=3600)  # 有效期一小时
    return response



2 读取Cookie


可以通过HttpResponse对象的COOKIES属性来读取本次请求携带的cookie值。request.COOKIES为字典类型

def cookie(request):
    cookie1 = request.COOKIES.get('itcast1')
    print(cookie1)
    return HttpResponse('OK')



3 删除Cookie


可以通过HttpResponse对象中的delete_cookie方法来删除。

response.delete_cookie('itcast2')


状态保持


  • 浏览器请求服务器是无状态的。

  • 无状态:指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。

  • 无状态原因:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。

  • 有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等

  • 实现状态保持主要有两种方式:

    • 在客户端存储信息使用Cookie

    • 在服务器端存储信息使用Session



Session




1 启用Session


Django项目默认启用Session。

可以在settings.py文件中查看,如图所示

如需禁用session,将上图中的session中间件注释掉即可。


2 存储方式


在settings.py文件中,可以设置session数据的存储方式,可以保存在数据库、本地缓存等。


2.1 数据库


存储在数据库中,如下设置可以写,也可以不写,这是默认存储方式

SESSION_ENGINE='django.contrib.sessions.backends.db'


如果存储在数据库中,需要在项INSTALLED_APPS中安装Session应用。

数据库中的表如图所示

表结构如下

由表结构可知,操作Session包括三个数据:键,值,过期时间。


2.2 本地缓存


存储在本机内存中,如果丢失则不能找回,比数据库的方式读写更快。

SESSION_ENGINE='django.contrib.sessions.backends.cache'



2.3 混合存储


优先从本机内存中存取,如果没有则从数据库中存取。

SESSION_ENGINE='django.contrib.sessions.backends.cached_db'



2.4 Redis


在redis中保存session,需要引入第三方扩展,我们可以使用django-redis来解决。

网络连接

1) 安装扩展

pip install django-redis


2)配置

在settings.py文件中做如下设置

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
        }
    }
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'



注意


如果redis的ip地址不是本地回环127.0.0.1,而是其他地址,访问Django时,可能出现Redis连接错误,如下:

解决方法:

修改redis的配置文件,添加特定ip地址。

打开redis的配置文件

sudo vim /etc/redis/redis.conf


在如下配置项进行修改(如要添加10.211.55.5地址)

重新启动redis服务

sudo service redis-server restart



3 Session操作


通过HttpRequest对象的session属性进行会话的读写操作。

1) 以键值对的格式写session。

request.session['键']=值


2)根据键读取值。

request.session.get('键',默认值)


3)清除所有session,在存储中删除值部分。

request.session.clear()


4)清除session数据,在存储中删除session的整条数据。

request.session.flush()


5)删除session中的指定键及值,在存储中只删除某个键及对应的值。

del request.session['键']


6)设置session的有效期

request.session.set_expiry(value)


  • 如果value是一个整数,session将在value秒没有活动后过期。

  • 如果value为0,那么用户session的Cookie将在用户的浏览器关闭时过期。

  • 如果value为None,那么session有效期将采用系统默认值, 默认为两周,可以通过在settings.py中设置SESSION_COOKIE_AGE来设置全局默认值。


类视图与中间件




类视图


思考:一个视图,是否可以处理两种逻辑?比如get和post请求逻辑。


如何在一个视图中处理get和post请求



注册视图处理get和post请求


以函数的方式定义的视图称为函数视图,函数视图便于理解。但是遇到一个视图对应的路径提供了多种不同HTTP请求方式的支持时,便需要在一个函数中编写不同的业务逻辑,代码可读性与复用性都不佳。

def register(request):
    """处理注册"""
​
    # 请求方法,判断是GET/POST请求
    if request.method == 'GET':
        # 处理GET请求,返回注册页面
        return render(request, 'register.html')
    else:
        # 处理POST请求,实现注册逻辑
        return HttpResponse('这里实现注册逻辑')



类视图使用


在Django中也可以使用类来定义一个视图,称为类视图

使用类视图可以将视图对应的不同请求方式以类中的不同方法来区别定义。如下所示

from django.views.generic import View
​
class RegisterView(View):
    """类视图:处理注册"""
​
    def get(self, request):
        """处理GET请求,返回注册页面"""
        return render(request, 'register.html')
​
    def post(self, request):
        """处理POST请求,实现注册逻辑"""
        return HttpResponse('这里实现注册逻辑')


类视图的好处:

  • 代码可读性好

  • 类视图相对于函数视图有更高的复用性 , 如果其他地方需要用到某个类视图的某个特定逻辑,直接继承该类视图即可

定义类视图需要继承自Django提供的父类View,可使用from django.views.generic import View或者from django.views.generic.base import View导入,定义方式如上所示。

配置路由时,使用类视图的as_view()方法来添加

urlpatterns = [
    # 视图函数:注册
    # url(r'^register/$', views.register, name='register'),
    # 类视图:注册
    url(r'^register/$', views.RegisterView.as_view(), name='register'),
]



类视图原理


@classonlymethod
    def as_view(cls, **initkwargs):
        """
        Main entry point for a request-response process.
        """
        ...省略代码...
​
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.request = request
            self.args = args
            self.kwargs = kwargs
            # 调用dispatch方法,按照不同请求方式调用不同请求方法
            return self.dispatch(request, *args, **kwargs)
​
        ...省略代码...
​
        # 返回真正的函数视图
        return view
​
​
    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)



类视图的多继承重写dispatch


class CenterView(View):
​
    def get(self,request):
        return HttpResponse("OK")
​
    def post(self,request):
        return HttpResponse("OK")


使用面向对象多继承的特性。

class CenterView(LoginRequireMixin,View):
​
    def get(self,request):
        return HttpResponse("OK")
​
    def post(self,request):
        return HttpResponse("OK")



中间件


Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的请求和响应处理过程,修改Django的输入或输出。中间件的设计为开发者提供了一种无侵入式的开发方式,增强了Django框架的健壮性。

我们可以使用中间件,在Django处理视图的不同阶段对输入或输出进行干预。

中间件文档


1 中间件的定义方法


定义一个中间件工厂函数,然后返回一个可以被调用的中间件。

中间件工厂函数需要接收一个可以调用的get_response对象。

返回的中间件也是一个可以被调用的对象,并且像视图一样需要接收一个request对象参数,返回一个response对象。

def simple_middleware(get_response):
    # 此处编写的代码仅在Django第一次配置和初始化的时候执行一次。
​
    def middleware(request):
        # 此处编写的代码会在每个请求处理视图前被调用。
​
        response = get_response(request)
​
        # 此处编写的代码会在每个请求处理视图之后被调用。
​
        return response
​
    return middleware


例如,在book应用中新建一个middleware.py文件,

def my_middleware(get_response):
    print('init 被调用')
    def middleware(request):
        print('before request 被调用')
        response = get_response(request)
        print('after response 被调用')
        return response
    return middleware


定义好中间件后,需要在settings.py 文件中添加注册中间件

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'book.middleware.my_middleware',  # 添加中间件
]


定义一个视图进行测试

def middleware(request):
    print('view 视图被调用')
    return HttpResponse('OK')


执行结果

注意:Django运行在调试模式下,中间件init部分有可能被调用两次。


2 多个中间件的执行顺序


  • 在请求视图被处理,中间件由上至下依次执行

  • 在请求视图被处理,中间件由下至上依次执行

示例:

定义两个中间件

def my_middleware(get_response):
    print('init 被调用')
    def middleware(request):
        print('before request 被调用')
        response = get_response(request)
        print('after response 被调用')
        return response
    return middleware
​
def my_middleware2(get_response):
    print('init2 被调用')
    def middleware(request):
        print('before request 2 被调用')
        response = get_response(request)
        print('after response 2 被调用')
        return response
    return middleware


注册添加两个中间件

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'users.middleware.my_middleware',  # 添加
    'users.middleware.my_middleware2',  # 添加
]


执行结果

init2 被调用
init 被调用
before request 被调用
before request 2 被调用
view 视图被调用
after response 2 被调用
after response 被调用



模板




重点


  • 自带模板

    • 基本使用

    • 流程控制

    • 过滤器

    • 继承

  • Jinja2模板

    • 配置

  • CSRF

    • 原理

    • 如何防范



Django使用自带模板




1 配置


在工程中创建模板目录templates。

在settings.py配置文件中修改TEMPLATES配置项的DIRS值:

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',
            ],
        },
    },
]



2 定义模板


在templates目录中新建一个模板文件,如index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ city }}
</body>
</html>



3 模板渲染


调用模板分为两步骤:

  1. 找到模板 loader.get_template(模板文件在模板目录中的相对路径) -> 返回模板对象

  2. 渲染模板 模板对象.render(context=None, request=None) -> 返回渲染后的html文本字符串 context 为模板变量字典,默认值为None request 为请求对象,默认值为None

例如,定义一个视图

from django.http import HttpResponse
from django.template import loader
​
def index(request):
    # 1.模板
    template=loader.get_template('index.html')
​
    context={'city': '北京'}
    # 2.渲染模板
    return HttpResponse(template.render(context))


Django提供了一个函数render可以简写上述代码。

render(request对象, 模板文件路径, 模板数据字典)

from django.shortcuts import render
​
def index(request):
    context={'city': '北京'}
    return render(request,'index.html',context)



4 模板语法




4.1 模板变量


变量名必须由字母、数字、下划线(不能以下划线开头)和点组成。

语法如下:

模板变量可以使python的内建类型,也可以是对象。

def index(request):
    context = {
        'city': '北京',
        'adict': {
            'name': '西游记',
            'author': '吴承恩'
        },
        'alist': [1, 2, 3, 4, 5]
    }
    return render(request, 'index.html', context)



4.2 模板语句


1)for循环:

2)if条件:

比较运算符如下:

==
!=
<
>
<=
>=


布尔运算符如下:

and
or
not


注意:运算符左右两侧不能紧挨变量或常量,必须有空格。


4.3 注释


1)单行注释语法如下:

2)多行注释使用comment标签,语法如下:


###




过滤器


语法如下:

  • 使用管道符号|来应用过滤器,用于进行计算、转换操作,可以使用在变量、标签中。

  • 如果过滤器需要参数,则使用冒号:传递参数。

  • 变量|过滤器:参数
​
​
​
列举几个如下:
​
* **safe**,禁用转义,告诉模板这个变量是安全的,可以解释执行
​
* **length**,长度,返回字符串包含字符的个数,或列表、元组、字典的元素个数。
​
* **default**,默认值,如果变量不存在时则返回默认值。
​
* ```python
data|default:'默认值'


  • date,日期,用于对日期类型的值进行字符串格式化,常用的格式化字符如下:

    • Y表示年,格式为4位,y表示两位的年。

    • m表示月,格式为01,02,12等。

    • d表示日, 格式为01,02等。

    • j表示日,格式为1,2等。

    • H表示时,24进制,h表示12进制的时。

    • i表示分,为0-59。

    • s表示秒,为0-59。

    • value|date:"Y年m月j日  H时i分s秒"




未完待续 下一期下一章


全套笔记直接地址: 请移步这里

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。