From 556b58216be94b37ced6e6d80bfcd1c5197c9bca Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Sun, 3 May 2026 18:41:51 +0330 Subject: [PATCH] blog category added --- backend/blog/admin.py | 18 +++++++++++++ .../blog/migrations/0004_blogcategorymodel.py | 24 ++++++++++++++++++ .../0005_alter_blogmodel_category.py | 19 ++++++++++++++ backend/blog/models.py | 13 +++++++++- backend/blog/serializers.py | 19 +++++++++++--- backend/blog/urls.py | 1 + backend/blog/views.py | 25 +++++++++++++++++-- backend/core/settings/unfold_conf.py | 6 +++++ 8 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 backend/blog/migrations/0004_blogcategorymodel.py create mode 100644 backend/blog/migrations/0005_alter_blogmodel_category.py diff --git a/backend/blog/admin.py b/backend/blog/admin.py index 2cc2517..1dc70fb 100644 --- a/backend/blog/admin.py +++ b/backend/blog/admin.py @@ -30,3 +30,21 @@ class BlogModelAdmin(ModelAdmin, ImportExportModelAdmin): if db_field.name == "summery": kwargs["widget"] = UnfoldAdminTextareaWidget() return super().formfield_for_dbfield(db_field, request, **kwargs) + +@admin.register(BlogCategoryModel) +class BlogCategoryAdmin(ModelAdmin): + def has_view_permission(self, request, obj=None): + return request.user.is_superuser + + def has_add_permission(self, request, obj=None): + return request.user.is_superuser + + def has_view_permission(self, request, obj=None): + return request.user.is_superuser + + def has_change_permission(self, request, obj = ...): + return request.user.is_superuser + + + def has_delete_permission(self, request, obj = ...): + return request.user.is_superuser \ No newline at end of file diff --git a/backend/blog/migrations/0004_blogcategorymodel.py b/backend/blog/migrations/0004_blogcategorymodel.py new file mode 100644 index 0000000..c2d7fc0 --- /dev/null +++ b/backend/blog/migrations/0004_blogcategorymodel.py @@ -0,0 +1,24 @@ +# Generated by Django 5.2 on 2026-05-03 14:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0003_alter_blogmodel_author_alter_blogmodel_category_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='BlogCategoryModel', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(max_length=200, verbose_name='عنوان')), + ], + options={ + 'verbose_name': 'دسته بندی بلاگ', + 'verbose_name_plural': 'دسته بندی های بلاگ', + }, + ), + ] diff --git a/backend/blog/migrations/0005_alter_blogmodel_category.py b/backend/blog/migrations/0005_alter_blogmodel_category.py new file mode 100644 index 0000000..a6cd597 --- /dev/null +++ b/backend/blog/migrations/0005_alter_blogmodel_category.py @@ -0,0 +1,19 @@ +# Generated by Django 5.2 on 2026-05-03 14:16 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('blog', '0004_blogcategorymodel'), + ] + + operations = [ + migrations.AlterField( + model_name='blogmodel', + name='category', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='blogs', to='blog.blogcategorymodel', verbose_name='دسته بندی'), + ), + ] diff --git a/backend/blog/models.py b/backend/blog/models.py index 90edbb1..ca537dd 100644 --- a/backend/blog/models.py +++ b/backend/blog/models.py @@ -4,13 +4,24 @@ from django.utils.text import slugify from django.utils.timezone import now from product.models import SubCategoryModel + +class BlogCategoryModel(models.Model): + title = models.CharField(max_length=200, verbose_name='عنوان') + + class Meta: + verbose_name = 'دسته بندی بلاگ' + verbose_name_plural = 'دسته بندی های بلاگ' + + def __str__(self): + return self.title + class BlogModel(models.Model): author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blogs', verbose_name='نویسنده') title = models.CharField(max_length=200, verbose_name='عنوان') slug = models.SlugField(max_length=200, unique=True, blank=True) content = models.TextField(verbose_name='محتوا') summery = models.TextField(verbose_name='خلاصه') - category = models.ForeignKey(SubCategoryModel, on_delete=models.SET_NULL, null=True, related_name='blogs', verbose_name='دسته بندی') + category = models.ForeignKey(BlogCategoryModel, on_delete=models.SET_NULL, null=True, related_name='blogs', verbose_name='دسته بندی') created_at = models.DateTimeField(default=now, editable=False, verbose_name='ساخته شده در') updated_at = models.DateTimeField(auto_now=True, verbose_name='ابدیت شده در') is_published = models.BooleanField(default=False, verbose_name='انتشار در وبسایت') diff --git a/backend/blog/serializers.py b/backend/blog/serializers.py index 3c2570f..12ea953 100644 --- a/backend/blog/serializers.py +++ b/backend/blog/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from .models import BlogModel +from .models import BlogModel, BlogCategoryModel from account.models import User from product.serializers import SubCategorySerializer @@ -22,9 +22,22 @@ class BlogSerilizer(serializers.ModelSerializer): exclude = ('is_published',) +class BlogCategorySerilizer(serializers.ModelSerializer): + class Meta: + model = BlogCategoryModel + fields = '__all__' + + class AllBlogSerilizer(serializers.ModelSerializer): author = AuthorSerializer() - category = SubCategorySerializer() + category = BlogCategorySerilizer() class Meta: model = BlogModel - exclude = ('is_published', 'content',) \ No newline at end of file + exclude = ('is_published', 'content',) + + +class AllBlogCategorySerilizer(serializers.ModelSerializer): + class Meta: + model = BlogCategoryModel + fields = '__all__' + diff --git a/backend/blog/urls.py b/backend/blog/urls.py index 07d635b..ec475ec 100644 --- a/backend/blog/urls.py +++ b/backend/blog/urls.py @@ -3,5 +3,6 @@ from . import views urlpatterns = [ path('all', views.AllBlogView.as_view(), name='product-chat-view'), + path('categories', views.AllBlogCategoryView.as_view()), path('', views.BlogView.as_view(), name='product-chat-view'), ] \ No newline at end of file diff --git a/backend/blog/views.py b/backend/blog/views.py index fb503cb..353bcf7 100644 --- a/backend/blog/views.py +++ b/backend/blog/views.py @@ -1,14 +1,24 @@ from django.shortcuts import render from rest_framework.views import APIView, Response from rest_framework import status -from .models import BlogModel -from .serializers import AllBlogSerilizer, BlogSerilizer +from .models import BlogModel, BlogCategoryModel +from .serializers import AllBlogSerilizer, BlogSerilizer, AllBlogCategorySerilizer from django.shortcuts import get_object_or_404 from utils.pagination import StructurePagination from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes from django.db.models import Q + +class AllBlogCategoryView(APIView): + serializer_class = AllBlogCategorySerilizer + authentication_classes = [] + def get(self, request): + categories = BlogCategoryModel.objects.all() + category_ser = self.serializer_class(instance=categories, many=True, context={'request': request}) + return Response(category_ser.data, status=status.HTTP_200_OK) + + class AllBlogView(APIView): serializer_class = AllBlogSerilizer pagination_class = StructurePagination @@ -21,6 +31,12 @@ class AllBlogView(APIView): required=False, type=OpenApiTypes.STR, ), + OpenApiParameter( + name="category_id", + description="", + required=False, + type=OpenApiTypes.STR, + ), OpenApiParameter( name="limit", description="لیمیتش", @@ -42,8 +58,13 @@ class AllBlogView(APIView): def get(self, request): blogs = BlogModel.objects.filter(is_published=True) search_query = request.query_params.get('search', None) + category_id = request.query_params.get('category_id', None) + if search_query: blogs = blogs.filter(Q(title__icontains=search_query) | Q(content__icontains=search_query)) + if category_id: + category_obj = get_object_or_404(BlogCategoryModel, pk=category_id) + blogs.filter(category=category_obj) paginator = self.pagination_class() paginated_blogs = paginator.paginate_queryset(blogs, request) blog_ser = self.serializer_class(instance=paginated_blogs, many=True, context={'request': request}) diff --git a/backend/core/settings/unfold_conf.py b/backend/core/settings/unfold_conf.py index 7b4ca33..7596156 100644 --- a/backend/core/settings/unfold_conf.py +++ b/backend/core/settings/unfold_conf.py @@ -233,6 +233,12 @@ UNFOLD = { "link": reverse_lazy("admin:blog_blogmodel_changelist"), "permission": lambda request: request.user.is_superuser, }, + { + "title": _("دسته بندی بلاگ"), + "icon": "newsmode", + "link": reverse_lazy("admin:blog_blogcategorymodel_changelist"), + "permission": lambda request: request.user.is_superuser, + }, ],