評論接口
添加評論
- 建立應用,在項目目錄下
python manage.py startapp comments
- 注冊應用 blogproj/setttings.py
INSTALLED_APPS = [
...
'comments.apps.CommentsConfig',
]
- 建立模型comments/models.py
from django.db import models
from django.utils import timezone
class Comment(models.Model):
name = models.CharField(verbose_name='名字', max_length=50)
email = models.EmailField(verbose_name='郵箱')
url = models.URLField(verbose_name='網址', blank=True)
text = models.TextField(verbose_name='内容')
create_time = models.DateTimeField(verbose_name='建立時間', default=timezone.now)
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, verbose_name='文章')
class Meta:
verbose_name='評論'
verbose_name_plural = verbose_name
ordering = ['-create_time'] #降序
- 資料庫遷移
python manage.py
python manage.py migrate
- 建立comments序列化器, comments/serializers.py
from rest_framework import serializers
from .models import Comment
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = [
'name'
,'email'
,'url'
,'text'
,'create_time'
,'post'
]
read_only_fields = ['create_time',]
extra_kwargs = {'post':{'write_only':True}}
- 評論視圖集 comments/views.py
from rest_framework import viewsets,mixins
from .models import Comment
from .serializers import CommentSerializer
class CommentViewSet(viewsets.GenericViewSet,mixins.CreateModelMixin):
#序列化器
serializer_class = CommentSerializer
queryset = Comment.objects.all()
- 注冊Comment視圖集,blogproj/urls.py
from comments.views import CommentViewSet
...
router.register(r'comments',CommentViewSet,basename='comment')
通路:http://127.0.0.1:8000/api/comments/
評論清單
- 修改blog/views.py
class PostViewSet(viewsets.GenericViewSet, mixins.ListModelMixin,
mixins.RetrieveModelMixin):
...
@action(methods=["GET"], detail=True, url_path="comments", url_name="comment",
pagination_class = LimitOffsetPagination,serializer_class=CommentSerializer)
def list_comments(self,request,*args, **kwargs):
post = self.get_object() #文章對象
queryset = post.comment_set.all().order_by("-create_time") #文章的所有的評論
page = self.paginate_queryset(queryset) #對評論清單進行分頁
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
- 通路:http://127.0.0.1:8000/api/posts/2/comments/
接口緩存
-
緩存機制
blogproj/settings.py
- 本地
redisCACHES = { 'default':{ 'BACKEND':'django.core.cache.backends.locmem.LocMemCache', } }
- 安裝:pip install django-redis-cache
- 配置
CACHES = { "default": { "BACKEND": "redis_cache.RedisCache", "LOCATION": "redis://:[email protected]:6379/0", "OPTIONS": { "CONNECTION_POOL_CLASS": "redis.BlockingConnectionPool", "CONNECTION_POOL_CLASS_KWARGS": {"max_connections": 50, "timeout": 20}, "MAX_CONNECTIONS": 1000, "PICKLE_VERSION": -1, }, }, }
- 本地
-
緩存架構
安裝:pip install drf-extensions
-
文章清單緩存
blog/views.py
- 導入keyBit
from rest_framework_extensions.key_constructor.constructors import DefaultKeyConstructor from rest_framework_extensions.key_constructor.bits import ( ListSqlQueryKeyBit,PaginationKeyBit,RetrieveSqlQueryKeyBit ) from rest_framework_extensions.cache.decorators import cache_response
- 實作KeyConstructor
#文章清單緩存key生成器 class PostListKeyConstructor(DefaultKeyConstructor): list_sql = ListSqlQueryKeyBit pagination = PaginationKeyBit updated_at = RetrieveSqlQueryKeyBit
- 緩存list
class PostViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin): ... @cache_response(timeout=5*60, key_func=PostListKeyConstructor()) def list(self, request, *args, **kwargs): return super().list(self, request, *args, **kwargs)
- 導入keyBit
- 自動維護時間更新
blog/models.py
from django.db.models.signals import post_delete,post_save
from django.core.cache import cache
from datetime import datetime
...
def change_post_updated_at(sender=None, instance=None,*args,**kwargs):
cache.set("post_updated_at", datetime.utcnow())
post_delete.connect(receiver=change_post_updated_at, sender=Post)
post_save.connect(receiver=change_post_updated_at, sender=Post)
- 更新時間
blog/utils.py
from rest_framework_extensions.key_constructor.bits import KeyBitBase
from django.core.cache import cache
from datetime import datetime
class UpdateAtKeyBit(KeyBitBase):
key = "updated_at"
def get_data(self, **kwargs):
value = cache.get(self.key, None)
if not value:
value = datetime.utcnow()
cache.set(self.key, value=value)
return str(value)
- 更新keyConstructor
blog/views.py
from .utils import UpdateAtKeyBit
class PostUpdatedAtKeyBit(UpdateAtKeyBit):
key = "post_updated_at"
#文章清單緩存key生成器
class PostListKeyConstructor(DefaultKeyConstructor):
list_sql = ListSqlQueryKeyBit()
pagination = PaginationKeyBit()
updated_at = PostUpdatedAtKeyBit() #更新
API版本管理
- 開啟版本管理
blogproj/settings.py
REST_FRAMEWORK = {
...
'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.NamespaceVersioning',
'DEFAULT_VERSION':'v1'
}
- 修改blogproj/urls.py
urlpatterns = [
...
#api根視圖
path('api/v1/',include((router.urls,"api"), namespace='v1')),
path('api/v2/',include((router.urls,"api"), namespace='v2')),
限流
- 全局配置
blogproj/setttings.py
REST_FRAMEWORK = {
...
'DEFAULT_THROTTLE_CLASSES':{
'rest_framework.throttling.AnonRateThrottle'
},
'DEFAULT_THROTTLE_RATES':{
'anon': '10/min',
}
}
- 局部配置
- 限制評論通路次數
comments/views.py
from rest_framework.throttling import AnonRateThrottle
class CommentAnonRateThrottle(AnonRateThrottle):
THROTTLE_RATES = {'anon': "5/min"}
class CommentViewSet(viewsets.GenericViewSet,mixins.CreateModelMixin):
...
throttle_classes = [CommentAnonRateThrottle]