Skip to content

FatihG34/Blog_App_Django-with_Frontend

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

36 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

✈ FULLSTACK-PROJECT-BLOG-APP ✈

πŸ’» BACKEND πŸ’»

πŸš€ INITIAL SETUP

# CREATING VIRTUAL ENVIRONMENT # windows πŸ‘‡ python -m venv env # linux / Mac OS πŸ‘‡ vitualenv env # ACTIVATING ENVIRONMENT # windows πŸ‘‡ source env/Scripts/activate # linux / Mac OS πŸ‘‡ source env/bin/activate # PACKAGE INSTALLATION # if pip does not work try pip3 in linux/Mac OS pip install djangorestframework pip freeze > requirements.txt django-admin startproject main . # alternatively python -m pip install django pip install python-decouple django-admin --version
# πŸ’¨ If you already have a requirement.txt file, you can install the packages in the file # πŸ’¨ by entering the following commands respectively in the terminal πŸ‘‡ 1-python -m venv env 2-source env/Scripts/activate 3-pip install -r requirements.txt πŸš€ 4-python.exe -m pip install --upgrade pip 5-python manage.py migrate 6-python manage.py createsuperuser 7-python manage.py runserver

πŸ›‘ Secure your project

🚩 .gitignore

βœ” Add a ".gitignore" file at same level as env folder, and check that it includes ".env" and /env lines.

πŸ”Ή Do that before adding your files to staging area, else you will need extra work to unstage files to be able to ignore them.

πŸ”Ή On this page you can create "gitignore files" for your projects.

🚩 Python Decouple

πŸ’» To use python decouple in this project, first install it πŸ‘‡

pip install python-decouple

πŸ’» Go to terminal to update "requirements.txt" πŸ‘‡

pip freeze > requirements.txt

βœ” Create a new file and name as ".env" at same level as env folder

βœ” Copy your SECRET_KEY from settings.py into this .env file. Don't forget to remove quotation marks and blanks from SECRET_KEY

