九个视图子类

# 两个视图基类
1.APIView 2.GenericAPIView
APIView: renderer_classes响应格式类 parser_classes请求解析类 跟数据库解耦合
GenericAPIView:queryset数据集 serializer_class序列化类 跟数据库耦合 # 5个视图扩展类 (提供方法)
ListModelMixin --> list --> 查询所有
RetrieveModelMixin --> retrieve --> 查询一个
CreateModelMixin --> create --> 新增一个
UpdateModelMixin --> update --> 修改一个
DestroyModelMixin --> destroy --> 删除一个 # 9个视图子类
继承关系公式: 视图子类 = n * 视图扩展类 + GenericAPIView # 示例:
ListAPIView = ListModelMixin + GenericAPIView
RetrieveAPIView = RetrieveModelMixin + GenericAPIView
CreateAPIView = CreateModelMixin + GenericAPIView
...
RetrieveDestroyAPIView = RetrieveModelMixin + DestroyModelMixin + GenericAPIView
RetrieveUpdateDestroyAPIView = RetrieveModelMixin + UpdateModelMixin + DestroyModelMixin + GenericAPIView '''
总结:9个视图子类都继承GenericAPIView
'''

使用视图子类写五个接口:这里上一节讲过,所以不再赘述。

## 路由
urlpatterns = [
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookView.as_view()),
] # 视图类
class BookView(ListCreateAPIView): # 查询所有,新增一个
queryset = Book.objects.all()
serializer_class = BookSerializer class BookDetailView(RetrieveUpdateDestroyAPIView): # 新增一个,修改一个,删除一个
queryset = Book.objects.all()
serializer_class = BookSerializer

以后可能只希望写某几个接口,而不是全部接口都存在,

可以通过继承不同的视图类实现。

只要查询所有和删除一个,怎么写?

为什么没有Destroy和Updata的组合?

因为必须先查出来,再修改或删除,所以没有这个组合。

继续封装:两个视图类 ---> 一个视图类

问题:

1.有两个get请求对应一个CBV

2.两个路由路径对应一个CBV

视图集

继承ModelViewSet类写五个接口

