From a7fbf44e944f1bd39dc80ee21683fb629de3d552 Mon Sep 17 00:00:00 2001 From: ryantoxx Date: Sun, 2 Aug 2026 14:52:18 +0300 Subject: [PATCH 1/4] finished task 1 and 2 --- apps/blog/admin.py | 7 ++++++- apps/blog/migrations/0002_blog_enabled.py | 17 +++++++++++++++++ apps/blog/models.py | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 apps/blog/migrations/0002_blog_enabled.py diff --git a/apps/blog/admin.py b/apps/blog/admin.py index f73d5ded..4e62d389 100644 --- a/apps/blog/admin.py +++ b/apps/blog/admin.py @@ -2,5 +2,10 @@ from apps.blog.models import Blog, Category -admin.site.register(Blog) + +@admin.register(Blog) +class BlogAdmin(admin.ModelAdmin): + list_display = ("title", "enabled") + + admin.site.register(Category) diff --git a/apps/blog/migrations/0002_blog_enabled.py b/apps/blog/migrations/0002_blog_enabled.py new file mode 100644 index 00000000..4bba9039 --- /dev/null +++ b/apps/blog/migrations/0002_blog_enabled.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2.18 on 2026-08-02 11:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("blog", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="blog", + name="enabled", + field=models.BooleanField(default=True), + ), + ] diff --git a/apps/blog/models.py b/apps/blog/models.py index 141c4c26..e65651f9 100644 --- a/apps/blog/models.py +++ b/apps/blog/models.py @@ -14,3 +14,4 @@ class Blog(models.Model): body = models.TextField() posted = models.DateField(db_index=True, auto_now_add=True) category = models.ForeignKey(Category, on_delete=models.CASCADE) + enabled = models.BooleanField(default=True) From feb18eab41686b76dbbb88c55f46a6407e9459c4 Mon Sep 17 00:00:00 2001 From: ryantoxx Date: Sun, 2 Aug 2026 15:33:03 +0300 Subject: [PATCH 2/4] implemented create blog endpoint --- apps/blog/urls.py | 3 ++- apps/blog/views.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/blog/urls.py b/apps/blog/urls.py index 402081cf..40ebcd4e 100644 --- a/apps/blog/urls.py +++ b/apps/blog/urls.py @@ -1,7 +1,7 @@ from django.urls import path from rest_framework.routers import DefaultRouter -from apps.blog.views import BlogItemView, BlogListView, CategoryViewSet +from apps.blog.views import BlogCreateView, BlogItemView, BlogListView, CategoryViewSet router = DefaultRouter(trailing_slash=False) router.register( @@ -13,5 +13,6 @@ urlpatterns = [ path("blog", BlogListView.as_view(), name="blog_list"), path("blog/", BlogItemView.as_view(), name="blog_item"), + path("blog/create", BlogCreateView.as_view(), name="blog_create"), *router.urls, ] diff --git a/apps/blog/views.py b/apps/blog/views.py index a9d39b23..706ec3f8 100644 --- a/apps/blog/views.py +++ b/apps/blog/views.py @@ -30,3 +30,16 @@ class BlogItemView(GenericAPIView): def get(self, request: Request, pk: int) -> Response: blog: Blog = get_object_or_404(Blog.objects.all(), pk=pk) return Response(self.get_serializer(blog).data) + + +class BlogCreateView(GenericAPIView): + serializer_class = BlogSerializer + permission_classes = (IsAuthenticated,) + + def post(self, request: Request) -> Response: + serializer = self.serializer_class(data=request.data) + serializer.is_valid(raise_exception=True) + + blog = Blog.objects.create(**serializer.validated_data) + + return Response(self.serializer_class(blog).data) From 6062f18c74b65cc917b596d05abcf2d79b5d47d3 Mon Sep 17 00:00:00 2001 From: ryantoxx Date: Sun, 2 Aug 2026 15:59:32 +0300 Subject: [PATCH 3/4] finished task 4, 5 and 6 --- apps/blog/admin.py | 3 ++- apps/blog/migrations/0003_comment.py | 21 +++++++++++++++++++++ apps/blog/models.py | 5 +++++ apps/blog/serializers.py | 8 +++++++- apps/blog/urls.py | 3 ++- apps/blog/views.py | 20 ++++++++++++++++++-- 6 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 apps/blog/migrations/0003_comment.py diff --git a/apps/blog/admin.py b/apps/blog/admin.py index 4e62d389..e132e362 100644 --- a/apps/blog/admin.py +++ b/apps/blog/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from apps.blog.models import Blog, Category +from apps.blog.models import Blog, Category, Comment @admin.register(Blog) @@ -9,3 +9,4 @@ class BlogAdmin(admin.ModelAdmin): admin.site.register(Category) +admin.site.register(Comment) diff --git a/apps/blog/migrations/0003_comment.py b/apps/blog/migrations/0003_comment.py new file mode 100644 index 00000000..d93dae97 --- /dev/null +++ b/apps/blog/migrations/0003_comment.py @@ -0,0 +1,21 @@ +# Generated by Django 4.2.18 on 2026-08-02 12:36 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("blog", "0002_blog_enabled"), + ] + + operations = [ + migrations.CreateModel( + name="Comment", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("text", models.TextField()), + ("blog", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to="blog.blog")), + ], + ), + ] diff --git a/apps/blog/models.py b/apps/blog/models.py index e65651f9..ca0e61db 100644 --- a/apps/blog/models.py +++ b/apps/blog/models.py @@ -15,3 +15,8 @@ class Blog(models.Model): posted = models.DateField(db_index=True, auto_now_add=True) category = models.ForeignKey(Category, on_delete=models.CASCADE) enabled = models.BooleanField(default=True) + + +class Comment(models.Model): + text = models.TextField() + blog = models.ForeignKey(Blog, on_delete=models.CASCADE) diff --git a/apps/blog/serializers.py b/apps/blog/serializers.py index 9137b4c3..782e6c4b 100644 --- a/apps/blog/serializers.py +++ b/apps/blog/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from apps.blog.models import Blog, Category +from apps.blog.models import Blog, Category, Comment class CategorySerializer(serializers.ModelSerializer): @@ -13,3 +13,9 @@ class BlogSerializer(serializers.ModelSerializer): class Meta: model = Blog fields = "__all__" + + +class CommentSerializer(serializers.ModelSerializer): + class Meta: + model = Comment + fields = "__all__" diff --git a/apps/blog/urls.py b/apps/blog/urls.py index 40ebcd4e..5bf6ef83 100644 --- a/apps/blog/urls.py +++ b/apps/blog/urls.py @@ -1,7 +1,7 @@ from django.urls import path from rest_framework.routers import DefaultRouter -from apps.blog.views import BlogCreateView, BlogItemView, BlogListView, CategoryViewSet +from apps.blog.views import BlogCreateView, BlogItemView, BlogListView, CategoryViewSet, CommentCreateView router = DefaultRouter(trailing_slash=False) router.register( @@ -14,5 +14,6 @@ path("blog", BlogListView.as_view(), name="blog_list"), path("blog/", BlogItemView.as_view(), name="blog_item"), path("blog/create", BlogCreateView.as_view(), name="blog_create"), + path("comment/create", CommentCreateView.as_view(), name="comment_create"), *router.urls, ] diff --git a/apps/blog/views.py b/apps/blog/views.py index 706ec3f8..ef45d35a 100644 --- a/apps/blog/views.py +++ b/apps/blog/views.py @@ -4,8 +4,8 @@ from rest_framework.request import Request from rest_framework.response import Response -from apps.blog.models import Blog, Category -from apps.blog.serializers import BlogSerializer, CategorySerializer +from apps.blog.models import Blog, Category, Comment +from apps.blog.serializers import BlogSerializer, CategorySerializer, CommentSerializer from apps.common.permissions import ReadOnly @@ -43,3 +43,19 @@ def post(self, request: Request) -> Response: blog = Blog.objects.create(**serializer.validated_data) return Response(self.serializer_class(blog).data) + + +class CommentCreateView(GenericAPIView): + serializer_class = CommentSerializer + permission_classes = (IsAuthenticated,) + + def post(self, request: Request) -> Response: + serializer = self.serializer_class(data=request.data) + serializer.is_valid(raise_exception=True) + + comment = Comment.objects.create( + blog_id=serializer.validated_data["blog"].id, + text=serializer.validated_data["text"], + ) + + return Response(self.serializer_class(comment).data) From bb679ce6325da2ed50049d70ee483d3aacde44ff Mon Sep 17 00:00:00 2001 From: ryantoxx Date: Sun, 2 Aug 2026 18:38:29 +0300 Subject: [PATCH 4/4] finished Milestone 1 --- .../migrations/0004_alter_comment_blog.py | 20 +++++++++++++++++++ apps/blog/models.py | 2 +- apps/blog/serializers.py | 10 ++++++---- 3 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 apps/blog/migrations/0004_alter_comment_blog.py diff --git a/apps/blog/migrations/0004_alter_comment_blog.py b/apps/blog/migrations/0004_alter_comment_blog.py new file mode 100644 index 00000000..8da077f6 --- /dev/null +++ b/apps/blog/migrations/0004_alter_comment_blog.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.18 on 2026-08-02 15:32 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("blog", "0003_comment"), + ] + + operations = [ + migrations.AlterField( + model_name="comment", + name="blog", + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name="comments", to="blog.blog" + ), + ), + ] diff --git a/apps/blog/models.py b/apps/blog/models.py index ca0e61db..422130a4 100644 --- a/apps/blog/models.py +++ b/apps/blog/models.py @@ -19,4 +19,4 @@ class Blog(models.Model): class Comment(models.Model): text = models.TextField() - blog = models.ForeignKey(Blog, on_delete=models.CASCADE) + blog = models.ForeignKey(Blog, on_delete=models.CASCADE, related_name="comments") diff --git a/apps/blog/serializers.py b/apps/blog/serializers.py index 782e6c4b..ebf83dc3 100644 --- a/apps/blog/serializers.py +++ b/apps/blog/serializers.py @@ -9,13 +9,15 @@ class Meta: fields = "__all__" -class BlogSerializer(serializers.ModelSerializer): +class CommentSerializer(serializers.ModelSerializer): class Meta: - model = Blog + model = Comment fields = "__all__" -class CommentSerializer(serializers.ModelSerializer): +class BlogSerializer(serializers.ModelSerializer): + comments = CommentSerializer(many=True, read_only=True) + class Meta: - model = Comment + model = Blog fields = "__all__"