ModelViewSet额外路由参数
用了DefaultRouter,那么在URL匹配时带路径参数,只有update、delete、retrieve能带,关键是匹配pk还是写死的,我们需要对任意参数,同时还能修改方法命名。
咋搞?很简单。比如我们要在HahaViewSet里写一个xixi的GET haha/{name}/xixi/的接口。
第一步路由:
router = routers.DefaultRouter()
router.register(r'haha', haha.HahaViewSet, basename="haha")
urlpatterns = [
path('', include(router.urls)),
url(r'haha/(?P<name>\w+)/xixi/$', haha.HahaViewSet.as_view({'get': 'xixi'})),
...
]
第二步方法:
@swagger_auto_schema(...)
@action(detail=False, methods=["GET"], url_path="")
def xixi(self, request, *args, **kwargs): # 方法名字要与路由匹配的action字典匹配上
name = kwargs.get("name") # 没有带name,url的w+就不会匹配到,直接404
...
ADMIN事件触发
通常在使用Django框架后,定义models时,我们往往会把使用字段放在/admin可访问里,这样比直接去操作DB客户端简单些,而且在实际开发中并不是人人都有去权限去修改DB,就算有修改起来也比较麻烦。
举个使用例子吧,先定义一个model在models.py
class Haha(models.Model):
name = models.CharField(verbose_name="姓名", max_length=50, db_index=True)
class Meta:
verbose_name = "哈哈表"
verbose_name_plural = "哈哈表"
那么在admin.py文件就可以加上admin定义:
@admin.register(models.Haha)
class HahaAdmin(admin.ModelAdmin):
list_display = ["name"]
search_fields = ["name"]
这是个很基本的例子,但如果现在我们的项目用上了缓存呢。
那么在 /admin 增删改根本就不会影响到缓存,而往往我们逻辑上的诉求是在 /admin后台增删改时可以把对应的缓存删掉,待接口调数据调不到时去DB拿,再更新到缓存,admin删除缓存怎么办呢?
这就需要两个东西admin触发事件与model信号,解决admin增删改缓存不一致的问题。
需要重新两个方法(
save_model, delete_model
)和利用信号机制编写一个信号接收函数(自定义命名)。
from django.contrib import admin
from django_redis import get_redis_connection
from . import models
@admin.register(models.Haha)
class HahaAdmin(admin.ModelAdmin):
list_display = ["name"]
search_fields = ["name"]
def save_model(self, request, obj, form, change):
# 删除缓存
get_redis_connection().delete("%s_key" % obj.name)
# super().save_model(request, obj, form, change)源码也是这个
obj.save()
def delete_model(self, request, obj):
# 删除缓存
get_redis_connection().delete("%s_key" % obj.name)
# super().delete_model(request, obj)源码也是这个
obj.delete()
上面是完整的代码,写到这里有小伙伴就拿去测试了,发现为啥删除的时候,缓存去不掉。
这里就有一个特别大的操作误区了。如何才会触发这两个函数。
自行去测试会发现,只对这里的删除和保存才会触发save_model, delete_model。
保存还好,只有这一种保存方式,那么删除呢?
删除还有直接在页面选中删除的方式,这就触发不到delete_model。
这时候就需要信号接受函数,sender就为对应的model
from django.db.models.signals import post_delete
from django_redis import get_redis_connection
from django.dispatch import receiver
@receiver(post_delete, sender=Haha)
def delete_cache(sender, instance, **kwargs):
# 删除缓存
get_redis_connection().delete("%s_key" % name)
OK,到这里大功告成。