# 路由
urlpatterns = [
path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'})),
path('books/<int:pk>/', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
] # 视图类
class BookView(ModelViewSet): # 查询所有,新增一个
queryset = Book.objects.all()
serializer_class = BookSerializer

查看ModelViewSet内部继承关系:

从注释也可以看出来他继承了 5个视图扩展类,也就是说ModelViewSet内部具备所有的"动作",也就是例如:

create()list()update()retrieve()destroy()这些方法

但是我们请求来了,还是会调用视图类中的get()post()put()delete()这些方法呀。

比如一个扩展子类:ListAPIView

他的内部就是写了get方法,我们get请求来了之后,就会调用这个方法,然后再去调用父类的list方法。

ModelViewSet内部居然没有写,这是怎么回事?

这是因为ModelViewSet继承的最后一个类GenericViewSet,这是一个魔法类,他重写了as_view。

我们直接发个请求运行一下。

会发现如下报错:

可以得知,一旦继承ModelViewSet,路由层的写法就变了!

现在需要这样写:

这样写的意思是:

  • 对于books/这个路由:

    get请求 --执行--> list方法

    post请求 --执行--> create方法

  • 对于books/<int:pk>/这个路由:

    get请求 --执行--> retrieve方法

    put请求 --执行--> updata方法

    delete请求 --执行--> destroy方法

先记住这个格式,知道怎么用,后续源码分析再详细了解。

继承 ReadOnlyModelView编写2个只读接口

# 路由
urlpatterns = [
path('books/', views.BookView.as_view({'get': 'list'})),
path('books/<int:pk>/', views.BookView.as_view({'get': 'retrieve'})),
] # 视图类
class BookView(ReadOnlyModelViewSet): # 查询所有,新增一个
queryset = Book.objects.all()
serializer_class = BookSerializer

查看 readonlymodelview内部继承关系:

这个类中只有list方法和retrieve方法。他同样继承了魔法类。

所以继承这个类就只能写两个只读接口:查询所有、查询一个

ViewSetMixin源码分析

查看GenericViewSet继承关系:

ViewSetMixin是个魔法类,重写了as_view:

查找as_view方法

路由写法为什么变了?

导致路由写法变了的原因是: ViewSetMixin

当请求来了之后,会执行ViewSetMixin类中的as_view方法的返回值。

# 请求来了,路由匹配成功---》get请求,匹配成功books,会执行  views.BookView.as_view({'get': 'list', 'post': 'create'})()------>读as_view【这个as_view是ViewSetMixin的as_view】

从路由层开始分析,根据继承属性一个一个找as_view方法(从左往右)

ListModelMixinRetrieveModelMixinCreateModelMixinUpdateModelMixin DestroyModelMixin这些方法中都没有as_view。

所以会进入到GenericViewSet:

GenericViewSet的第一个父类是ViewSetMixin。

所以会先执行ViewSetMixin的as_view():

@classonlymethod
def as_view(cls, actions=None, **initkwargs):
# 如果没有传actions,直接抛异常,路由写法变了后,as_view中不传字典,直接报错
if not actions:
raise TypeError("The `actions` argument must be provided when "
"calling `.as_view()` on a ViewSet. For example "
"`.as_view({'get': 'list'})`")
# 。。。。其他代码不用看
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if 'get' in actions and 'head' not in actions:
actions['head'] = actions['get']
self.action_map = actions
for method, action in actions.items():
handler = getattr(self, action)
setattr(self, method, handler) return self.dispatch(request, *args, **kwargs)
# 去除了csrf校验
return csrf_exempt(view)

如果不给actions传参数,直接抛出异常。

也就是不给as_view()传字典,就会抛出异常。

as_view执行完后会返回内层函数view:(这里执行的view是去除了csrf校验的)

# 路由匹配成功执行views.BookView.as_view({'get': 'list', 'post': 'create'})()----》本质执
行ViewSetMixin----》as_view----》内的view()---》代码贴过来
def view(request, *args, **kwargs):
#actions 是传入的字典--->{'get': 'list', 'post': 'create'}
self.action_map = actions
# 第一次循环:method:get,action:list
# 第一次循环:method:post,action:create
for method, action in actions.items():
# 反射:去视图类中反射,action对应的方法,action第一次是list,去视图类中反射list方法
# handler就是视图类中的list方法
handler = getattr(self, action)
# 反射修改:把method:get请求方法,handler:list
# 视图类的对象的get方法,变成了list
setattr(self, method, handler) return self.dispatch(request, *args, **kwargs) #dispatch是APIView的 # 关于这里self.dipatch的说明
self.dipatch是APIView的dispatch
'''
self.dipatch --进行--> 封装新request, 执行三大认证 --调用--> django view的dispatch
'''
# 关于反射的总结
反射得到的是我们继承的List create方法
反射修改对象的属性 比如将get方法修改为存放list方法
最后的dispatch作用是获取你写的CBV类中的get方法(此时get方法 --> list方法)。
魔法类可以修改对象中的属性所指向的方法。 # 关于整体的总结:
-1 只要继承ViewSetMixin的视图类,路由写法就变了(重写了as_veiw)
-2 变成需要需要传入字典映射方法:{'get': 'list', 'post': 'create'}
-只要传入actions,以后访问get就是访问list,访问post,就是访问create
-3 其他执行跟之前一样
-4 以后视图类类中的方法名,可以任意命名,只要在路由中做好映射即可【重要】

setattr修改对象的属性

实际上ModelViewSet中根本没有get方法,我们通过setattr给CBV的对象新增了一个get属性,里面存放的就是list方法。

而这个list方法又是通过反射在CBV的父类获取到的。所以就产生了这么神奇的效果。

我们也可以在自己的CBV中重写list方法,这样getattr获取到的就是我们重写的list方法,然后get请求来了之后,也会执行我们重写的这个list。重写list之后,建议使用super方法调用一下父类的list,这样就可以在父类list的基础上,新增一些功能。

# 示例:
def token_auth(func):
def inner(self, request, *args, **kwargs):
token = request.query_params.get('token')
token_exist = UserToken.objects.filter(token=token)
if token_exist:
res = func(self, request, *args, **kwargs)
return res
else:
return Response({'code': 100, 'msg': '请先登录'}) return inner class BookView(ModelViewSet): # 针对 获取一个 修改一个 删除一个 接口添加token验证
queryset = Book.objects
serializer_class = BookSerializer @token_auth
def retrieve(self, request, *args, **kwargs):
res = super().retrieve(request, *args, **kwargs)
return res @token_auth
def update(self, request, *args, **kwargs):
res = super().update(request, *args, **kwargs)
return res @token_auth
def destroy(self, request, *args, **kwargs):
res = super().update(request, *args, **kwargs)
return res

from rest_framework.viewsets包下的类


# from rest_framework.viewsets下有这几个类: ViewSetMixin:魔法类,重写了as_view,只要继承他,以后路由写法变成了映射方法
ModelViewSet: 5个视图扩展类 + ViewSetMixin(魔法类) + GenericAPIView
ReadOnlyModelViewSet: 2个视图扩展类 + ViewSetMixin(魔法类) + GenericAPIView 只读的两个
ViewSet:ViewSetMixin(魔法类) + APIView
GenericViewSet:ViewSetMixin(魔法类) + GenericAPIView # 重点
以后,你想继承APIView,但是想变路由写法【视图类中方法名任意命名】,要继承ViewSet
以后,你想继承GenericAPIView,但是想变路由写法【视图类中方法名任意命名】,要继承GenericViewSet # 总结
只要想变路由,就要继承ViewSetMixin,但是ViewSetMixin不是CBV视图类,他没有list,create等方法,所以要配合APIView, GenericAPIView一起使用,所以会出现ViewSet,GenerucViewSet,帮助我们继承好了。
ViewSet: ViewSetMixin(魔法类) + APIView
GenericViewSet:ViewSetMixin(魔法类) + GenericAPIView

视图层大总结

# 1. 两个视图基类
-APIView,GenericAPIView
# 2. 5个视图扩展类,不是视图类,必须配合GenericAPIView # 3. 9个视图子类,是视图类,只需要继承其中某一个即可 # 4. 视图集
-ModelViewSet:路由写法变了,只需要写两行,5个接口都有了
-ReadOnlyModelViewSet:路由写法变了,只需要写两行,2个只读接口都有了
-ViewSetMixin:不是视图类,魔法,重写了as_view,路由写法变了,变成映射了
views.BookView.as_view({'get': 'list', 'post': 'create'})
-ViewSet:ViewSetMixin+ APIView
-GenericViewSet:ViewSetMixin+ GenericAPIView # 举例子:发送短信接口,视图类叫SendView,方法叫send_sms,路由配置变了
get--->send_sms
class SendView(ViewSet):
def send_sms(self,request):

任意命名视图类的方法

在视图类写的方法可以任意命名,只要在路由层的字典写好映射关系就行。

只要想变路由,就要继承ViewSetMixin,但是ViewSetMixin不是CBV视图类,他没有list,create等方法,所以要配合APIView,GenericAPIView一起使用,所以会出现ViewSet,GenerucViewSet,帮助我们继承好了。

如何选择视图类

  • 为什么要使用APIview?

    对于发送短信的接口,

    其不跟数据库打交道:继承ViewSet

    ViewSet = 魔法类 + APIView

    因为APIView不需要配置queryset和序列化类

    继承GenericViewSet会查数据库,这是一种资源的浪费。

    所以跟数据库打交道:继承GenericViewSet

    GenericViewSet = 魔法类 + GenericAPIview

  • 有没有推荐的视图类组合?

    9个视图子类 + 魔法类

    因为通常我们对一个数据库资源比如:user

    对于这些数据资源,我们不一定会提供全部接口,很可能只会写其中的几个接口。

路由系统

路由写法的三种情况

# drf 由于继承ViewSetMinxin类,路由写法变了
-原生+drf,以后的路由写法,可能会有如下情况(三种情况)
-path('books/', views.BookView.as_view()
# 原生django写法
-path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'}))
# 魔法类路由写法
-自动生成 ---> 还有扩展

路由类的使用

使用路由类是为了自动生成路由。

# drf提供了两个路由类,继承ModelViewSet后,路由可以自动生成

# 使用步骤:
# 第一步:导入路由类
# 第二步,实例化得到对象(两个类,一般使用SimpleRouter)
# 第三步:注册:router.register('books', views.BookView, 'books')
# 第四步:在urlpatterns中注册,两种方式
-urlpatterns += router.urls
-include:path('/api/v1/', include(router.urls)) 方式多一些 # 底层实现:自动生成路由就
-本质是自动做映射,能够自动成的前提是,视图类中要有 5个方法的某要给或多个
get--->list
get---->retrieve
put---->update
post---->create
delete---->destory
-ModelViewSet,ReadOnlyModelViewSet可以自动生成 -9个试图子类+配合ViewSetMixin 才可以自动生成
-GenericAPIView+5个试图扩展类+配合ViewSetMixin 才能自动生成

使用步骤

第一步:导入路由类 使用simplerouter 就生成两个路由 使用DefaultRouter -->生成的路由更多

第二步:实例化得到对象。

第三步:注册路由。路径和视图类建立关系 有几个视图类就要写几次

第四步:在urlpatterns注册

也就是将生成好的路由,添加到urlpatterns列表。

使用SimpleRouter(常用)

from rest_framework.routers import SimpleRouter

router =  SimpleRouter()
router.register('books', views.BookView, 'books') urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += router.urls

关于router.register:

第一个参数:具体路由地址 (会自动帮我们加斜杠,这里不需要跟以前一样添加)

第二个参数:该路由地址对应的视图类

第三个参数:相当于是一个路由别名

来自官方文档:

register() 方法有两个强制参数:

  • prefix - 用于此组路由的URL前缀。
  • viewset` - 处理请求的viewset类。

还可以指定一个附加参数(可选):

  • base_name - 用于创建的URL名称的基本名称。如果不设置该参数,将根据视图集的queryset属性(如果有)来自动生成基本名称。
  • 注意,如果视图集不包括queryset属性,那么在注册视图集时必须设置base_name

SimpleRouter会生成两个接口:

可以发现一个是 books/另一个是books/pk/

使用DefaultRouter

DefaultRouter比SimpleRouter多写了一些接口:

还包括一个默认返回所有列表视图的超链接的API根视图。

访问根,可以看到有哪些地址:

注册路由的两种方式

直接添加到urlpatterns列表

from rest_framework.routers import SimpleRouter, DefaultRouter

router = DefaultRouter()
router.register('books', views.BookView, 'books')
# router.register('api/v1/books', views.BookView, 'books') urlpatterns = [
path('admin/', admin.site.urls),
] urlpatterns += router.urls # 在这里添加 # router.urls也是一个列表:
[<URLPattern '^books/$' [name='books-list']>, <URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']>]

使用路由分发include

from rest_framework.routers import SimpleRouter

router = SimpleRouter()
router.register('books', views.BookView, 'books') urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls))
]

自动生成路由底层实现

# 自动生成路由底层实现
-本质是自动做映射,能够自动生成的前提是,视图类中要有 5个方法的某个或多个
get--->list
get---->retrieve
put---->update
post---->create
delete---->destory - ModelViewSet,ReadOnlyModelViewSet 可以自动生成
- 9个试图子类 + 配合ViewSetMixin 可以自动生成
- GenericAPIView + 5个试图扩展类+配合ViewSetMixin 可以自动生成

什么时候可以自动生成路由?

前提: 有list,create...等方法 有ViewSetMixin魔法类

自动生成路由使用的多,ModelViewSet用的不多,因为我们通常使用一个或者两个接口 。

所以如下这个组合用的多:

9个试图子类 + 配合ViewSetMixin

9个视图子类提供listcreate...方法 ViewSetMixin反射进行对象属性替换,使得get对应list 。

action装饰器

使用装饰器会将被装饰的方法的名字添加在原路由的后面,生成一个新路由:

原路由:send/

装饰器新增的路由:send/方法名/

# action 写在视图类的方法上,可以自动生成路由

# 使用步骤
- 1 写在视图类方法上
class SendView(ViewSet):
# methods指定请求方法,可以传多个
# detail:只能传True和False
-False,不带id的路径:send/send_sms/
-True,带id的路径:send/2/send_sms/
# url_path:生成send后路径的名字,默认以方法名命名
# url_name:别名,反向解析使用,了解即可
@action(methods=['POST'], detail=False)
def send_sms(self, request): # 以后看到的drf路由写法
后期,都是自动生成,一般不在urlpatterns 加入路由了 # 补充:
-1 不同请求方式可以使用不同序列化类
-2 不同action使用不同序列化类
class SendView(GenericViewSet):
queryset = None
serializer_class = '序列化类' def get_serializer(self, *args, **kwargs):
if self.action=='lqz':
return '某个序列化类'
else:
return '另一个序列化列'
@action(methods=['GET'], detail=True)
def send_sms(self, request,pk):
print(pk)
# 手机号,从哪去,假设get请求,携带了参数
phone = request.query_params.get('phone')
print('发送成功,%s' % phone)
return Response({'code': 100, 'msg': '发送成功'}) @action(methods=['GET'], detail=True)
def lqz(self,request): # get
# 序列化类
pass @action(methods=['GET'], detail=True)
def login(self,request): # get
# 序列化类
pass

无法自动生成的路由

我们知道路由自动生成,是实现了请求(get)和类中方法(list)的对应。

如果我们在类中写listcreate,... ,updata之外的方法呢?

还能自动生成这些方法的路由吗?

示例:

get携带参数,参数是手机号

路由怎么写?

如果这样写,那就相当于get请求映射send_sms方法而不是list方法。

自动生成路由,只能映射到list,create...,但是我们需要执行send_sms,并且区分开原来的list方法,所以需要加drf提供的装饰器:

加上这个装饰之后,会新增一个路由send/send_sms/

这样就可以对这个新增的路由发送请求了。

不同action使用不同序列化类

class SendView(GenericViewSet):
queryset = None
serializer_class = '序列化类' def get_serializer(self, *args, **kwargs):
if self.action=='lqz':
return '某个序列化类'
else:
return '另一个序列化列'
@action(methods=['GET'], detail=True)
def send_sms(self, request,pk):
print(pk)
# 手机号,从哪去,假设get请求,携带了参数
phone = request.query_params.get('phone')
print('发送成功,%s' % phone)
return Response({'code': 100, 'msg': '发送成功'}) @action(methods=['GET'], detail=True)
def lqz(self,request): # get
# 序列化类
pass @action(methods=['GET'], detail=True)
def login(self,request): # get
# 序列化类
pass

如何实现不同的方法,使用不同的序列化类?

用action产生的路径来判断不同的get请求。

我怎么知道self里面有个action,在什么时候放进去的?

在ViewSetMixin:

自动生成路由时才会有action属性.

action_map是as_view传入的字典。

查看self.action:

认证组件前戏

登录接口

# 访问某个接口,需要登陆后才能访问

# 第一步:写个登录功能,用户表
-User表
-UserToken表:存储用户登录状态 [这个表可以没有,如果没有,把字段直接写在User表上也可以]

随机字符串可以放在user表,也可以放在usertoken表里。

建表:

用户删掉掉了之后,用户token没有存在的必要。所以可以使用级联删除。

虽然UserToken中没有外键,但是UserToken还是可以进行反向查询,其生成的对象中有一个user属性。(反向查询表名小写)

登录接口:

登录接口是不需要使用序列化类的。

使用uuid模块生成随机字符串。

关于传给前端的随机字符串,最好不要用时间戳。

时间戳怎么重复?不同机器可能出现同一时间戳,及不同机器同一时间登录。

updata_or_create方法:

根据user去查,如果能查到,就把default里面的token给放进去。也就是如果有token就更新,如果没有就创建。

登录接口:

#### 表模型

class User(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32) class UserToken(models.Model): # 跟User是一对一
token = models.CharField(max_length=32)
user = models.OneToOneField(to='User', on_delete=models.CASCADE, null=True)
# user :反向,表名小写,所有有user字段 ### 路由
router.register('user', views.UserView, 'user') # /api/v1/user/login post 请求 # 视图类
#### 登录接口 自动生成路由+由于登录功能,不用序列化,继承ViewSet
from .models import User, UserToken
import uuid class UserView(ViewSet):
@action(methods=['POST'], detail=False)
def login(self, request):
username = request.data.get('username')
password = request.data.get('password')
user = User.objects.filter(username=username, password=password).first()
if user:
# 用户存在,登录成功
# 生成一个随机字符串--uuid
token = str(uuid.uuid4()) # 生成一个永不重复的随机字符串
# 在userToken表中存储一下:1 从来没有登录过,插入一条, 2 登录过,修改记录
# 如果有就修改,如果没有就新增 (if 自己写)
# kwargs 传入的东西查找,能找到,使用defaults的更新,否则新增一条
UserToken.objects.update_or_create(user=user, defaults={'token': token})
return Response({'code': '100', 'msg': '登录成功', 'token': token})
else:
return Response({'code': '101', 'msg': '用户名或密码错误'})

【Django drf】视图层大总结 ViewSetMixin源码分析 路由系统 action装饰器的更多相关文章

  1. springMVC源码分析--HandlerMethodReturnValueHandlerComposite返回值解析器集合(二)

    在上一篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)我们介绍了返回值解析器HandlerMethodReturnValueHand ...

  2. Spring AOP 源码分析 - 筛选合适的通知器

    1.简介 从本篇文章开始,我将会对 Spring AOP 部分的源码进行分析.本文是 Spring AOP 源码分析系列文章的第二篇,本文主要分析 Spring AOP 是如何为目标 bean 筛选出 ...

  3. Tomcat源码分析(类加载与类加载器)

    Tomcat的挑战 Tomcat上可以部署多个项目 Tomcat的一般部署,可以通过多种方式启动一个Tomcat部署多个项目,那么Tomcat在设计时会遇到什么挑战呢? Tomcat运行时需要加载哪些 ...

  4. drf框架,restful接口规范,源码分析

    复习 """ 1.vue如果控制html 在html中设置挂载点.导入vue.js环境.创建Vue对象与挂载点绑定 2.vue是渐进式js框架 3.vue指令 {{ }} ...

  5. Django框架(十八)—— CBV源码分析、restful规范、restframework框架

    目录 CBV源码分析.restful规范.restframework框架 一.CBV源码分析 1.url层的使用CBV 2.as_view方法 3.view方法 4.dispatch方法(可以在视图层 ...

  6. drf的基本使用、APIView源码分析和CBV源码拓展

    cbv源码拓展 扩展,如果我在Book视图类中重写dispatch方法 -可以实现,在get,post方法执行之前或者之后执行代码,完成类似装饰器的效果 def dispatch(self, requ ...

  7. Django 之 restframework 版本控制的使用以及源码分析

    Django rest_framework 之 版本控制 一.何为版本控制: ​ 用于版本的控制 二.内置的版本控制类: from rest_framework.versioning import Q ...

  8. SpringMVC视图机制详解[附带源码分析]

    目录 前言 重要接口和类介绍 源码分析 编码自定义的ViewResolver 总结 参考资料 前言 SpringMVC是目前主流的Web MVC框架之一. 如果有同学对它不熟悉,那么请参考它的入门bl ...

  9. 【lwip】07-链路层收发以太网数据帧源码分析

    目录 前言 7.1 链路层概述 7.2 MAC地址的基本概念 7.3 以太网帧结构 7.4 以太网帧结构 7.5 以太网帧报文数据结构 7.6 发送以太网数据帧 7.7 接收以太网数据帧 7.8 虚拟 ...

  10. 精尽Spring Boot源码分析 - 日志系统

    该系列文章是笔者在学习 Spring Boot 过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring Boot 源码分析 GitHub 地址 进行阅读 Sprin ...

随机推荐

  1. JS学习笔记 (四) 数组进阶

    1.基本知识 1.数组是值的有序集合.每个值叫做一个元素,而每个元素在数组中的位置称为索引,以数字表示,以0开始. 2.数组是无类型的.数组元素可以是任意类型,并且同一个数组中的不同元素也可能有不同的 ...

  2. 解决vue中对象属性改变视图不更新的问题

    在使用VUE的过程中,会遇到这样一种情况, vue data 中的数据更新后,视图没有自动更新. 这个情况一般分为两种, 一种是数组的值改变,在改变数组的值的是时候使用索引值去更改某一项,这样视图不会 ...

  3. Thinkphp6使用腾讯云发送短信步骤

    1.前提条件国内短信地址:https://console.cloud.tencent.com/smsv2 已开通短信服务,具体操作请参见 国内短信快速入门.如需发送国内短信,需要先 购买国内短信套餐包 ...

  4. 随笔——安卓手机调试微信网页,x5错误页

    如果打开debugx5.qq.com提示您使用的不是x5内核 那么先打开debugmm.qq.com/?forcex5=true 再打开http://debugtbs.qq.com 将进入下面这个页面 ...

  5. Karmada跨集群优雅故障迁移特性解析

    摘要:在 Karmada 最新版本 v1.3中,跨集群故障迁移特性支持优雅故障迁移,确保迁移过程足够平滑. 本文分享自华为云社区<Karmada跨集群优雅故障迁移特性解析>,作者:Karm ...

  6. Vue 双向绑定数据已经更新,但是视图更新:

    使用ElementUI做动态增减表单项的时候,发现数据刷新后视图未更新 Vue包装了数个数组操作函数,使用这些方法操作的数组去,其数据变动时会被vue监测: push() pop() shift() ...

  7. SSH(二)框架配置文件

    在引入了宽假所需要的jar包后,引入相应配置文件. 一.Struts2的配置文件: 1.Struts2的黑心过滤器,在web.xml中引入: <!-- struts2框架的核心过滤器  clas ...

  8. Day31面向对象之魔法方法

    Day31面向对象之魔法方法 类的常用魔法方法如下 序号 双下方法 触发条件 1 init 对象添加独有数据的时候自动触发 2 str 对象被执行打印操作的时候自动触发 3 call 对象加括号调用的 ...

  9. day34 JSTL标签

    JSTL标签 <!-- 写在jsp文件的最前 --> <!-- JSTL标签库是一个JSP标签的集合,封装了许多jsp应用程序通用的核心功能 prefix="c" ...

  10. Java反射与安全问题

    1.Java反射机制 Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的 ...