|
1 | 1 | import demjson3
|
| 2 | +import datetime |
2 | 3 | from django.http import JsonResponse
|
3 | 4 | from django.utils import timezone
|
4 | 5 | from django.views.decorators.csrf import csrf_exempt
|
|
11 | 12 | sendNotification,
|
12 | 13 | )
|
13 | 14 | from .forms import ArticleForm, CommentForm
|
| 15 | +from django.db.models import Q, Count, Max |
| 16 | +from user.dto.user_simple import user_simple |
14 | 17 | from .models import Article, Comment
|
15 | 18 | from django.conf import settings
|
16 | 19 | from .dto.article_all import article_all
|
| 20 | +from django.core.cache import caches |
17 | 21 | from .dto.article_normal import article_normal
|
18 | 22 | from .dto.comment_normal import comment_normal
|
19 | 23 | from .dto.comment_likes import comment_likes
|
|
22 | 26 | from utils.exception.types.bad_request import (
|
23 | 27 | BadRequestException,
|
24 | 28 | ReturnUsersNumException,
|
| 29 | + RankWithoutDays, |
25 | 30 | )
|
| 31 | +from django.core.paginator import Paginator |
26 | 32 | from utils.exception.types.not_found import (
|
27 | 33 | ArticleNotFoundException,
|
28 | 34 | CommentNotFoundException,
|
@@ -78,7 +84,7 @@ def post(self, request) -> JsonResponse:
|
78 | 84 | article.update_time = timezone.now()
|
79 | 85 | article.author = user
|
80 | 86 | article.save()
|
81 |
| - content = f"我创建了文章(id={article.id}),请及时去审核" |
| 87 | + content = f"我创建了文章(id={article.id}),请及时审核" |
82 | 88 | sendNotification(
|
83 | 89 | article.author,
|
84 | 90 | None,
|
@@ -372,3 +378,106 @@ def return_users_num_pass(self, request):
|
372 | 378 | raise ReturnUsersNumException()
|
373 | 379 | return int(request.GET["return_users_num"])
|
374 | 380 | return None
|
| 381 | + |
| 382 | + |
| 383 | +class ArticleRanking(View): |
| 384 | + # AT0203 文章上传榜单 |
| 385 | + def get(self, request) -> JsonResponse: |
| 386 | + days = request.GET["days"] # 要多少天的榜单 |
| 387 | + page = request.GET.get("page", 1) # 获取页面数,默认为第1页 |
| 388 | + pagesize = request.GET.get("pageSize", 10) # 获取每页显示数量,默认为10条 |
| 389 | + if not days: |
| 390 | + raise RankWithoutDays() |
| 391 | + days = int(days) |
| 392 | + try: |
| 393 | + token = token_pass(request.headers) |
| 394 | + user: User = token_user(token) |
| 395 | + my_id = user.id |
| 396 | + except: |
| 397 | + my_id = 0 |
| 398 | + my_amount = 0 |
| 399 | + my_rank = 0 |
| 400 | + rank_count = 0 |
| 401 | + result_json_list = [] |
| 402 | + paginator = Pages(self.get_rank_queries(days), pagesize) |
| 403 | + current_page = paginator.get_page(page) |
| 404 | + adjacent_pages = list( |
| 405 | + paginator.get_adjacent_pages(current_page, adjancent_pages=3) |
| 406 | + ) |
| 407 | + |
| 408 | + for rank_q in self.get_rank_queries(days): |
| 409 | + con_id = rank_q["author_id"] |
| 410 | + amount = rank_q["article_count"] |
| 411 | + rank_count = rank_count + 1 |
| 412 | + if con_id == my_id: |
| 413 | + my_amount = amount |
| 414 | + my_rank = rank_count |
| 415 | + result_json_list.append( |
| 416 | + { |
| 417 | + "author": user_simple(User.objects.filter(id=con_id)[0]), |
| 418 | + "amount": amount, |
| 419 | + } |
| 420 | + ) |
| 421 | + # 发送给前端 |
| 422 | + return JsonResponse( |
| 423 | + { |
| 424 | + "ranking": result_json_list, |
| 425 | + "me": {"amount": my_amount, "rank": my_rank}, |
| 426 | + "pagination": { |
| 427 | + "total_pages": paginator.num_pages, |
| 428 | + "current_page": current_page.number, |
| 429 | + "page_size": pagesize, |
| 430 | + "previous_page": current_page.has_previous(), |
| 431 | + "next_page": current_page.has_next(), |
| 432 | + "adjacent_pages": adjacent_pages, |
| 433 | + }, |
| 434 | + }, |
| 435 | + status=200, |
| 436 | + ) |
| 437 | + |
| 438 | + @classmethod |
| 439 | + def get_rank_queries(cls, days): |
| 440 | + rank_cache = caches["article_ranking"] |
| 441 | + rank_queries = rank_cache.get(str(days)) |
| 442 | + if rank_queries is None: |
| 443 | + # 发现缓存中没有要查询的天数的榜单,更新榜单,并把更新的表格录入到数据库缓存中article_ranking表的对应位置 |
| 444 | + rank_queries = cls.update_rank(days) |
| 445 | + rank_cache.set(str(days), rank_queries) |
| 446 | + return rank_queries |
| 447 | + |
| 448 | + @classmethod |
| 449 | + def update_rank(cls, search_days): # 不包括存储在数据库中 |
| 450 | + if search_days != 0: |
| 451 | + start_date = timezone.now() - datetime.timedelta(days=search_days) |
| 452 | + # 查询发布时间在规定开始时间之后的 |
| 453 | + result = ( |
| 454 | + Article.objects.filter( |
| 455 | + Q(publish_time__gt=start_date) & Q(visibility=True) |
| 456 | + ) |
| 457 | + .values("author_id") |
| 458 | + .annotate( |
| 459 | + article_count=Count("author_id"), |
| 460 | + last_date=Max("publish_time"), |
| 461 | + ) |
| 462 | + .order_by("-article_count", "-last_date") |
| 463 | + ) |
| 464 | + else: |
| 465 | + result = ( |
| 466 | + Article.objects.filter(visibility=True) |
| 467 | + .values("author_id") |
| 468 | + .annotate( |
| 469 | + article_count=Count("author_id"), |
| 470 | + last_date=Max("publish_time"), |
| 471 | + ) |
| 472 | + .order_by("-article_count", "-last_date") |
| 473 | + ) |
| 474 | + return result # 返回的是Queries |
| 475 | + |
| 476 | + |
| 477 | +class Pages(Paginator): |
| 478 | + # 对原有的Paginator类进行扩展,获取当前页的相邻页面 |
| 479 | + def get_adjacent_pages(self, current_page, adjancent_pages=3): |
| 480 | + current_page = current_page.number |
| 481 | + start_page = max(current_page - adjancent_pages, 1) # 前面的页码数 |
| 482 | + end_page = min(current_page + adjancent_pages, self.num_pages) # 后面的页码数 |
| 483 | + return range(start_page, end_page + 1) |
0 commit comments