update blog performance and fix blog view
This commit is contained in:
@@ -14,18 +14,25 @@ class AuthorSerializer(serializers.ModelSerializer):
|
|||||||
else:
|
else:
|
||||||
return 'ادمین وبسایت'
|
return 'ادمین وبسایت'
|
||||||
|
|
||||||
|
class BlogCategorySerilizer(serializers.ModelSerializer):
|
||||||
|
name = serializers.SerializerMethodField()
|
||||||
|
class Meta:
|
||||||
|
model = BlogCategoryModel
|
||||||
|
fields = ['id', 'name']
|
||||||
|
|
||||||
|
def get_name(self, obj):
|
||||||
|
return obj.title
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BlogSerilizer(serializers.ModelSerializer):
|
class BlogSerilizer(serializers.ModelSerializer):
|
||||||
category = SubCategorySerializer()
|
category = BlogCategorySerilizer()
|
||||||
author = AuthorSerializer()
|
author = AuthorSerializer()
|
||||||
class Meta:
|
class Meta:
|
||||||
model = BlogModel
|
model = BlogModel
|
||||||
exclude = ('is_published',)
|
exclude = ('is_published',)
|
||||||
|
|
||||||
|
|
||||||
class BlogCategorySerilizer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = BlogCategoryModel
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
|
|
||||||
class AllBlogSerilizer(serializers.ModelSerializer):
|
class AllBlogSerilizer(serializers.ModelSerializer):
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
from django.urls import path
|
from django.urls import path, re_path
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('all', views.AllBlogView.as_view(), name='product-chat-view'),
|
path('all', views.AllBlogView.as_view(), name='product-chat-view'),
|
||||||
path('categories', views.AllBlogCategoryView.as_view()),
|
path('categories', views.AllBlogCategoryView.as_view()),
|
||||||
path('<int:slug>', views.BlogView.as_view(), name='product-chat-view'),
|
re_path(r'^(?P<slug>[\w\u0600-\u06FF\-]+)$', views.BlogView.as_view(), name='blog-view'),
|
||||||
]
|
]
|
||||||
+38
-27
@@ -6,15 +6,19 @@ from .serializers import AllBlogSerilizer, BlogSerilizer, AllBlogCategorySeriliz
|
|||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from utils.pagination import StructurePagination
|
from utils.pagination import StructurePagination
|
||||||
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
|
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
|
||||||
from django.db.models import Q
|
from django.db.models import Q, F
|
||||||
|
from django.views.decorators.cache import cache_page
|
||||||
|
from django.utils.decorators import method_decorator
|
||||||
|
from django.core.cache import cache
|
||||||
|
|
||||||
|
|
||||||
class AllBlogCategoryView(APIView):
|
class AllBlogCategoryView(APIView):
|
||||||
serializer_class = AllBlogCategorySerilizer
|
serializer_class = AllBlogCategorySerilizer
|
||||||
authentication_classes = []
|
authentication_classes = []
|
||||||
|
|
||||||
|
@method_decorator(cache_page(60 * 60)) # Cache for 1 hour
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
categories = BlogCategoryModel.objects.all()
|
categories = BlogCategoryModel.objects.all().only('id', 'name')
|
||||||
category_ser = self.serializer_class(instance=categories, many=True, context={'request': request})
|
category_ser = self.serializer_class(instance=categories, many=True, context={'request': request})
|
||||||
return Response(category_ser.data, status=status.HTTP_200_OK)
|
return Response(category_ser.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
@@ -23,29 +27,30 @@ class AllBlogView(APIView):
|
|||||||
serializer_class = AllBlogSerilizer
|
serializer_class = AllBlogSerilizer
|
||||||
pagination_class = StructurePagination
|
pagination_class = StructurePagination
|
||||||
authentication_classes = []
|
authentication_classes = []
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
parameters=[
|
parameters=[
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="search",
|
name="search",
|
||||||
description="بگرددددد تو بلاااااگگگووووو",
|
description="بگردش در بلاگ",
|
||||||
required=False,
|
required=False,
|
||||||
type=OpenApiTypes.STR,
|
type=OpenApiTypes.STR,
|
||||||
),
|
),
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="category_id",
|
name="category_id",
|
||||||
description="",
|
description="فیلتر بر اساس دسته بندی",
|
||||||
required=False,
|
required=False,
|
||||||
type=OpenApiTypes.STR,
|
type=OpenApiTypes.STR,
|
||||||
),
|
),
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="limit",
|
name="limit",
|
||||||
description="لیمیتش",
|
description="تعداد نتایج",
|
||||||
required=False,
|
required=False,
|
||||||
type=OpenApiTypes.INT,
|
type=OpenApiTypes.INT,
|
||||||
),
|
),
|
||||||
OpenApiParameter(
|
OpenApiParameter(
|
||||||
name="offset",
|
name="offset",
|
||||||
description="افستش",
|
description="شروع از",
|
||||||
required=False,
|
required=False,
|
||||||
type=OpenApiTypes.INT,
|
type=OpenApiTypes.INT,
|
||||||
)
|
)
|
||||||
@@ -56,25 +61,30 @@ class AllBlogView(APIView):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
blogs = BlogModel.objects.filter(is_published=True)
|
# Use only() to fetch required fields
|
||||||
|
blogs = BlogModel.objects.filter(is_published=True).select_related('category').only(
|
||||||
|
'id', 'title', 'slug', 'summery', 'cover_image', 'views', 'created_at', 'category'
|
||||||
|
)
|
||||||
|
|
||||||
search_query = request.query_params.get('search', None)
|
search_query = request.query_params.get('search', None)
|
||||||
category_id = request.query_params.get('category_id', None)
|
category_id = request.query_params.get('category_id', None)
|
||||||
|
|
||||||
if search_query:
|
if search_query:
|
||||||
blogs = blogs.filter(Q(title__icontains=search_query) | Q(content__icontains=search_query))
|
blogs = blogs.filter(Q(title__icontains=search_query) | Q(summery__icontains=search_query))
|
||||||
|
|
||||||
if category_id:
|
if category_id:
|
||||||
category_obj = get_object_or_404(BlogCategoryModel, pk=category_id)
|
blogs = blogs.filter(category_id=category_id) # Use category_id directly
|
||||||
blogs.filter(category=category_obj)
|
|
||||||
paginator = self.pagination_class()
|
paginator = self.pagination_class()
|
||||||
paginated_blogs = paginator.paginate_queryset(blogs, request)
|
paginated_blogs = paginator.paginate_queryset(blogs, request)
|
||||||
blog_ser = self.serializer_class(instance=paginated_blogs, many=True, context={'request': request})
|
blog_ser = self.serializer_class(instance=paginated_blogs, many=True, context={'request': request})
|
||||||
return paginator.get_paginated_response(blog_ser.data)
|
return paginator.get_paginated_response(blog_ser.data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BlogView(APIView):
|
class BlogView(APIView):
|
||||||
serializer_class = BlogSerilizer
|
serializer_class = BlogSerilizer
|
||||||
authentication_classes = []
|
authentication_classes = []
|
||||||
|
|
||||||
def get_client_ip(self, request):
|
def get_client_ip(self, request):
|
||||||
"""Helper function to get the client IP from request headers."""
|
"""Helper function to get the client IP from request headers."""
|
||||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||||
@@ -84,24 +94,25 @@ class BlogView(APIView):
|
|||||||
ip = request.META.get('REMOTE_ADDR')
|
ip = request.META.get('REMOTE_ADDR')
|
||||||
return ip
|
return ip
|
||||||
|
|
||||||
|
|
||||||
def get(self, request, slug):
|
def get(self, request, slug):
|
||||||
blog = get_object_or_404(BlogModel, slug=slug)
|
# Use only() to fetch required fields
|
||||||
|
blog = get_object_or_404(BlogModel.objects.select_related('category', 'author'), slug=slug)
|
||||||
|
|
||||||
if blog.is_published:
|
if blog.is_published:
|
||||||
# Track views using session
|
# Track views using cache instead of session (more efficient)
|
||||||
client_ip = self.get_client_ip(request)
|
client_ip = self.get_client_ip(request)
|
||||||
session_key = f'viewed_blog_{slug}_{client_ip}'
|
cache_key = f'viewed_blog_{slug}_{client_ip}'
|
||||||
|
|
||||||
if not request.session.get(session_key):
|
if not cache.get(cache_key):
|
||||||
blog.views += 1
|
# Use F() to avoid race conditions
|
||||||
blog.save()
|
BlogModel.objects.filter(pk=blog.pk).update(views=F('views') + 1)
|
||||||
print(f'views {blog.views}')
|
blog.refresh_from_db(fields=['views'])
|
||||||
print(session_key)
|
cache.set(cache_key, True, 3600) # Cache for 1 hour
|
||||||
request.session[session_key] = True
|
|
||||||
request.session.set_expiry(3600)
|
|
||||||
|
|
||||||
blog_ser = self.serializer_class(instance=blog, context={'request': request})
|
blog_ser = self.serializer_class(instance=blog, context={'request': request})
|
||||||
return Response(blog_ser.data, status=status.HTTP_200_OK)
|
return Response(blog_ser.data, status=status.HTTP_200_OK)
|
||||||
else:
|
else:
|
||||||
return Response({'detail': 'object with the given id does not exist or is not published yet'},
|
return Response(
|
||||||
status=status.HTTP_404_NOT_FOUND)
|
{'detail': 'object with the given id does not exist or is not published yet'},
|
||||||
|
status=status.HTTP_404_NOT_FOUND
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user