# CREATING VIRTUAL ENVIRONMENT
# windows
py -m venv env
# windows other option
python -m venv env
# linux / Mac OS
vitualenv env
# ACTIVATING ENVIRONMENT
# windows
.\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 django
# alternatively python -m pip install django
pip install python-decouple
pip freeze > requirements.txt
django-admin --version
django-admin startproject main .
add a gitignore file at same level as env folder, and check that it includes .env and /env lines
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 from SECRET_KEY
SECRET_KEY = django-insecure-)=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')
go to terminal
py manage.py migrate
py manage.py runserver
click the link with CTRL key pressed in the terminal and see django rocket.
go to terminal
py manage.py makemigrations
py manage.py migrate
pip install djangorestframework
go to settings.py and add 'rest_framework' app to installed apps
go to terminal
py manage.py startapp student_api
go to settings.py and add 'student_api' app to installed apps
go to student_api.models.py
from django.db import models
class Student(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
number = models.IntegerField(blank=True, null=True)
def __str__(self):
return f"{self.last_name} {self.first_name}"
go to student_api.admin.py
from django.contrib import admin
from .models import Student
# Register your models here.
admin.site.register(Student)
create serializers.py under student_api
from rest_framework import serializers
from .models import Student
class StudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
# fields = ["id", "first_name", "last_name", "number"]
fields = '__all__'
go to student_api.views.py
from django.shortcuts import HttpResponse
from .models import Student
from .serializers import StudentSerializer
from rest_framework import generics
# Create your views here.
def home(request):
return HttpResponse('<h1>API Page</h1>')
class StudentList(generics.ListCreateAPIView):
serializer_class = StudentSerializer
queryset = Student.objects.all()
class StudentOperations(generics.RetrieveUpdateDestroyAPIView):
serializer_class = StudentSerializer
queryset = Student.objects.all()
go to drf.urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('student_api.urls')),
]
go to student_api.urls.py
from django.urls import path
from .views import home, StudentList, StudentOpr
urlpatterns = [
path('', home),
path('student/', StudentList.as_view()),
path('student/<int:pk>/', StudentOpr.as_view(), name="detail"),
]
py manage.py makemigrations
py manage.py migrate
py .\manage.py createsuperuser
pip freeze > requirements.txt
py .\manage.py runserver
pip install django-cors-headers
settings.py
ALLOWED_HOSTS = ['*']
INSTALLED_APPS = [
# ...
'corsheaders',
]
MIDDLEWARE = [
# ...
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
# ...
]
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CORS_EXPOSE_HEADERS = (
'Access-Control-Allow-Origin: *',
)
Permissions determine whether a request should be granted or denied access.
Authorization checks who sends this request.
The default permission policy may be set globally, using the DEFAULT_PERMISSION_CLASSES
setting. For example.
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
You can also set the authentication policy on a per-view, or per-viewset basis, using the APIView
class-based views.
Example:
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
The AllowAny permission class will allow unrestricted access, regardless of if the request was authenticated or unauthenticated.
The IsAuthenticated permission class will deny permission to any unauthenticated user, and allow permission otherwise. This permission is suitable if you want your API to only be accessible to registered users.
The IsAdminUser permission class will deny permission to any user, unless user.is_staff is True in which case permission will be allowed. This permission is suitable if you want your API to only be accessible to a subset of trusted administrators.
The IsAuthenticatedOrReadOnly will allow authenticated users to perform any request. Requests for unauthorised users will only be permitted if the request method is one of the "safe" methods; GET, HEAD or OPTIONS.
This permission class ties into Django's standard django.contrib.auth model permissions. This permission must only be applied to views that have a .queryset property or get_queryset() method.
Similar to DjangoModelPermissions, but also allows unauthenticated users to have read-only access to the API.
This permission class ties into Django's standard object permissions framework that allows per-object permissions on models.
The default authentication schemes may be set globally, using the DEFAULT_AUTHENTICATION_CLASSES setting. For example.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
]
}
You can also set the authentication scheme on a per-view or per-viewset basis, using the APIView class-based views. Example
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = [SessionAuthentication, BasicAuthentication]
This authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients.
In Basic Authentication you need to send always send username and password, in every request in headers. But this is not safe. To handle this issue token authentication was introduced. When a user logged in an authentication is sent as a response. After that in every request this token will be sent in heades instead of password and username.
These tokens should be stored in backend database. We have options to handle the this sequence. Most used case is to create a token when a user logged in and save it in db and then delete this token whenever user logged out.
To use the TokenAuthentication
scheme you'll need to configure the authentication classes to include TokenAuthentication
, and additionally include rest_framework.authtoken
in your INSTALLED_APPS
setting:
go to settings.py and add 'rest_framework.authtoken' into installed apps
INSTALLED_APPS = [
...
'rest_framework.authtoken'
]
go to terminal
py manage.py migrate
navigate to admin dashboard and check Token table
add users, and token to these users
go to postman send Token
go to terminal
py manage.py startapp user_api
go to settings.py and add 'user_api' into installed apps
go to models.py
from django.db import models
# Create your models here.
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
go to serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
class RegistrationSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['username', 'email', 'password']
go to main urls.py, and add following line into urlpatterns
urlpatterns = [
...
path('user/', include('user_api.urls')),
]
go to user_api urls.py
from rest_framework.authtoken.views import obtain_auth_token
from django.urls import path
from .views import registration_view, logout_view
urlpatterns = [
path('login/', obtain_auth_token, name='login'),
path('register/', registration_view, name='register'),
path('logout/', logout_view, name='logout'),
]
go to views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import RegistrationSerializer
from rest_framework.authtoken.models import Token
# Create your views here.
@api_view(['POST'])
def registration_view(request):
if request.method == 'POST':
serializer = RegistrationSerializer(data=request.data)
data = {}
if serializer.is_valid():
password = serializer.validated_data.get('password')
serializer.validated_data['password'] = make_password(password)
user = serializer.save()
token, _ = Token.objects.get_or_create(user=user)
data = serializer.data
data['token'] = token.key
else:
data = serializer.errors
return Response(data)
@api_view(['POST'])
def logout_view(request):
if request.method == 'POST':
request.user.auth_token.delete()
data = {
'message': 'logout'
}
return Response(data)
To implement a custom permission, override BasePermission and implement either, or both, of the following methods: .has_permission(self, request, view) .has_object_permission(self, request, view, obj) The methods should return True if the request should be granted access, and False otherwise.
under student_api create permissions.py
from rest_framework import permissions
class IsAdminOrReadOnly(permissions.IsAdminUser):
def has_permission(self, request, view):
if request.method in permissions.SAFE_METHODS:
return True
else:
return bool(request.user and request.user.is_staff)
class IsAddedByUserOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
else:
return obj.user == request.user or request.user.is_staff
go to student_api models.py and make following amendments
from django.db import models
from django.contrib.auth.models import User
class Student(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
number = models.IntegerField(blank=True, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return f"{self.last_name} {self.first_name}"
Here we added a new field as user which has one to many relation with User table. When we do migrations it will ask what do with current students in our db as they don't have any user currently. When asked you can type 1 and then press enter.
go to terminal
py manage.py makemigrations
py manage.py migrate
go to student_api views.py
from django.shortcuts import HttpResponse
from .models import Student
from .serializers import StudentSerializer
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
# from rest_framework.authentication import SessionAuthentication, BasicAuthentication, TokenAuthentication
from .permissions import IsAdminOrReadOnly, IsAddedByUserOrReadOnly
# from rest_framework.response import Response
# from rest_framework import status
# Create your views here.
def home(request):
return HttpResponse('<h1>API Page</h1>')
class StudentList(generics.ListCreateAPIView):
serializer_class = StudentSerializer
queryset = Student.objects.all()
permission_classes = [IsAdminOrReadOnly]
# authentication_classes = [BasicAuthentication]
def perform_create(self, serializer):
serializer.save(user=self.request.user)
# def create(self, request, *args, **kwargs):
# serializer = self.get_serializer(data=request.data)
# if not serializer.is_valid(raise_exception=False):
# return Response({"message": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
# serializer.validated_data['user'] = request.user
# self.perform_create(serializer)
# headers = self.get_success_headers(serializer.data)
# return Response({"message": "created successfully"}, status=status.HTTP_201_CREATED, headers=headers)
class StudentOperations(generics.RetrieveUpdateDestroyAPIView):
serializer_class = StudentSerializer
queryset = Student.objects.all()
# permission_classes = [IsAuthenticatedOrReadOnly]
# permission_classes = [IsAuthenticated]
permission_classes = [IsAddedByUserOrReadOnly]
USING dj-rest-auth
go to terminal
pip install dj-rest-auth
Add dj_rest_auth
app to INSTALLED_APPS in your django settings.py:
INSTALLED_APPS = (
...,
'rest_framework',
'rest_framework.authtoken',
...,
'dj_rest_auth'
)
Add dj_rest_auth main urls:
urlpatterns = [
...,
path('auth/', include('dj_rest_auth.urls'))
]
Migrate your database
python manage.py migrate
If you want to enable standard registration process you will need to install django-allauth
by using pip install 'dj-rest-auth[with_social]'
.
Add django.contrib.sites
, allauth
, allauth.account
, allauth.socialaccount
and dj_rest_auth.registration
apps to INSTALLED_APPS in your django settings.py:
Add SITE_ID = 1
to your django settings.py
INSTALLED_APPS = (
...,
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'dj_rest_auth.registration',
)
SITE_ID = 1
Add dj_rest_auth.registration urls:
urlpatterns = [
...,
path('auth/registration/', include('dj_rest_auth.registration.urls'))
]
Migrate your database
python manage.py migrate