SECRET_KEY=-)=b-%-w+0_^slb(exmy*mfiaj&wz6_fb4m&s=az-zs!1^ui7j

βœ” Go to "settings.py", make amendments below πŸ‘‡

from decouple import config SECRET_KEY = config('SECRET_KEY')

πŸ’» INSTALLING DJANGO REST

πŸ’» Go to terminal πŸ‘‡

python manage.py makemigrations python manage.py migrate pip install djangorestframework

βœ” Go to "settings.py" and add 'rest_framework' app to INSTALLED_APPS

πŸ’» PostgreSQL Setup

πŸ’» To get Python working with Postgres, you will need to install the β€œpsycopg2” moduleπŸ‘‡

pip install psycopg2

πŸ’» Go to terminal to update requirements.txt πŸ‘‡

pip freeze > requirements.txt

βœ” Go to settings.py and add '' app to INSTALLED_APPS

🚩 Install Swagger

πŸ”Ή Explain a sample API reference documentation

πŸ”Ή Swagger is an open source project launched by a startup in 2010. The goal is to implement a framework that will allow developers to document and design APIs, while maintaining synchronization with the code.

πŸ”Ή Developing an API requires orderly and understandable documentation.

πŸ”Ή To document and design APIs with Django rest framework we will use drf-yasg which generate real Swagger/Open-API 2.0 specifications from a Django Rest Framework API.

πŸ“œ You can find the documentation here.

πŸ’» Go to terminal for installation πŸ‘‡

pip install drf-yasg

πŸ’» Go to terminal to update requirements.txt πŸ‘‡

pip freeze > requirements.txt

βœ” Go to "settings.py" and add 'drf_yasg' app to INSTALLED_APPS

βœ” Here is the updated "urls.py" file for swagger. In swagger documentation, those patterns are not up-to-date πŸ‘‡

from django.contrib import admin from django.urls import path # Three modules for swagger: 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="Flight Reservation API", default_version="v1", description="Flight Reservation API project provides flight and reservation info", terms_of_service="#", contact=openapi.Contact( email="rafe@clarusway.com"), # Change e-mail on this line! license=openapi.License(name="BSD License"), ), public=True, permission_classes=[permissions.AllowAny], ) urlpatterns = [ path("admin/", admin.site.urls), # Url paths for swagger: path("swagger(<format>\.json|\.yaml)", 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="schemaredoc"), ]

πŸ’» MIGRATE πŸ‘‡

python manage.py migrate

πŸš€ RUNSERVER πŸ‘‡

python manage.py runserver

πŸ”΄ If you have this problem πŸ‘‰ ( return Database.Cursor.execute(self, query, params) sqlite3.OperationalError:) when you create "superuser" you should write this command πŸ‘‡

python manage.py migrate --run-syncdb

βœ” After running the server, go to swagger page and redoc page of your project!

🚩 INSTALL DEBUG TOOLBAR πŸ‘‡

πŸ”Ή The Django Debug Toolbar is a configurable set of panels that display various debug information about the current request/response and when clicked, display more details about the panel’s content.

πŸ“œ See the Django Debug Toolbar documentation page.

πŸ’» For Installation go to terminal πŸ‘‡

pip install django-debug-toolbar

πŸ’» Go to terminal to update "requirements.txt" πŸ‘‡

pip freeze > requirements.txt

βœ” Go to "settings.py" and add 'debug_toolbar' app to INSTALLED_APPS

🚩 Add django-debug-toolbar’s URLs to your project’s URLconf πŸ‘‡

from django.urls import include urlpatterns = [ # ... path('__debug__/', include('debug_toolbar.urls')), ]

🚩 Add the middleware to the top πŸ‘‡

MIDDLEWARE = [ "debug_toolbar.middleware.DebugToolbarMiddleware", # ... ]

🚩 Add configuration of internal IPs to "settings.py" πŸ‘‡

INTERNAL_IPS = [ "127.0.0.1", ]

🚩 ADDING AN APP

πŸ’» Go to terminal πŸ‘‡

python manage.py startapp blog

βœ” Go to "settings.py" and add 'blog' app to "INSTALLED_APPS"

πŸ’» INSTALL DJ-REST-AUTH

pip install dj-rest-auth

πŸ’» Go to terminal to update "requirements.txt" πŸ‘‡

pip freeze > requirements.txt

🚩 Add "dj_rest_auth" app to "INSTALLED_APPS" in your django "base.py" πŸ‘‡

 'rest_framework', 'rest_framework.authtoken', 'dj_rest_auth',

🚩 Go to "main/urls.py" and add the path πŸ‘‡

path('auth/', include('user.urls'))

βœ” Create "api" folder under "blog" App. πŸ‘‰ Then create "urls.py", "serializers.py" and "views.py" files under "api" folder πŸ‘‡

🚩 Go to "users/urls.py" and add πŸ‘‡

from django.urls import path, include urlpatterns = [ path('auth/', include('dj_rest_auth.urls')), ]

πŸ’» Migrate your database

python manage.py migrate

🚩 Start Models in "Blog" app πŸ‘‡

from django.db import models from django.conf import settings User = settings.AUTH_USER_MODEL class Category(models.Model): name = models.CharField(max_length=50) def __str__(self): return self.name class BlogPost(models.Model): STATUS = ( ("d", "DRAFT"), ("p", "PUBLISHED"), ) title = models.CharField(max_length=100) author = models.ForeignKey(User, related_name="post_user", on_delete=models.CASCADE) category = models.ForeignKey(Category, related_name="post_category", on_delete=models.CASCADE) content = models.TextField() image = models.URLField(max_length=200, blank=True, default="https://robohash.org/9c681a48b0ef374675df3ca8d6b014a5?set=set4&bgset=&size=400x400") published_date = models.DateTimeField(auto_now_add=True, blank=True) last_updated_date = models.DateTimeField(auto_now=False, blank=True) status = models.CharField(max_length=50, choises=STATUS) #! We use slug for the fields we want to appear instead of ID πŸ‘‡ slug = models.SlugField() def __str__(self): return self.title class Like(models.Model): user = models.ForeignKey(User, related_name="like_user", on_delete=models.CASCADE) post = models.ForeignKey(BlogPost, related_name="like_post", on_delete=models.CASCADE) def __str__(self): return self.user.username class Comment(models.Model): content = models.TextField() time_stamp = models.DateTimeField(auto_now_add=True, blank=True) user = models.ForeignKey(User, related_name="comment_user", on_delete=models.CASCADE) post = models.ForeignKey(BlogPost, related_name="comment_post", on_delete=models.CASCADE) def __str__(self): return self.user.username class Post_view(models.Model): user = models.ForeignKey(User, related_name="post_viewed_user", on_delete=models.CASCADE) post = models.ForeignKey(BlogPost, related_name="viewed_post", on_delete=models.CASCADE) viewed_date_time = models.DateTimeField(auto_now_add=True, blank=True)

πŸ’» Migrate your database πŸ‘‡

python manage.py migrate

🚩 Create "user" app and add "INSTALLED_APP"

🚩 Go to "models.py" in "user" app and add πŸ‘‡

from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): image = models.URLField(max_length=200, blank=True) bio = models.TextField(blank=True)

🚩 Register the model in "admin.py" πŸ‘‡

from django.contrib import admin from .models import User admin.site.register(User)

🚩 Go "main/settings.py" and add πŸ‘‡

AUTH_USER_MODEL = 'user.User'

🚩 Create "serializers.py" file under "user" app and add πŸ‘‡

from rest_framework import serializers, validators from django.contrib.auth import get_user_model from django.contrib.auth.password_validation import validate_password from dj_rest_auth.serializers import TokenSerializer User = get_user_model() class RegisterSerializer(serializers.ModelSerializer): email = serializers.EmailField( required=True, validators=[validators.UniqueValidator(queryset=User.objects.all())] ) password = serializers.CharField( write_only=True, required=True, validators=[validate_password], style={"input_type": "password"} ) password1 = serializers.CharField( write_only=True, required=True, validators=[validate_password], style={"input_type": "password"} ) class Meta: model = User fields = ( 'username', 'email', 'first_name', 'last_name', 'password', 'password1', 'image', 'bio' ) def validate(self, data): if data['password'] != data['password1']: raise serializers.ValidationError( {"password": "Password didn't match..... "} ) return data def create(self, validated_data): password = validated_data.pop("password") validated_data.pop('password1') user = User.objects.create(**validated_data) user.set_password(password) user.save() return user class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ( 'username', 'email' ) class CustomTokenSerializer(TokenSerializer): user = UserSerializer(read_only=True) class Meta(TokenSerializer.Meta): fields = ( 'key', 'user' )

πŸ”΄ SIGNALS πŸ‘‡

πŸ”Ή Django include a β€œsignal dispatcher” which helps decoupled applications get notified when actions occur elsewhere in the framework.

πŸ”Ή In nutshell, signals allow certain senders to notify a set of receivers that some action has taken place.

πŸ”Ή They’re especially useful when many pieces of code may be interested in the same events.

πŸ”΄ Listening to signals πŸ‘‰ Parameters:

πŸ”Ή receiver: The callback function which will be connected to this signal. See Receiver functions for more information.

πŸ”Ή sender: Specifies a particular sender to receive signals from. See Connecting to signals sent by specific senders for more information.

πŸ”Ή weak: Django stores signal handlers as weak references by default. Thus, if your receiver is a local function, it may be garbage collected. To prevent this, pass weak=False when you call the signal’s connect() method.

πŸ”Ή dispatch_uid: A unique identifier for a signal receiver in cases where duplicate signals may be sent. See Preventing duplicate signals for more information.

🚩 Create "signals.py" file under "user" app and add πŸ‘‡

from django.db.models.signals import post_save from django.dispatch import receiver from rest_framework.authtoken.models import Token from django.contrib.auth import get_user_model User = get_user_model() @receiver(post_save, sender=User) def create_token(sender, instance=None, created=False, **kwargs): if created: Token.objects.create(user=instance)

🚩 Go to "apps.py" and add this under UsersConfig() πŸ‘‡

def ready(self): import user.signals

🚩 Go to "views.py" and create RegisterView() πŸ‘‡

from rest_framework import generics, status from rest_framework.response import Response from rest_framework.authtoken.models import Token from .serializers import RegisterSerializer from django.contrib.auth import get_user_model User = get_user_model() class RegisterView(generics.CreateAPIView): queryset = User.objects.all() serializer_class = RegisterSerializer def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.save() data = serializer.data if Token.objects.filter(user=user).exists(): token = Token.objects.get(user=user) data['token'] = token.key else: data['error'] = 'User dont have token. Please login' headers = self.get_success_headers(serializer.data) return Response(data, status=status.HTTP_201_CREATED, headers=headers)

🚩 Create "urls.py" file under "user" app and add πŸ‘‡

from django.urls import path, include from .views import RegisterView urlpatterns = [ path('', include('dj_rest_auth.urls')), path('register/', RegisterView.as_view()) ]

βœ” Create "serializers.py" file under "User" app and add πŸ‘‡

from rest_framework import serializers, validators from django.contrib.auth.models import User from django.contrib.auth.password_validation import validate_password class RegisterSerializer(serializers.ModelSerializer): email = serializers.EmailField( required = True, validators=[validators.UniqueValidator(queryset=User.objects.all())] ) password = serializers.CharField( required = True, write_only = True, validators = [validate_password], style = {"input_type":"password"} ) password1 = serializers.CharField( required = True, write_only = True, validators = [validate_password], style = {"input_type":"password"} ) class Meta: model = User fields = ( "username", "email", "first_name", "last_name", "password", "password1", ) def validate(self, data): if data["password"] != data["password1"]: raise serializers.ValidationError( {"password": "Password must be same with above !..."} ) return data def create(self, validated_data): password = validated_data.pop("password") validated_data.pop("password1") user = User.objects.create(**validated_data) user.set_password(password) user.save() return user

🚩 Go to "user/api/views.py" and create RegisterView() πŸ‘‡

from rest_framework import generics from django.contrib.auth.models import User from .serializers import RegisterSerializer class RegisterView(generics.CreateAPIView): queryset = User.objects.all() serializer_class = RegisterSerializer def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) user = serializer.save() data = serializer.data if Token.objects.filter(user=user): token = Token.objects.get(user=user) data['token'] = token.key else: data['error'] = 'User does not have token . Try again ...' headers = self.get_success_headers(serializer.data) return Response(data, status=status.HTTP_201_CREATED, headers=headers)

🚩 Go to "urls.py" and add the path πŸ‘‡

from users.api.views import RegisterView path('register/', RegisterView.as_view()),

🚩 Go to "user/api/serializers.py" and add UpdateUserSerializerπŸ‘‡

class UpdateUserSerializer(serializers.ModelSerializer): email = serializers.EmailField( required=True, validators=[validators.UniqueValidator(queryset=User.objects.all())] ) class Meta: model = User fields = ( "username", "id", "email", "first_name", "last_name", "profile_pic", "biography", )

🚩 Go to user/api/views.py and add "UpdateUserView" πŸ‘‡

class UpdateUserView(generics.RetrieveUpdateAPIView): #! We used RetrieveUpdateAPIView so that the user can only update. πŸ‘† queryset = User.objects.all() serializer_class = UpdateUserSerializer

πŸ‘‡ Go to "user/api/urls.py" and add the path πŸ‘‡

path('update-profile/<int:pk>', UpdateUserView.as_view()),

✏ Create "api" folder under "blog" app and add the "views, serializers, urls" files.

🚩 Create models in "models.py" under "blog" app πŸ‘‡

from django.db.models.signals import pre_save from django.dispatch import receiver from django.db import models from django.conf import settings from django.template.defaultfilters import slugify from blog.api.utils import get_random_code User = settings.AUTH_USER_MODEL class Category(models.Model): name = models.CharField(max_length=50) def __str__(self): return self.name class BlogPost(models.Model): STATUS = ( ("d", "DRAFT"), ("p", "PUBLISHED"), ) title = models.CharField(max_length=100) author = models.ForeignKey( User, related_name="post_user", on_delete=models.PROTECT, default='Anonymous User') category = models.ForeignKey( Category, related_name="post_category", on_delete=models.CASCADE) content = models.TextField() # image = models.ImageField(upload_to=None, height_field=None, width_field=None, max_length=None) image = models.URLField(max_length=200, blank=True, default="https://gravatar.com/avatar/2074b7945e3c6c493b0b2b94b24c35c2?s=400&d=robohash&r=x") published_date = models.DateTimeField(auto_now_add=True, blank=True) last_updated_date = models.DateTimeField(auto_now=True, blank=True) status = models.CharField(max_length=2, choices=STATUS) slug = models.SlugField(blank=True, null=True) def __str__(self): return self.title class Like(models.Model): user = models.ForeignKey( User, related_name="like_user", on_delete=models.PROTECT) post = models.ForeignKey( BlogPost, related_name="like_post", on_delete=models.CASCADE) def __str__(self): return self.user class Comment(models.Model): content = models.TextField() time_stamp = models.DateTimeField(auto_now_add=True, blank=True) user = models.ForeignKey(User, related_name="comment_user", on_delete=models.PROTECT, default='Anonymous User') post = models.ForeignKey( BlogPost, related_name="comment_post", on_delete=models.CASCADE) def __str__(self): return self.user class Post_view(models.Model): user = models.ForeignKey( User, related_name="post_viewed_user", on_delete=models.PROTECT) post = models.ForeignKey( BlogPost, related_name="viewed_post", on_delete=models.CASCADE) viewed_date_time = models.DateTimeField(auto_now_add=True, blank=True)

🚩 Register the models in "admin.py" πŸ‘‡

from django.contrib import admin from blog.models import BlogPost, Category, Comment, Like, Post_view admin.site.register(Category) admin.site.register(Like) admin.site.register(BlogPost) admin.site.register(Comment) admin.site.register(Post_view)

🚩 Create "signals.py" file under "blog/api" folder and add πŸ‘‡

from django.db.models.signals import pre_save from django.dispatch import receiver from django.template.defaultfilters import slugify from blog.models import BlogPost from .utils import get_random_code @receiver(pre_save, sender=BlogPost) def pre_save_create_slug(sender, instance,**kwargs): if not instance.slug: instance.slug = slugify(instance.title + " " + get_random_code())

🚩 Create "utils.py" file under "blog/api" folder and add πŸ‘‡

import uuid #! πŸ‘† user uniqe id => Slug field must be uniqe def get_random_code(): code = str(uuid.uuid4())[:11].replace("-","") return code

🚩 Customize the BlogConfig() in "apps.py" in "blog"app πŸ‘‡

from django.apps import AppConfig class BlogConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "blog" def ready(self): import blog.api.signals

🚩 Go to "api/serializers.py" under "blog" app πŸ‘‡

from rest_framework import serializers from blog.models import BlogPost, Category, Comment, Like, Post_view from users.api.serializers import UserSerializer from django.contrib.auth import get_user_model # User = settings.AUTH_USER_MODEL User = get_user_model() # class AllUserSerializer(serializers.ModelSerializer): # class Meta: # model = User # fields = ( # "username", # "first_name", # "last_name", # "profile_pic", # "biography" # ) class CategorySerializer(serializers.ModelSerializer): class Meta: model = Category fields = ( 'id', 'name' ) class CommentSerializer(serializers.ModelSerializer): # user = serializers.StringRelatedField(read_only=True) # user_id = serializers.IntegerField() # post = serializers.StringRelatedField() # post_id = serializers.IntegerField() # class Meta: # model = Comment # fields = "__all__" # kimin yorum yaptığını belirtmek için ilave edildi user = serializers.StringRelatedField(read_only=True) class Meta: model = Comment fields = ( "id", "content", "time_stamp", "user", ) class LikeSerializer(serializers.ModelSerializer): # like_user = AllUserSerializer(many=True, read_only=True) user = serializers.StringRelatedField() user_id = serializers.IntegerField() class Meta: model = Like fields = ( "id", "user", "user_id", "post", # "like_user" ) class BlogPostSerializer(serializers.ModelSerializer): comment_post = CommentSerializer(many=True, read_only=True) like_post = LikeSerializer(many=True, read_only=True) category = serializers.StringRelatedField(read_only=True) category_id = serializers.IntegerField() author = serializers.StringRelatedField(read_only=True) author_id = serializers.IntegerField(read_only=True) like_count = serializers.SerializerMethodField() comment_count = serializers.SerializerMethodField() post_view_count = serializers.SerializerMethodField() class Meta: model = BlogPost fields = ( "id", "title", "author", "author_id", "category_id", "category", "content", "image", "published_date", "last_updated_date", "status", "slug", "like_count", "comment_count", "post_view_count", "comment_post", "like_post", ) read_only_fields = ( "published_date", "updated_date", "slug", ) def get_like_count(self, obj): return Like.objects.filter(post=obj.id).count() def get_comment_count(self, obj): return Comment.objects.filter(post=obj.id).count() def get_post_view_count(self, obj): return Post_view.objects.filter(post=obj.id).count()

🚩 Go to "api/views.py" under blog app πŸ‘‡

from rest_framework import permissions from rest_framework.exceptions import ValidationError from rest_framework.generics import get_object_or_404 from rest_framework import generics, status from blog.api.pagination import CustomLimitOffsetPagination from blog.api.permissions import IsAdminUserOrReadOnly, IsPostOwnerOrReadOnly from blog.api.serializers import BlogPostSerializer, CategorySerializer, CommentSerializer,LikeSerializer from rest_framework.response import Response from blog.models import BlogPost, Category, Post_view, Comment, Like class CategoryView(generics.ListCreateAPIView): queryset = Category.objects.all() serializer_class = CategorySerializer permission_classes = [IsAdminUserOrReadOnly] class BlogPostView(generics.ListCreateAPIView): queryset = BlogPost.objects.all() serializer_class = BlogPostSerializer pagination_class = CustomLimitOffsetPagination permission_classes = [permissions.IsAuthenticatedOrReadOnly] def perform_create(self, serializer): serializer.save(author=self.request.user) class BlogPostDetailView(generics.RetrieveUpdateDestroyAPIView): queryset = BlogPost.objects.all() serializer_class = BlogPostSerializer lookup_field = "slug" permission_classes = [IsPostOwnerOrReadOnly] def retrieve(self, request, *args, **kwargs): instance = self.get_object() serializer = self.get_serializer(instance) # Post_view.objects.get_or_create(user=request.user, post=instance) Post_view.objects.create(user=request.user, post=instance) return Response(serializer.data) class CommentView(generics.CreateAPIView): queryset = Comment.objects.all() serializer_class = CommentSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly] def perform_create(self, serializer): print(self.kwargs) slug = self.kwargs.get('slug') blog = get_object_or_404(BlogPost, slug=slug) user = self.request.user comments = Comment.objects.filter(post=blog, user=user) if comments.exists(): raise ValidationError( "You can not add another comment, for this Post !") serializer.save(post=blog, user=user) class LikeView(generics.ListCreateAPIView): queryset = Like.objects.all() serializer_class = LikeSerializer def create(self, request, *args, **kwargs): user = request.data.get('user_id') post = request.data.get('post') serializer = self.get_serializer(data=request.data) exists_like = Like.objects.filter(user_id=user, post=post) serializer.is_valid(raise_exception=True) if exists_like: exists_like.delete() else: self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

🚩 Create "permissions.py" file under "api" folder in the "blog" app and add πŸ‘‡

from rest_framework import permissions class IsPostOwnerOrReadOnly(permissions.BasePermission): #! If the request.user is the same as the author, it can update/delete. Otherwise can view πŸ‘‡ def has_object_permission(self, request, view, obj): if request.method in permissions.SAFE_METHODS: return True return request.user == obj.author class IsAdminUserOrReadOnly(permissions.IsAdminUser): #! "Admin" can do any action. If not it can only view πŸ‘‡ def has_permission(self, request, view): is_admin = super().has_permission(request, view) return request.method in permissions.SAFE_METHODS or is_admin

🚩 Create "pagination.py" file under "api" folder in the "blog" app and add πŸ‘‡

from rest_framework.pagination import LimitOffsetPagination #! For 6 posts to appear on each page πŸ‘‡ class CustomLimitOffsetPagination(LimitOffsetPagination): default_limit = 6

🚩 Go to "blog/api/urls.py" and add the path πŸ‘‡

from .views import ( CategoryView, BlogPostView, BlogPostDetailView, CommentView, LikeView ) from django.urls import path from rest_framework import routers urlpatterns = [ path("category/", CategoryView.as_view()), path("posts/", BlogPostView.as_view()), path("like/", LikeView.as_view()), path("posts/<str:slug>/", BlogPostDetailView.as_view()), path("posts/<str:slug>/add_comment/", CommentView.as_view()), ]

πŸ“’ Do not forget to check the endpoints you wrote in Postman.

πŸ₯³ END OF THE BACKEND πŸ₯³


πŸ“’ FOR DJANGO DEPLOYMENT YOU CAN USE "PYTHON ANY WHERE"

πŸ’» Commands for setup πŸ‘‡

 git clone https://github.com/githubUserName/projectName.git cd projectName python -m venv env source env/bin/activate pip install --upgrade pip pip install -r requirements.txt echo SECRET_KEY=write_random_chars_to_here > .env python manage.py migrate $ python manage.py createsuperuser # optional

πŸ’» Command for learn to current path πŸ‘‡

 pwd
  • "Add New Web App" with ManualConfigration with Python_LastVersion

  • Set "Source Code" with "Main Path" (example: /home/anyWhereUserName/ProjectName)

  • Set "Working Directory" with "Main Path" (example: /home/anyWhereUserName/ProjectName)

  • Set "VirtualEnv" with "Env Path" (example: /home/anyWhereUserName/ProjectName/env)

🚩 pythonanywhere/Web -> WSGI Configuration File(pythonanywhere_com_wsgi.py) πŸ‘‡

 import os import sys # Set: Project Main Path: path = '/home/anyWhereUserName/ProjectName' if path not in sys.path: sys.path.append(path) # Set: Where is settings.py: os.environ['DJANGO_SETTINGS_MODULE'] = 'projectFolderName.settings' from django.core.wsgi import get_wsgi_application application = get_wsgi_application()

πŸ‘ Finished 😎

β€Ό Don't forget πŸ‘‰ click to 'Reload' button before publish.

if error, checking: settting.py: ALLOWED_HOSTS = ['*'] # folder -> static-files-path: STATIC_URL = 'static/' # root -> static-files-path: STATIC_ROOT = BASE_DIR / STATIC_URL # Alternates: # if in base folder -> STATIC_ROOT = BASE_DIR / 'static/' # if in app folder -> STATIC_ROOT = BASE_DIR / 'appFolderName/static/' urls.py: from django.conf import settings from django.conf.urls.static import static # url -> static-files-path: urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 

FOR REACT CONFIGURATION

πŸ’» Install "cors-headers" for connecting with Frontend πŸ‘‡

βœ” DJANGO-CORS-HEADERS βœ”


πŸ”‘ A Django App that adds Cross-Origin Resource Sharing (CORS) headers to responses.

πŸ”‘ This allows in-browser requests to your Django application from other origins.

πŸ”‘ Adding CORS headers allows your resources to be accessed on other domains.

πŸ”‘ It's important you understand the implications before adding the headers, since you could be unintentionally opening up your site's private data to others.

πŸ’» To install cors-headers πŸ‘‡

pip install django-cors-headers

βœ” Add 'corsheaders' to "INSTALLED_APPS" in "settings.py" file.

🚩 You will also need to add a middleware class to listen in on responses πŸ‘‡

MIDDLEWARE = [ ..., "corsheaders.middleware.CorsMiddleware", ..., ]

🚩 To allow all origins; add πŸ‘‡

CORS_ALLOW_ALL_ORIGINS=True

🚩 Add a list of HTTP verbs that are allowed for the actual request πŸ‘‡

CORS_ALLOW_METHODS = [ "DELETE", "GET", "OPTIONS", "PATCH", "POST", "PUT", ]

πŸ’» Runserver πŸ‘‡

python manage.py runserver

πŸ’» Open the React Project and start it πŸ‘‡

yarn start

******************************************************

About

No description or website provided.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages