Skip to content

Commit cce3390

Browse files
author
zmrenwu
committed
Step11: 加缓存为接口提速
1 parent d594c15 commit cce3390

File tree

12 files changed

+223
-79
lines changed

12 files changed

+223
-79
lines changed

Pipfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ django-haystack = "*"
1818
djangorestframework = "*"
1919
django-filter = "*"
2020
drf-haystack = "*"
21+
drf-extensions = "*"
22+
django-redis-cache = "*"
2123

2224
[requires]
2325
python_version = "3"

Pipfile.lock

Lines changed: 62 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ $ git clone https://github.com/HelloGitHub-Team/HelloDjango-REST-framework-tutor
199199
10. [实现分类、标签、归档日期接口](https://www.zmrenwu.com/courses/django-rest-framework-tutorial/materials/99/)
200200
11. [评论接口](https://www.zmrenwu.com/courses/django-rest-framework-tutorial/materials/100/))
201201
12. [基于 drf-haystack 实现文章搜索接口](https://www.zmrenwu.com/courses/django-rest-framework-tutorial/materials/101/))
202+
13. [加缓存为接口提速](https://www.zmrenwu.com/courses/django-rest-framework-tutorial/materials/102/))
202203

203204
## 公众号
204205
<p align="center">

blog/models.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import re
2+
from datetime import datetime
23

34
import markdown
45
from django.contrib.auth.models import User
6+
from django.core.cache import cache
57
from django.db import models
8+
from django.db.models.signals import post_delete, post_save
69
from django.urls import reverse
710
from django.utils import timezone
811
from django.utils.functional import cached_property
@@ -148,3 +151,11 @@ def body_html(self):
148151
@cached_property
149152
def rich_content(self):
150153
return generate_rich_content(self.body)
154+
155+
156+
def change_post_updated_at(sender=None, instance=None, *args, **kwargs):
157+
cache.set("post_updated_at", datetime.utcnow())
158+
159+
160+
post_save.connect(receiver=change_post_updated_at, sender=Post)
161+
post_delete.connect(receiver=change_post_updated_at, sender=Post)

blog/utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
from datetime import datetime
2+
3+
from django.core.cache import cache
14
from django.utils.html import strip_tags
5+
from rest_framework_extensions.key_constructor.bits import KeyBitBase
6+
27
from haystack.utils import Highlighter as HaystackHighlighter
38

49

@@ -14,3 +19,14 @@ def highlight(self, text_block):
1419
if len(text_block) < self.max_length:
1520
start_offset = 0
1621
return self.render_html(highlight_locations, start_offset, end_offset)
22+
23+
24+
class UpdatedAtKeyBit(KeyBitBase):
25+
key = "updated_at"
26+
27+
def get_data(self, **kwargs):
28+
value = cache.get(self.key, None)
29+
if not value:
30+
value = datetime.utcnow()
31+
cache.set(self.key, value=value)
32+
return str(value)

blog/views.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,28 @@
88
from rest_framework.permissions import AllowAny
99
from rest_framework.response import Response
1010
from rest_framework.serializers import DateField
11-
from rest_framework.views import APIView
11+
from rest_framework_extensions.cache.decorators import cache_response
12+
from rest_framework_extensions.key_constructor.bits import (
13+
ListSqlQueryKeyBit,
14+
PaginationKeyBit,
15+
RetrieveSqlQueryKeyBit,
16+
)
17+
from rest_framework_extensions.key_constructor.constructors import DefaultKeyConstructor
1218

1319
from comments.serializers import CommentSerializer
1420
from drf_haystack.viewsets import HaystackViewSet
1521
from pure_pagination.mixins import PaginationMixin
1622

1723
from .filters import PostFilter
1824
from .models import Category, Post, Tag
19-
from .search_indexes import PostIndex
2025
from .serializers import (
2126
CategorySerializer,
2227
PostHaystackSerializer,
2328
PostListSerializer,
2429
PostRetrieveSerializer,
2530
TagSerializer,
2631
)
32+
from .utils import UpdatedAtKeyBit
2733

2834

2935
class IndexView(PaginationMixin, ListView):
@@ -78,6 +84,36 @@ def get(self, request, *args, **kwargs):
7884
return response
7985

8086

87+
# ---------------------------------------------------------------------------
88+
# Django REST framework 接口
89+
# ---------------------------------------------------------------------------
90+
91+
92+
class PostUpdatedAtKeyBit(UpdatedAtKeyBit):
93+
key = "post_updated_at"
94+
95+
96+
class CommentUpdatedAtKeyBit(UpdatedAtKeyBit):
97+
key = "comment_updated_at"
98+
99+
100+
class PostListKeyConstructor(DefaultKeyConstructor):
101+
list_sql = ListSqlQueryKeyBit()
102+
pagination = PaginationKeyBit()
103+
updated_at = PostUpdatedAtKeyBit()
104+
105+
106+
class PostObjectKeyConstructor(DefaultKeyConstructor):
107+
retrieve_sql = RetrieveSqlQueryKeyBit()
108+
updated_at = PostUpdatedAtKeyBit()
109+
110+
111+
class CommentListKeyConstructor(DefaultKeyConstructor):
112+
list_sql = ListSqlQueryKeyBit()
113+
pagination = PaginationKeyBit()
114+
updated_at = CommentUpdatedAtKeyBit()
115+
116+
81117
class IndexPostListAPIView(ListAPIView):
82118
serializer_class = PostListSerializer
83119
queryset = Post.objects.all()
@@ -103,6 +139,14 @@ def get_serializer_class(self):
103139
self.action, super().get_serializer_class()
104140
)
105141

142+
@cache_response(timeout=5 * 60, key_func=PostListKeyConstructor())
143+
def list(self, request, *args, **kwargs):
144+
return super().list(request, *args, **kwargs)
145+
146+
@cache_response(timeout=5 * 60, key_func=PostObjectKeyConstructor())
147+
def retrieve(self, request, *args, **kwargs):
148+
return super().retrieve(request, *args, **kwargs)
149+
106150
@action(
107151
methods=["GET"], detail=False, url_path="archive/dates", url_name="archive-date"
108152
)
@@ -112,6 +156,7 @@ def list_archive_dates(self, request, *args, **kwargs):
112156
data = [date_field.to_representation(date) for date in dates]
113157
return Response(data=data, status=status.HTTP_200_OK)
114158

159+
@cache_response(timeout=5 * 60, key_func=CommentListKeyConstructor())
115160
@action(
116161
methods=["GET"],
117162
detail=True,

blogproject/settings/production.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
11
from .common import *
22

3-
SECRET_KEY = os.environ['DJANGO_SECRET_KEY']
3+
SECRET_KEY = os.environ["DJANGO_SECRET_KEY"]
44

5-
DEBUG = False
5+
DEBUG = True
66

7-
ALLOWED_HOSTS = ['hellodjango-blog-tutorial-demo.zmrenwu.com']
8-
HAYSTACK_CONNECTIONS['default']['URL'] = 'http://hellodjango_blog_tutorial_elasticsearch:9200/'
7+
ALLOWED_HOSTS = [
8+
"hellodjango-blog-tutorial-demo.zmrenwu.com",
9+
"127.0.0.1",
10+
"192.168.10.73",
11+
]
12+
HAYSTACK_CONNECTIONS["default"]["URL"] = "http://elasticsearch:9200/"
13+
14+
CACHES = {
15+
"default": {
16+
"BACKEND": "redis_cache.RedisCache",
17+
"LOCATION": "redis://:UJaoRZlNrH40BDaWU6fi@redis:6379/0",
18+
"OPTIONS": {
19+
"CONNECTION_POOL_CLASS": "redis.BlockingConnectionPool",
20+
"CONNECTION_POOL_CLASS_KWARGS": {"max_connections": 50, "timeout": 20},
21+
"MAX_CONNECTIONS": 1000,
22+
"PICKLE_VERSION": -1,
23+
},
24+
},
25+
}

comments/models.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,31 @@
1+
from datetime import datetime
2+
3+
from django.core.cache import cache
14
from django.db import models
5+
from django.db.models.signals import post_delete, post_save
26
from django.utils import timezone
37

48

59
class Comment(models.Model):
6-
name = models.CharField('名字', max_length=50)
7-
email = models.EmailField('邮箱')
8-
url = models.URLField('网址', blank=True)
9-
text = models.TextField('内容')
10-
created_time = models.DateTimeField('创建时间', default=timezone.now)
11-
post = models.ForeignKey('blog.Post', verbose_name='文章', on_delete=models.CASCADE)
10+
name = models.CharField("名字", max_length=50)
11+
email = models.EmailField("邮箱")
12+
url = models.URLField("网址", blank=True)
13+
text = models.TextField("内容")
14+
created_time = models.DateTimeField("创建时间", default=timezone.now)
15+
post = models.ForeignKey("blog.Post", verbose_name="文章", on_delete=models.CASCADE)
1216

1317
class Meta:
14-
verbose_name = '评论'
18+
verbose_name = "评论"
1519
verbose_name_plural = verbose_name
16-
ordering = ['-created_time']
20+
ordering = ["-created_time"]
1721

1822
def __str__(self):
19-
return '{}: {}'.format(self.name, self.text[:20])
23+
return "{}: {}".format(self.name, self.text[:20])
24+
25+
26+
def change_comment_updated_at(sender=None, instance=None, *args, **kwargs):
27+
cache.set("comment_updated_at", datetime.utcnow())
28+
29+
30+
post_save.connect(receiver=change_comment_updated_at, sender=Comment)
31+
post_delete.connect(receiver=change_comment_updated_at, sender=Comment)

compose/production/nginx/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ COPY ./compose/production/nginx/sources.list /etc/apt/
66
RUN apt-get update && apt-get install -y --allow-unauthenticated certbot python-certbot-nginx
77

88
RUN rm /etc/nginx/conf.d/default.conf
9-
COPY ./compose/production/nginx/hellodjango-blog-tutorial.conf /etc/nginx/conf.d/hellodjango-blog-tutorial.conf
9+
COPY ./compose/production/nginx/hellodjango-rest-framework-tutorial.conf /etc/nginx/conf.d/hellodjango-rest-framework-tutorial.conf
1010

1111

1212

0 commit comments

Comments
 (0)