diff --git a/Pipfile b/Pipfile index 04900b1..06f1706 100644 --- a/Pipfile +++ b/Pipfile @@ -16,6 +16,7 @@ gunicorn = "*" dj-database-url = "*" psycopg2 = "*" termcolor = "*" +drf-yasg = "*" [dev-packages] autopep8 = "*" diff --git a/Pipfile.lock b/Pipfile.lock index c89fa11..382f736 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "638fb82004dffe189889ef206fc6fd7901b7e5e03228ca29452600d9e0393e66" + "sha256": "b1048116e2fc682571cc6680ff7ede2050e74f7940317fb2df2bd9107705079f" }, "pipfile-spec": 6, "requires": { @@ -213,6 +213,14 @@ "index": "pypi", "version": "==0.93.4" }, + "drf-yasg": { + "hashes": [ + "sha256:8b72e5b1875931a8d11af407be3a9a5ba8776541492947a0df5bafda6b7f8267", + "sha256:d50f197c7f02545d0b736df88c6d5cf874f8fea2507ad85ad7de6ae5bf2d9e5a" + ], + "index": "pypi", + "version": "==1.20.0" + }, "gunicorn": { "hashes": [ "sha256:9dcc4547dbb1cb284accfb15ab5667a0e5d1881cc443e0677b4882a4067a807e", @@ -229,6 +237,14 @@ "markers": "python_version >= '3'", "version": "==3.3" }, + "inflection": { + "hashes": [ + "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", + "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2" + ], + "markers": "python_version >= '3.5'", + "version": "==0.5.1" + }, "itypes": { "hashes": [ "sha256:03da6872ca89d29aef62773672b2d408f490f80db48b23079a4b194c86dd04c6", @@ -298,6 +314,14 @@ "markers": "python_version >= '3.6'", "version": "==3.2.0" }, + "packaging": { + "hashes": [ + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + ], + "markers": "python_version >= '3.6'", + "version": "==21.3" + }, "psycopg2": { "hashes": [ "sha256:06f32425949bd5fe8f625c49f17ebb9784e1e4fe928b7cce72edc36fb68e4c0c", @@ -330,6 +354,14 @@ "markers": "python_version >= '3.6'", "version": "==2.3.0" }, + "pyparsing": { + "hashes": [ + "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea", + "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484" + ], + "markers": "python_version >= '3.6'", + "version": "==3.0.7" + }, "python3-openid": { "hashes": [ "sha256:33fbf6928f401e0b790151ed2b5290b02545e8775f982485205a066f874aaeaf", @@ -360,6 +392,45 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.3.1" }, + "ruamel.yaml": { + "hashes": [ + "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7", + "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af" + ], + "markers": "python_version >= '3'", + "version": "==0.17.21" + }, + "ruamel.yaml.clib": { + "hashes": [ + "sha256:0847201b767447fc33b9c235780d3aa90357d20dd6108b92be544427bea197dd", + "sha256:1070ba9dd7f9370d0513d649420c3b362ac2d687fe78c6e888f5b12bf8bc7bee", + "sha256:1866cf2c284a03b9524a5cc00daca56d80057c5ce3cdc86a52020f4c720856f0", + "sha256:221eca6f35076c6ae472a531afa1c223b9c29377e62936f61bc8e6e8bdc5f9e7", + "sha256:31ea73e564a7b5fbbe8188ab8b334393e06d997914a4e184975348f204790277", + "sha256:3fb9575a5acd13031c57a62cc7823e5d2ff8bc3835ba4d94b921b4e6ee664104", + "sha256:4ff604ce439abb20794f05613c374759ce10e3595d1867764dd1ae675b85acbd", + "sha256:6e7be2c5bcb297f5b82fee9c665eb2eb7001d1050deaba8471842979293a80b0", + "sha256:72a2b8b2ff0a627496aad76f37a652bcef400fd861721744201ef1b45199ab78", + "sha256:77df077d32921ad46f34816a9a16e6356d8100374579bc35e15bab5d4e9377de", + "sha256:78988ed190206672da0f5d50c61afef8f67daa718d614377dcd5e3ed85ab4a99", + "sha256:7b2927e92feb51d830f531de4ccb11b320255ee95e791022555971c466af4527", + "sha256:7f7ecb53ae6848f959db6ae93bdff1740e651809780822270eab111500842a84", + "sha256:825d5fccef6da42f3c8eccd4281af399f21c02b32d98e113dbc631ea6a6ecbc7", + "sha256:846fc8336443106fe23f9b6d6b8c14a53d38cef9a375149d61f99d78782ea468", + "sha256:89221ec6d6026f8ae859c09b9718799fea22c0e8da8b766b0b2c9a9ba2db326b", + "sha256:9efef4aab5353387b07f6b22ace0867032b900d8e91674b5d8ea9150db5cae94", + "sha256:a32f8d81ea0c6173ab1b3da956869114cae53ba1e9f72374032e33ba3118c233", + "sha256:a49e0161897901d1ac9c4a79984b8410f450565bbad64dbfcbf76152743a0cdb", + "sha256:ada3f400d9923a190ea8b59c8f60680c4ef8a4b0dfae134d2f2ff68429adfab5", + "sha256:bf75d28fa071645c529b5474a550a44686821decebdd00e21127ef1fd566eabe", + "sha256:cfdb9389d888c5b74af297e51ce357b800dd844898af9d4a547ffc143fa56751", + "sha256:d67f273097c368265a7b81e152e07fb90ed395df6e552b9fa858c6d2c9f42502", + "sha256:dc6a613d6c74eef5a14a214d433d06291526145431c3b964f5e16529b1842bed", + "sha256:de9c6b8a1ba52919ae919f3ae96abb72b994dd0350226e28f3686cb4f142165c" + ], + "markers": "python_version < '3.11' and platform_python_implementation == 'CPython'", + "version": "==0.2.6" + }, "setuptools": { "hashes": [ "sha256:2347b2b432c891a863acadca2da9ac101eae6169b1d3dfee2ec605ecd50dbfe5", @@ -428,7 +499,7 @@ "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed", "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_full_version < '4.0.0'", "version": "==1.26.8" }, "whitenoise": { @@ -623,7 +694,7 @@ "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b", "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "markers": "sys_platform == 'win32'", "version": "==0.4.4" }, "configargparse": { @@ -1209,7 +1280,7 @@ "sha256:000ca7f471a233c2251c6c7023ee85305721bfdf18621ebff4fd17a8653427ed", "sha256:0e7c33d9a63e7ddfcb86780aac87befc2fbddf46c58dbb487e0855f7ceec283c" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_full_version < '4.0.0'", "version": "==1.26.8" }, "watchdog": { diff --git a/blogapp/swagger_schema.py b/blogapp/swagger_schema.py new file mode 100644 index 0000000..47127a0 --- /dev/null +++ b/blogapp/swagger_schema.py @@ -0,0 +1,12 @@ +from drf_yasg.inspectors import SwaggerAutoSchema + + +class CustomAutoSchema(SwaggerAutoSchema): + + def get_tags(self, operation_keys=None): + tags = self.overrides.get('tags', None) or getattr( + self.view, 'my_tags', []) + if not tags: + tags = [operation_keys[0]] + + return tags diff --git a/blogapp/urls.py b/blogapp/urls.py index 9621c2b..cb6429d 100644 --- a/blogapp/urls.py +++ b/blogapp/urls.py @@ -13,7 +13,6 @@ # all_blogger_blogs.register('blogs', OwnerBlogListVSet, 'blogs') - comment_router = NestedDefaultRouter(all_blogger_blogs, 'blog', lookup='blog') comment_router.register('comments', CommentVSet, basename='comments') diff --git a/blogapp/views.py b/blogapp/views.py index d12dbac..d8f2e4b 100644 --- a/blogapp/views.py +++ b/blogapp/views.py @@ -21,6 +21,10 @@ class BloggerViewSet(ModelViewSet): + """ Blogger can retrive own details as well as others detail, but can only perform update,delete for own + list: + to get all bloggers + """ http_method_names = ["get", "patch", "delete", "head", "options"] filter_backends = [ DjangoFilterBackend, @@ -42,6 +46,7 @@ class BloggerViewSet(ModelViewSet): permission_classes = [IsAdminUser | (IsAuthenticated & IsSelf)] queryset = Blogger.objects.all() serializer_class = BloggerAdminSerializer + my_tags = ["Blogger"] def get_permissions(self): method = self.request.method @@ -67,6 +72,7 @@ class OwnBlogViewSet(ModelViewSet): ordering_fields = ["title", "created_at"] serializer_class = BlogReadSerializer permission_classes = [IsAdminUser | (IsAuthenticated & IsBlogOwner)] + my_tags = ["Blogger-Blog"] # queryset = Blog.objects.prefetch_related( # 'comments').select_related('creator').all() @@ -100,10 +106,12 @@ class AllBlogVSet(ListModelMixin, GenericViewSet): queryset = Blog.objects.select_related( 'creator').prefetch_related('comments').all() serializer_class = BlogReadSerializer + my_tags = ["All Blogs"] class CommentVSet(ModelViewSet): http_method_names = ["get", "post", "patch", "delete", "option", "head"] + my_tags = ["Blog-Comments"] def get_permissions(self): if self.request.method == 'GET': diff --git a/core/settings/common.py b/core/settings/common.py index 0ad05d2..ac434ab 100644 --- a/core/settings/common.py +++ b/core/settings/common.py @@ -31,6 +31,8 @@ 'django.contrib.messages', 'django.contrib.staticfiles', # 3rd party apps + # 'django.contrib.staticfiles', # required for serving swagger ui's css/js files + 'drf_yasg', # "debug_toolbar", 'rest_framework', 'djoser', @@ -60,6 +62,16 @@ ROOT_URLCONF = 'core.urls' + +SWAGGER_SETTINGS = { + "DEFAULT_AUTO_SCHEMA_CLASS": "blogapp.swagger_schema.CustomAutoSchema", + "LOGIN_URL": 'admin/', + "LOGOUT_URL":'admin/logout', + "OPERATIONS_SORTER":'method', + "TAGS_SORTER":'alpha', + "DOC_EXPANSION":"none", +} + TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', @@ -130,7 +142,9 @@ ), 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticatedOrReadOnly', - ] + ], + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', + 'PAGE_SIZE': 5, } SIMPLE_JWT = { diff --git a/core/urls.py b/core/urls.py index b2090c3..418b1aa 100644 --- a/core/urls.py +++ b/core/urls.py @@ -13,11 +13,37 @@ 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ -from django.conf import settings ,urls +from django.conf import settings, urls from django.contrib import admin from django.urls import path, include from django.conf.urls.static import static +# DRF_YASG +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="Blogapp API", + default_version='v1', + description=""" + # This is the `Blogapp API` documentation + + > ### Here all the api routes are grouped by tags + + """, + # terms_of_service="https://www.google.com/policies/terms/", + # contact=openapi.Contact(email="pritam.chk98@gmail.com"), + # license=openapi.License(name="BSD License"), + ), + public=True, + permission_classes=[permissions.AllowAny], +) +# DRF_YASG + + urlpatterns = [ path('admin/', admin.site.urls), path('auth/', include('djoser.urls')), @@ -25,9 +51,11 @@ # path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), # own app routes path('blogapp/', include("blogapp.urls")), + #FIXME: drf_yasg url + path('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), ] # urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) if settings.DEBUG: import debug_toolbar - urlpatterns+=path("__debug__/", include(debug_toolbar.urls)), \ No newline at end of file + urlpatterns += path("__debug__/", include(debug_toolbar.urls)),