From 7f7be354599ccbe514ee24bab3753d9f2124a363 Mon Sep 17 00:00:00 2001 From: vladislavdacenko Date: Mon, 13 Nov 2023 14:30:41 +0200 Subject: [PATCH 1/5] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=BE=D0=B1=D0=B8=D0=B2?= =?UTF-8?q?=20=D0=BB=D1=804=20=D0=B4=D0=BE=20=D0=BA=D1=96=D0=BD=D1=86?= =?UTF-8?q?=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Blog/serializer.py | 0 Blog/urls.py | 0 BlogProject/yasg.py | 0 requirements.txt | 0 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Blog/serializer.py create mode 100644 Blog/urls.py create mode 100644 BlogProject/yasg.py create mode 100644 requirements.txt diff --git a/Blog/serializer.py b/Blog/serializer.py new file mode 100644 index 0000000..e69de29 diff --git a/Blog/urls.py b/Blog/urls.py new file mode 100644 index 0000000..e69de29 diff --git a/BlogProject/yasg.py b/BlogProject/yasg.py new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 From b7ab7c2445ff879188cabedb52cd7d7b2eb57af2 Mon Sep 17 00:00:00 2001 From: vladislavdacenko Date: Mon, 13 Nov 2023 14:34:31 +0200 Subject: [PATCH 2/5] =?UTF-8?q?=D0=92=D0=B8=D0=BA=D0=BE=D0=BD=D0=B0=D0=B2?= =?UTF-8?q?=20=D1=83=D1=81=D1=96=20=D0=B7=D0=B0=D0=B2=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8F=20=D0=B2=20=D0=BB=D1=804?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/BlogProject.iml | 2 +- .idea/misc.xml | 2 +- Blog/serializer.py | 14 ++++ Blog/views.py | 163 +++++++++++++++++++++++++++++++++++++++- BlogProject/settings.py | 14 +--- BlogProject/urls.py | 24 ++---- BlogProject/yasg.py | 21 ++++++ db.sqlite3 | Bin 151552 -> 151552 bytes requirements.txt | 3 + 9 files changed, 212 insertions(+), 31 deletions(-) diff --git a/.idea/BlogProject.iml b/.idea/BlogProject.iml index 92de0e4..8a24ab6 100644 --- a/.idea/BlogProject.iml +++ b/.idea/BlogProject.iml @@ -16,7 +16,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index a6c6116..c0ac767 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/Blog/serializer.py b/Blog/serializer.py index e69de29..9963870 100644 --- a/Blog/serializer.py +++ b/Blog/serializer.py @@ -0,0 +1,14 @@ +from rest_framework import serializers +from Blog.models import Post, Comment + + +class PostSerializer(serializers.ModelSerializer): + class Meta: + model = Post + fields = ['title', 'content', 'author', 'publ_date', 'category'] + +class CommentSerializer(serializers.ModelSerializer): + class Meta: + model = Comment + fields = ['post', 'author_of_the_comment', 'content_of_the_comment', 'date_of_creation'] + diff --git a/Blog/views.py b/Blog/views.py index 91ea44a..f92b5c7 100644 --- a/Blog/views.py +++ b/Blog/views.py @@ -1,3 +1,164 @@ from django.shortcuts import render +from drf_yasg.utils import swagger_auto_schema + +from .models import Post, Comment +from .serializer import PostSerializer, CommentSerializer +from django.http import Http404 +from rest_framework.views import APIView +from rest_framework.response import Response +from rest_framework import status +from drf_yasg import openapi + +class PostList(APIView): + + @swagger_auto_schema( + operation_description="Get a list of posts", + responses={200: openapi.Response('List of posts', PostSerializer(many=True))} + ) + def get(self, request, format=None): + post = Post.objects.all() + serializer = PostSerializer(post, many=True) + return Response(serializer.data) + + @swagger_auto_schema( + operation_description="Create a new post", + request_body=PostSerializer, + responses={201: 'Created', 400: 'Bad Request'} + ) + + def post(self, request, format=None): + serializer = PostSerializer(data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class PostDetail(APIView): + + def get_object(self, pk): + try: + return Post.objects.get(pk=pk) + except Post.DoesNotExist: + raise Http404 + + @swagger_auto_schema( + operation_description="Get details of a specific post", + manual_parameters=[ + openapi.Parameter('pk', openapi.IN_PATH, description="Post ID", type=openapi.TYPE_INTEGER), + ], + responses={200: openapi.Response('Post details', PostSerializer)} + ) + + def get(self, request, pk, format=None): + post = self.get_object(pk) + serializer = PostSerializer(post) + return Response(serializer.data) + + @swagger_auto_schema( + operation_description="Update details of a specific post", + manual_parameters=[ + openapi.Parameter('pk', openapi.IN_PATH, description="Post ID", type=openapi.TYPE_INTEGER), + ], + request_body=PostSerializer, + responses={200: 'Updated', 400: 'Bad Request'} + ) + + def put(self, request, pk, format=None): + post = self.get_object(pk) + serializer = PostSerializer(post, data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + @swagger_auto_schema( + operation_description="Delete a specific post", + manual_parameters=[ + openapi.Parameter('pk', openapi.IN_PATH, description="Post ID", type=openapi.TYPE_INTEGER), + ], + responses={204: 'No Content'} + ) + + def delete(self, request, pk, format=None): + post = self.get_object(pk) + post.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + + +class CommentList(APIView): + + @swagger_auto_schema( + operation_description="Get a list of comments", + responses={200: openapi.Response('List of comments', CommentSerializer(many=True))} + ) + + def get(self, request, format=None): + comment = Comment.objects.all() + serializer = CommentSerializer(comment, many=True) + return Response(serializer.data) + + @swagger_auto_schema( + operation_description="Create a new comment", + request_body=CommentSerializer, + responses={201: 'Created', 400: 'Bad Request'} + ) + + def post(self, request, format=None): + serializer = CommentSerializer(data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class CommentDetail(APIView): + + def get_object(self, pk): + try: + return Comment.objects.get(pk=pk) + except Comment.DoesNotExist: + raise Http404 + + @swagger_auto_schema( + operation_description="Get details of a specific comment", + manual_parameters=[ + openapi.Parameter('pk', openapi.IN_PATH, description="Comment ID", type=openapi.TYPE_INTEGER), + ], + responses={200: openapi.Response('Comment details', CommentSerializer)} + ) + + def get(self, request, pk, format=None): + comment = self.get_object(pk) + serializer = CommentSerializer(comment) + return Response(serializer.data) + + @swagger_auto_schema( + operation_description="Update details of a specific comment", + manual_parameters=[ + openapi.Parameter('pk', openapi.IN_PATH, description="Comment ID", type=openapi.TYPE_INTEGER), + ], + request_body=CommentSerializer, + responses={200: 'Updated', 400: 'Bad Request'} + ) + + def put(self, request, pk, format=None): + comment = self.get_object(pk) + serializer = CommentSerializer(comment, data=request.data) + if serializer.is_valid(): + serializer.save() + return Response(serializer.data) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + @swagger_auto_schema( + operation_description="Delete a specific comment", + manual_parameters=[ + openapi.Parameter('pk', openapi.IN_PATH, description="Comment ID", type=openapi.TYPE_INTEGER), + ], + responses={204: 'No Content'} + ) + + def delete(self, request, pk, format=None): + comment = self.get_object(pk) + comment.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + -# Create your views here. diff --git a/BlogProject/settings.py b/BlogProject/settings.py index 9bf9d7d..1efd18c 100644 --- a/BlogProject/settings.py +++ b/BlogProject/settings.py @@ -1,14 +1,3 @@ -""" -Django settings for BlogProject project. - -Generated by 'django-admin startproject' using Django 4.2.6. - -For more information on this file, see -https://docs.djangoproject.com/en/4.2/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/4.2/ref/settings/ -""" from pathlib import Path @@ -38,6 +27,9 @@ 'django.contrib.messages', 'django.contrib.staticfiles', 'Blog', + 'rest_framework', + 'drf_yasg', + ] MIDDLEWARE = [ diff --git a/BlogProject/urls.py b/BlogProject/urls.py index ce890c3..3a4e885 100644 --- a/BlogProject/urls.py +++ b/BlogProject/urls.py @@ -1,22 +1,12 @@ -""" -URL configuration for BlogProject project. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/4.2/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" from django.contrib import admin -from django.urls import path +from django.urls import path, re_path, include +from .yasg import urlpatterns as doc_urls + urlpatterns = [ path('admin/', admin.site.urls), + path('api/', include([ + path('blog/', include('Blog.urls')), + ])), ] +urlpatterns += doc_urls \ No newline at end of file diff --git a/BlogProject/yasg.py b/BlogProject/yasg.py index e69de29..b5588d9 100644 --- a/BlogProject/yasg.py +++ b/BlogProject/yasg.py @@ -0,0 +1,21 @@ +from django.urls import re_path, path +from rest_framework import permissions +from drf_yasg.views import get_schema_view +from drf_yasg import openapi + +schema_view = get_schema_view( + openapi.Info( + title="Snippets API", + default_version='v1', + description="Test description", + license=openapi.License(name="BSD License"), + ), + public=True, + permission_classes=(permissions.AllowAny,), +) + +urlpatterns = [ + path('swagger/', schema_view.without_ui(cache_timeout=0), name='schema-json'), + path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), + path('redoc/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'), +] \ No newline at end of file diff --git a/db.sqlite3 b/db.sqlite3 index ae0541903e9dde9739af9e4dac80f907492d4306..3137b2269c4685207d2353599bf0a494154ce23a 100644 GIT binary patch delta 1250 zcmaiz%WoT16vpq&Z61?$a$J?RRHeje9n>hXGf$7ls0$}??bxwXzv3hanX$+9Gq&Tg z^Kca$)-r7=p3r3@>8QtIc zbkBFbyLp${yvuxYo)SNOYl0HL{@{y&GoPbg2+{BYLhvmt!^e<;FX6Z5Ag97sXza8J zvwe7g((1KrqHd(Ccx!pg@(%orSZ2If&Lk>j!*m=EQ3pS%^5SB;RHJj{vlxri)^{gP zo#{mgbu&79f~a&VYPk7g>^#?p*SR*aOuL@0x#KpOS$=Jx8s^c=OW{-vFd!qk&nbu;b?3{sfwOx z(4TTNg0i?^NRhB!ibq$X(iMRdL@Uo*In~SyPEmDAij9}lQI3YWCK1BUb*oUOkuh@+b zFVS6rk76!|>?joLB~@LiEX&nGV<}TiY4Tc16}6m_t@F0DZ*?~BcF$z;u249gh}7bx z@}ws=U$jbUs4-LY#;yhT~X_W>2K8YNFvAua#nfxPzZw^i9d0Mx-RJiGD{Q zTO79*>T+}=nVgR()j%Px_!C-&pH)glpLK2}!6_bpd`2YJO;&hsxV{)O49#=RJ+bUx zlEVwJY9ODl#`7g(!r^w+Rs-`5UwJkjo1D)0L^5qU+v;K+1bLYOU4XlX1_qoQ);8j?04hpLxg}Cv(jwcZR868d?Zi@RWFb z4~8r_K>eR@bo1%`pe7!dZDC zRn~K*47Sic==23b7qz5hl+9VKst+HbNW{l({c@igJq~{%3ic7~!+!JR<{$887p5qh zCcv>icu5YkgJ2JKV2AAf4yN`l#s_Pg>1w_Df$B1mR1xeY!S)WYfi}={fc4VHFvaxr z5%?d7s2xDvhgz+@R}`2S3<$vk2m*=QpZ&pU%piD|8KEeb(C);XTrBQ2BgwvWNXSwJ1`|ka6Gbbu@qW0Uxz(L2X7`RwC^|n5dj);abBDlsj zb`i%Jj_fXT64^+g#iKR4q*uhY(ks!e&E*X(yB+B6b-Sfk&8%7R=(@F;MuY76J1ttt z#Vu-c>?71gn+L zTnznzZ^Ac&4>YkSrBbe%|3&z!t(`;;DOCRFUetNGLWKb;jLK-MlY(1SaeX!Q59TXB z0@Xm6aEUN~+6?kxuXe?y@lJT>D_+spDW_G?437FoOn-3PHxil}o8%du2${i9sIk`N Sk?_d&9UOzgNrx|UTK_L^ws*4t diff --git a/requirements.txt b/requirements.txt index e69de29..fa5e2a5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,3 @@ +Django~=4.2.6 +djangorestframework==3.14.0 +drf-yasg==1.21.7 From 86111d76d96546597fac51ada521df1bd2530fa7 Mon Sep 17 00:00:00 2001 From: vladislavdacenko Date: Mon, 13 Nov 2023 14:34:38 +0200 Subject: [PATCH 3/5] =?UTF-8?q?=D0=92=D0=B8=D0=BA=D0=BE=D0=BD=D0=B0=D0=B2?= =?UTF-8?q?=20=D1=83=D1=81=D1=96=20=D0=B7=D0=B0=D0=B2=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=BD=D1=8F=20=D0=B2=20=D0=BB=D1=804?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Blog/urls.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Blog/urls.py b/Blog/urls.py index e69de29..a7779a6 100644 --- a/Blog/urls.py +++ b/Blog/urls.py @@ -0,0 +1,13 @@ +from django.urls import path +from . import views + +from rest_framework.urlpatterns import format_suffix_patterns + +urlpatterns = [ + path('post/', views.PostList.as_view()), + path('post//', views.PostDetail.as_view()), + path('comment/', views.CommentList.as_view()), + path('comment//', views.CommentDetail.as_view()), +] + +urlpatterns = format_suffix_patterns(urlpatterns) \ No newline at end of file From 9f66a81ea1c96b4a93603215ef09709f8dbbb963 Mon Sep 17 00:00:00 2001 From: vladislavdacenko Date: Mon, 13 Nov 2023 14:46:51 +0200 Subject: [PATCH 4/5] finish --- Blog/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Blog/views.py b/Blog/views.py index f92b5c7..0450f2c 100644 --- a/Blog/views.py +++ b/Blog/views.py @@ -138,6 +138,7 @@ def get(self, request, pk, format=None): ], request_body=CommentSerializer, responses={200: 'Updated', 400: 'Bad Request'} + ) def put(self, request, pk, format=None): From 215c4634569325e2ca0d454f5268ae2bf0c9f814 Mon Sep 17 00:00:00 2001 From: vladislavdacenko Date: Sun, 3 Dec 2023 13:30:09 +0200 Subject: [PATCH 5/5] =?UTF-8?q?=D0=94=D0=BE=D0=B4=D0=B0=D0=B2=20=D0=B0?= =?UTF-8?q?=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D0=B7=D0=B0=D1=86=D1=96=D1=8E=20?= =?UTF-8?q?=D1=96=20=D0=BF=D0=B5=D1=80=D0=BC=D1=96=D1=88=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Blog/urls.py | 3 ++- Blog/views.py | 7 ++++++- BlogProject/settings.py | 7 +++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Blog/urls.py b/Blog/urls.py index a7779a6..6cb9b44 100644 --- a/Blog/urls.py +++ b/Blog/urls.py @@ -1,4 +1,4 @@ -from django.urls import path +from django.urls import path, include from . import views from rest_framework.urlpatterns import format_suffix_patterns @@ -8,6 +8,7 @@ path('post//', views.PostDetail.as_view()), path('comment/', views.CommentList.as_view()), path('comment//', views.CommentDetail.as_view()), + path('drf-auth', include('rest_framework.urls')), ] urlpatterns = format_suffix_patterns(urlpatterns) \ No newline at end of file diff --git a/Blog/views.py b/Blog/views.py index 0450f2c..f354b97 100644 --- a/Blog/views.py +++ b/Blog/views.py @@ -1,5 +1,6 @@ from django.shortcuts import render from drf_yasg.utils import swagger_auto_schema +from rest_framework.permissions import IsAuthenticatedOrReadOnly from .models import Post, Comment from .serializer import PostSerializer, CommentSerializer @@ -10,13 +11,14 @@ from drf_yasg import openapi class PostList(APIView): + permission_classes = [IsAuthenticatedOrReadOnly] @swagger_auto_schema( operation_description="Get a list of posts", responses={200: openapi.Response('List of posts', PostSerializer(many=True))} ) def get(self, request, format=None): - post = Post.objects.all() + post = Post.objects.all() serializer = PostSerializer(post, many=True) return Response(serializer.data) @@ -34,6 +36,7 @@ def post(self, request, format=None): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class PostDetail(APIView): + permission_classes = [IsAuthenticatedOrReadOnly] def get_object(self, pk): try: @@ -86,6 +89,7 @@ def delete(self, request, pk, format=None): class CommentList(APIView): + permission_classes = [IsAuthenticatedOrReadOnly] @swagger_auto_schema( operation_description="Get a list of comments", @@ -111,6 +115,7 @@ def post(self, request, format=None): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class CommentDetail(APIView): + permission_classes = [IsAuthenticatedOrReadOnly] def get_object(self, pk): try: diff --git a/BlogProject/settings.py b/BlogProject/settings.py index 1efd18c..20ad7ae 100644 --- a/BlogProject/settings.py +++ b/BlogProject/settings.py @@ -115,3 +115,10 @@ # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +REST_FRAMEWORK = { + 'DEFAULT_AUTHENTICATION_CLASSES': [ + 'rest_framework.authentication.BasicAuthentication', + 'rest_framework.authentication.SessionAuthentication', + ] +} \ No newline at end of file