This section lists commonly used commands when working with Django projects.
--
1. Create a Django Project
$ django-admin startproject project_1
2. Create a Django App
$ django-admin app first_app
3. Run the Django Development Server
$ python manage.py runserver
4. Convert Python Models to SQL Schema
$ python manage.py makemigrations
5. Apply Migrations to the Database
$ python manage.py migrate
6. Create Admin
$ python manage.py createsuperuser
--
Bootstrap5 template pack for django-crispy-forms Go
$ pip install crispy-bootstrap5
INSTALLED_APPS = (
...
"crispy_forms",
"crispy_bootstrap5",
...
)
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
{% load crispy_forms_tags %}
{% form | crispy %}
Used to configure how Django handles static files like CSS, JavaScript, and images.
STATIC_URL = 'static/'
STATICFILES_DIRS = [
BASE_DIR/'static',
]
{% load static %}
<src href="{% static 'photo.png' %}">
# URL to access media files in development in app
MEDIA_URL = '/media/'
# The directory on your server where media files are stored in root file.
MEDIA_ROOT = BASE_DIR / 'media'
from django.conf import settings
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)class Document(models.Model):
title = models.CharField(max_length=100)
file = models.FileField(upload_to='documents/') # Files will be stored in MEDIA_ROOT/documents/class DocumentForm(forms.ModelForm):
class Meta:
model = Document
fields = ['title', 'file']def upload_file(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES) # Include request.FILES for file uploads
if form.is_valid():
form.save()
return redirect('file_list')
else:
form = DocumentForm()
return render(request, 'upload_file.html', {'form': form})
def file_list(request):
documents = Document.objects.all()
return render(request, 'file_list.html', {'documents': documents})<h1>Upload File</h1>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form><h1>Uploaded Files</h1>
<ul>
{% for document in documents %}
<li>
{{ document.title }} - <a href="{{ document.file.url }}">Download</a>
</li>
{% endfor %}
</ul>EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com' # For Gmail
EMAIL_PORT = 587
EMAIL_HOST_USER = 'almamun20044@gmail.com'
EMAIL_HOST_PASSWORD = 'xdsblb-jdnr-wxqaeh'
EMAIL_USE_TLS = True
EMAIL_USE_SSL = Falsesend_mail(
subject='Welcome to LibZone',
message=f"Your OTP is {otp}. Please use this to reset your password.",
from_email='Refresh Bank noreply@libzone.com',
recipient_list=[user.email],
fail_silently=False,
)from django.core.mail import send_mail, EmailMultiAlternatives
from django.template.loader import render_to_string
context = {
'user': request.user,
}
body = render_to_string('templates/login_email.html',context) # Adds alternative HTML content
email = EmailMultiAlternatives(
subject="Login successful",
body='',
from_email= 'ReFresh Bank <noreply@example.com>',
to = [user.email],
)
email.attach_alternative(body, "text/html")
email.send()# Adds an attachment.
email.attach('example.pdf', b'PDF content here', 'application/pdf')
is used to ensure that a view can only be accessed by authenticated (logged-in) users. If a user is not logged in and tries to access a view that is decorated with @login_required, they are redirected to the login page.
LOGIN_URL = '/user/login/'from django.contrib.auth.decorators import login_required
@login_required(login_url='/user/login/')
@login_requireddef set_cookie_view(request):
// response = HttpResponse("Cookie Set")
response = render(request,'home.html')
response.set_cookie('username', 'AN_Mamun', max_age=3600) # Expires in 1 hour
return responsedef read_cookie_view(request):
username = request.COOKIES.get('username', 'Guest')
return HttpResponse(f"Hello, {username}!")def delete_cookie_view(request):
response = HttpResponse("Cookie Deleted")
response.delete_cookie('username')
return responseMethods : .keys(), .values(), items(),
SESSION_ENGINE : Backend to use (e.g., database, file-based, cache).
SESSION_COOKIE_NAME : Name of the session cookie.
SESSION_COOKIE_AGE : Expiry age of the session cookie (default: 1209600 seconds or 2 weeks).
SESSION_EXPIRE_AT_BROWSER_CLOSE : Boolean; if True, the session expires when the browser is closed.
SESSION_SAVE_EVERY_REQUEST : Boolean; if True, the session is saved to the database on every request.['key'] : Set a session value.
get('key', default=None) : Get a session value with an optional default.
pop('key', default=None) : Remove a session key and return its value.
clear() : Clears expired sessions from the database.
flush() : Remove the session and create a new empty session (useful for logout).
modified : Set this to True to force a session save.
clear_expired() : Remove expired sessions.
set_test_cookie() : Sets a test cookie to check browser cookie support.
set_expiry(value) : Sets the session expiry time.
exists(session_key) : Check if a session key exists.
get_session_cookie_age() : Returns the session cookie's age in seconds.
get_expiry_date() : Returns the expiry date and time of the session as a datetime object.
get_expiry_age() : Returns the number of seconds until the session expires.
get_expire_at_browser_close() : Returns True if the session expires when the browser closes.
test_cookie_worked() :Return boolean , Checks if the test cookie works.
delete_test_cookie() :Deletes the test cookie.last_activity = request.session.get('last_activity')
# Set session expiry to 1 hour (3600 seconds)
def set_session_expiry(request):
request.session.set_expiry(3600) # Expires after 1 hour
return render(request, 'home.html')
--
# cookie will expire in 7 days from when the user visits the page.
def home(request):
response = render(request,'home.html')
// response.set_cookie('name','AN_Mamun',max_age=60)
response.set_cookie('name','AN_Mamun',expires=datetime.utcnow()+timedelta(days=7))
return response
django.contrib.auth.views import Auth-Views
django.views.generic import Generic-Base, Edit, Details, List, Dates
| Auth Views ? | Generic base ? | Generic edit ? | Generic detail ? | Generic list ? | Generic dates ? |
|---|---|---|---|---|---|
| LoginView | RedirectView | CreateView | DetailView | ListView | ArchiveIndexView |
| PasswordChangeDoneView | TemplateView | DeleteView | DateDetailView | ||
| PasswordChangeView | View | FormView | DayArchiveView | ||
| PasswordResetCompleteView | UpdateView | MonthArchiveView | |||
| PasswordResetConfirmView | TodayArchiveView | ||||
| PasswordResetDoneView | WeekArchiveView | ||||
| PasswordResetView | YearArchiveView |
Purpose: Handles user login.
When to Use:
• To render a login form and authenticate users.
• To log users in and redirect them to a specified page.
• Attributes: template_name, redirect_authenticated_user, authentication_form, next_page, get_success_url()
Purpose: Logs out the user and redirects them to a specified page.
When to Use:
• To log users out.
• To clear session data.
• Attributes: next_page, template_name, get_next_page()
Purpose: Allows authenticated users to change their password.
When to Use:
• To let logged-in users update their passwords.
• Attributes: template_name, form_class, success_url, get_success_url()
Purpose: Confirms that the password has been changed successfully.
When to Use:
• To show a success message after the password is changed.
• Attributes: template_name
Purpose: Allows users to request a password reset via email.
When to Use:
• To initiate the password reset process.
• Sends an email to the user with a reset link.
• Attributes: template_name, email_template_name, subject_template_name, form_class, success_url, get_success_url()
Purpose: Displays a confirmation that the password reset email was sent.
When to Use:
• After a user requests a password reset.
• Attributes: template_name
Purpose: Allows users to set a new password using a reset link.
When to Use:
• After the user clicks the link in the password reset email.
• Attributes: template_name, form_class, success_url, get_success_url()
Purpose: Confirms that the password reset process is complete.
When to Use:
• After a user successfully resets their password.
• Attributes: template_name
Purpose: Logs out the user and redirects them to the login page.
When to Use:
• To provide "logout and redirect to login" functionality in one step.
• Attributes: template_name, next_page, get_redirect_url()
Purpose: Base class for all views. It doesn't perform any specific actions by itself but provides a foundation for building views.
When to Use:
• When you need full control over logic.
• It is the most customizable option for creating views.
• Use it when you want to define your own logic for handling requests and responses.
• It provides hooks like dispatch(), get(), post() for handling HTTP methods.
Purpose: Render a template.
When to Use:
• For static or minimally dynamic pages.
• Simplifies rendering templates without requiring custom logic.
• Use it when your view needs only to serve static data or simple dynamic content using templates.
Attributes: template_name, get_context_data()
Purpose: Perform HTTP redirects.
When to Use:
• To redirect users to another URL.
• Use it when you want to redirect users to another URL (either static or dynamic).
• Handles permanent (301) and temporary (302) redirects.
Attributes: url, pattern_name, permanent
Purpose: Handles the creation of new objects in the database.
When to Use:
• When you want to display a form for creating an object.
• Automatically saves valid form data to the database.
• Simplifies object creation with default implementation.
Attributes: template_name, form_class, model, fields, success_url, get_success_url()
Purpose: Handles the deletion of objects from the database.
When to Use:
• When you need a confirmation page for deleting an object.
• Automatically deletes the object when confirmed.
Attributes: template_name, model, success_url, object
Purpose: Handles form processing without being tied to a specific model.
When to Use:
• When you want to handle forms with custom logic (not linked to a model).
• Useful for forms that perform non-database actions (e.g., search forms, contact forms).
Attributes: template_name, form_class, success_url, get_success_url()
Purpose: Handles updating existing objects in the database.
When to Use:
• When you need to display a form for updating an existing object.
• Automatically saves the updated data to the database.
Attributes: template_name, form_class, fields, success_url, get_success_url()
def get_object(self, queryset = None): # to ensure that the profile you're updating belongs to the currently logged-in user
class UpdateProfileView(UpdateView):
template_name = 'profile/profile_setting.html'
model = Profile
form_class = UpdateUserProfileForm
success_url = reverse_lazy('profile')
def get_object(self, queryset = None):
return self.request.user.profile
Purpose: Displays detailed information about a specific object from the database.
When to Use:
• When you want to display detailed information about a single object (e.g., a product, blog post, or user profile).
• To fetch an object from the database based on its primary key or slug and render it using a template.
• Attributes: model, template_name, context_object_name, slug_field, slug_url_kwarg, pk_url_kwarg, get_context_data()
Purpose: Displays a list of objects from a database model.
When to Use:
• When you want to display a list of objects, such as blog posts, products, or any other model-based items.
• Automatically handles pagination for large datasets.
• It can filter and order results using query parameters.
• Attributes: model, template_name, context_object_name, paginate_by, ordering, get_queryset()
Purpose: This view is used for displaying a list of archived objects based on a particular time period (e.g., all objects from a certain year, month, or day). It provides a starting point for time-based views like year-based, month-based, etc.
When to Use:
• When you want to show a list of archived data organized by date.
• Typically used when displaying all objects in a particular time range (e.g., all blog posts published in a year).
• Attributes: date_field, template_name, context_object_name
Purpose: This view is used to display a detail view for a particular object within a specified date range (such as an object published on a specific day).
When to Use:
• When you need to show a single object that corresponds to a specific date (e.g., a blog post published on a particular day).
• Attributes: date_field, template_name, context_object_name
Purpose: This view is used for displaying all objects that were published on a specific day.
When to Use:
• When you want to display a list of objects published on a particular day (e.g., a list of blog posts for a specific date).
• Attributes: date_field, month_format, template_name
Purpose: This view is used for displaying all objects published within a specific month and year.
When to Use:
• When you need to display a list of objects for a particular month (e.g., blog posts published in January).
• Attributes: date_field, template_name, month_format
Purpose: This view is used for displaying all objects published today.
When to Use:
• When you want to show objects created or published today.
• Attributes: date_field, template_name
Purpose: This view is used for displaying all objects that were published within a specific week.
When to Use:
• When you want to show a list of objects published within a particular week (e.g., blog posts published between Monday and Sunday of a week).
• Attributes: date_field, template_name
Purpose: This view is used for displaying all objects published in a particular year.
When to Use:
• When you want to show a list of objects published within a specific year (e.g., all blog posts from 2023).
• Attributes: date_field, template_name
pip install psycopg2
import dj_database_url
import environ
env = environ.Env()
environ.Env.read_env()
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': env("DB_NAME"),
'USER': env("DB_USER"),
'PASSWORD': env("DB_PASSWORD"),
'HOST': env("DB_HOST"),
'PORT': env("DB_PORT"),
}
}
ALLOWED_HOSTS = ["*"]
CSRF_TRUSTED_ORIGINS = ['https://libzone-app.onrender.com','https://*.127.0.0.1']
SECRET_KEY=django-insecure-kyh%asdfqrysd245e^b2e5lu0f68_vt2345asdfa370%$5n&7
DB_NAME=libzone
DB_USER=postgres
DB_PASSWORD=1223
DB_HOST=localhost
DB_PORT=5432
EMAIL_HOST_USER=almamun20044@gmail.com
EMAIL_HOST_PASSWORD=xdsblb-jdnr-wxqaeh #next
Your current payment view is not returning an HTTP response, which will cause an error. You need to redirect the user to the SSLCommerz payment gateway URL instead of just returning it as plain text.
from django.http import HttpResponse ,JsonResponse
from django.shortcuts import redirect, render
from rest_framework.response import Response
from django.contrib.auth.models import User
from datetime import datetime
from sslcommerz_lib import SSLCOMMERZ
import uuid # To generate unique transaction ID
from django.views.decorators.csrf import csrf_exempt
from rest_framework.decorators import api_view
@csrf_exempt
def payment(request, user_id):
print('abcd',user_id)
settings = {
'store_id': 'ancod6799f7f3afcfa',
'store_pass': 'ancod6799f7f3afcfa@ssl',
'issandbox': True # Set to False for production
}
try:
user = User.objects.get(pk=user_id) # Fix: Use `id=int(user_id)`
except User.DoesNotExist:
return HttpResponse("User -- not found.", status=404)
sslcz = SSLCOMMERZ(settings)
# Generate unique transaction ID
transaction_id = str(uuid.uuid4())
post_body = {
'total_amount': 100.26,
'currency': "BDT",
'tran_id': transaction_id, # Use unique transaction ID
'success_url': f"http://127.0.0.1:8000/payment/success/{user_id}",
'fail_url': "http://127.0.0.1:8000/payment/fail/",
'cancel_url': "http://127.0.0.1:8000/payment/cancel/",
'emi_option': 0,
'cus_name': user.username,
'cus_email': user.email,
'cus_phone': "01700000000",
'cus_add1': "customer address",
'cus_city': "Dhaka",
'cus_country': "Bangladesh",
'shipping_method': "NO",
'multi_card_name': "",
'num_of_item': 1,
'product_name': "Test",
'product_category': "Test Category",
'product_profile': "general"
}
response = sslcz.createSession(post_body) # API response
print('asdf',user.username)
if 'GatewayPageURL' in response:
return redirect(response['GatewayPageURL']) # Redirect user to payment page
else:
return HttpResponse("Payment gateway initialization failed.", status=400)
@csrf_exempt
def success_view(request, user_id):
try:
user = User.objects.get(id=int(user_id)) # Ensure `user_id` is an integer
except User.DoesNotExist:
return HttpResponse("User not found.", status=404)
context = {
'course_price':course.price,
'payment_date': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
}
return render(request,'payment_success.html',context)
// when view the web will show the api context
@api_view(['GET'])
def success_view(request, user_id):
try:
user = User.objects.get(id=int(user_id)) # Ensure `user_id` is an integer
except User.DoesNotExist:
return Response({"error": "User not found."}, status=404)
return Response({"message": "Payment successful","user": {"id": user.id,"username": user.username,"email": user.email}}, status=200)
@csrf_exempt
def payment(request,user_id,course_id):
if request.method != "POST":
return JsonResponse({"error": "Invalid request method"}, status=405)
print('abcd', user_id,'efgh',course_id)
settings = {
'store_id': 'ancod6799f7f3afcfa',
'store_pass': 'ancod6799f7f3afcfa@ssl',
'issandbox': True # Set to False for production
}
try:
user = User.objects.get(pk=user_id) # Ensure user exists
except User.DoesNotExist:
return JsonResponse({"error": "User not found"}, status=404)
sslcz = SSLCOMMERZ(settings)
# Generate unique transaction ID
transaction_id = str(uuid.uuid4())
post_body = {
'total_amount': 100.26,
'currency': "BDT",
'tran_id': transaction_id, # Unique transaction ID
'success_url': f"http://127.0.0.1:8000/payment/success/{user_id}/{course_id}",
'fail_url': "http://127.0.0.1:8000/payment/fail/",
'cancel_url': "http://127.0.0.1:8000/payment/cancel/",
'emi_option': 0,
'cus_name': user.username,
'cus_email': user.email,
'cus_phone': "01700000000",
'cus_add1': "customer address",
'cus_city': "Dhaka",
'cus_country': "Bangladesh",
'shipping_method': "NO",
'multi_card_name': "",
'num_of_item': 1,
'product_name': "Test",
'product_category': "Test Category",
'product_profile': "general"
}
response = sslcz.createSession(post_body) # API response
print('asdf', user.username)
if 'GatewayPageURL' in response:
return JsonResponse({"url": response['GatewayPageURL']}) # Send URL as JSON
else:
return JsonResponse({"error": "Payment gateway initialization failed"}, status=400) urlpatterns = [
path('pay/<int:user_id>/<int:course_id>/', payment, name='payment'),
path('success/<int:user_id>/<int:course_id>', success_view, name='payment_success'),
path('fail/', fail_view, name='payment_fail'),
path('cancel/', cancel_view, name='payment_cancel'),
]
const initiatePayment = (userId = 10) => {
alert('Payment started');
let course_id = 2;
fetch(`http://127.0.0.1:8000/payment/pay/${userId}/${course_id}/`, {
method: "POST",
headers: {
"Content-Type": "application/json"
}
})
.then(response => response.json()) // Expect JSON response
.then(data => {
if (data.url) {
console.log("Redirecting to:", data.url);
window.location.href = data.url; // Redirect user to SSLCOMMERZ payment page
} else {
console.error("Error:", data.error);
alert("Payment initialization failed: " + data.error);
}
})
.catch(error => console.error("Fetch error:", error));
}
// Call the function when needed (e.g., on a button click)
initiatePayment();
for field in user._meta.fields:
field_name = field.name
field_value = getattr(user, field_name)
print(f"{field_name}: {field_value}")id: 2
password: pbkdf2_sha256$...
last_login: 2025-05-13 13:30:25+00:00
is_superuser: False
username: anmamun0
first_name: AN
last_name: Mamun
email: anmamun0@gmail.com
is_staff: False
is_active: True
date_joined: 2025-05-13 12:20:15+00:00from django.db import models
class Category(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(max_length=100,blank=True,unique=True,null=True)
def __str__(self):
return self.name
class Book(models.Model):
image = models.URLField(max_length=255,null=True, blank=True)
title = models.CharField(max_length=255)
author = models.CharField(max_length=255)
isbn = models.CharField(max_length=13, unique=True) # Unique ISBN number
category = models.ManyToManyField(Category, blank=True,related_name='books')
language = models.CharField(max_length=50,default='Bangla', blank=True, null=True)
description = models.TextField()
copies = models.IntegerField(default=0)
available = models.IntegerField(default=0)
def __str__(self):
return f"{self.isbn} - {self.title}"class BookSerializer(serializers.ModelSerializer):
category = CategorySerializer(many=True, read_only=True) # Read-only nested category
class Meta:
model = Book
fields = "__all__"from rest_framework.authtoken.models import Token
from accounts.models import Profile
class CustomAdminTokenCheckMixin:
def is_admin(self, request):
# its best for safe security
# it will check , Header section has any "Authorization" variable ?
auth_header = request.headers.get('Authorization')
# it will check , Body section has any "token_id" variable ?
token_id = (
request.data.get('token_id') or
request.query_params.get('token_id') or
request.headers.get('token_id')
)
if auth_header and auth_header.startswith('Token '):
token_id = auth_header.split(' ')[1]
if not token_id:
return False
try:
token = Token.objects.get(key=token_id)
user = token.user
profile = Profile.objects.get(user=user)
return profile.role == 'admin'
except (Token.DoesNotExist, Profile.DoesNotExist):
return Falsefrom rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from rest_framework import status
from .models import Book, Category
from .serializers import BookSerializer, CategorySerializer
from .permissions import AdminTokenCheckMixin
class BookViewSet(AdminTokenCheckMixin, ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
def create(self, request, *args, **kwargs):
if not self.is_admin(request):
return Response({'error': 'Unauthorized'}, status=status.HTTP_401_UNAUTHORIZED)
return super().create(request, *args, **kwargs)
def update(self, request, *args, **kwargs):
if not self.is_admin(request):
return Response({'error': 'Unauthorized'}, status=status.HTTP_401_UNAUTHORIZED)
return super().update(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
if not self.is_admin(request):
return Response({'error': 'Unauthorized'}, status=status.HTTP_401_UNAUTHORIZED)
return super().destroy(request, *args, **kwargs)
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import BookViewSet, CategoryViewSet
router = DefaultRouter()
router.register('books', BookViewSet, basename='books')
urlpatterns = [
path('', include(router.urls)),
]✅ 1. GET All Books
fetch("http://127.0.0.1:8000/book/books/")
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error("Error:", err));✅ 2. GET Single Book (ID = 1)
fetch("http://127.0.0.1:8000/book/books/1/")
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error("Error:", err));✅ 3. POST (Create a New Book)
fetch("http://127.0.0.1:8000/book/books/", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
token_id: "your_token_string",
title: "New Book Title",
isbn: "1234567891234",
author: "Author Name",
description: "This is a new book",
copies: 5,
available: 5,
language: "English",
category: [1] // assuming category ID 1 exists
})
})
.then(res => res.json())
.then(data => console.log("Created:", data))
.catch(err => console.error("Error:", err));✅ 4. PUT (Update Entire Book by ID)
fetch("http://127.0.0.1:8000/book/books/1/", {
method: "PUT",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
token_id: "your_token_string",
title: "Updated Title",
isbn: "1234567891234",
author: "Updated Author",
description: "Updated description",
copies: 10,
available: 8,
language: "Bangla",
category: [1]
})
})
.then(res => res.json())
.then(data => console.log("Updated:", data))
.catch(err => console.error("Error:", err));✅ 5. PATCH (Update Partial Fields)
fetch("http://127.0.0.1:8000/book/books/1/", {
method: "PATCH",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
token_id: "your_token_string",
available: 3
})
})
.then(res => res.json())
.then(data => console.log("Patched:", data))
.catch(err => console.error("Error:", err));✅ 6. DELETE Book by ID
fetch("http://127.0.0.1:8000/book/books/1/", {
method: "DELETE",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
token_id: "your_token_string"
})
})
.then(res => {
if (res.status === 204) {
console.log("Deleted successfully");
} else {
console.error("Delete failed");
}
})
.catch(err => console.error("Error:", err));Let me know if you want to use Authorization: Token xxx in headers (more standard way) instead of body-based token_id — I can show that too.
class ProfileSerializerView(CustomAdminTokenCheckMixin, ModelViewSet):
serializer_class = ProfileSerializers
queryset = Profile.objects.filter(user__is_active=True)
def create(self, request, *args, **kwargs): # POST REQUEST
if not self.is_admin(request):
return Response({'detail': 'Permission Denied'}, status=status.HTTP_403_FORBIDDEN)
return super().create(request, *args, **kwargs)
def update(self, request, *args, **kwargs): # PUT
if not self.is_admin(request):
return Response({'detail': 'Permission Denied'}, status=status.HTTP_403_FORBIDDEN)
return super().update(request, *args, **kwargs)
def partial_update(self, request, *args, **kwargs): # PATCH
if not self.is_admin(request):
return Response({'detail': 'Permission Denied'}, status=status.HTTP_403_FORBIDDEN)
return super().partial_update(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs): # DELETE
if not self.is_admin(request):
return Response({'detail': 'Permission Denied'}, status=status.HTTP_403_FORBIDDEN)
return super().destroy(request, *args, **kwargs)
# 🔹 Custom GET endpoint
# GET-> list , POST -> create, PUT -> update, PATCH -> partial_update, DELETE -> destroy
@action(detail=False, methods=['get'], url_path='unactive') #Custom GET
def get_unactive_profiles(self, request):
if not self.is_admin(request):
return Response({'detail': 'Permission Denied'}, status=status.HTTP_403_FORBIDDEN)
profiles = Profile.objects.filter(user__is_active=False)
serializer = self.get_serializer(profiles, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
# Custom POST endpoint to activate a profile by pk
@action(detail=True, methods=['post'], url_path='activate') #Custom POST
def activate_profile(self, request, pk=None):
if not self.is_admin(request):
return Response({'detail': 'Permission Denied'}, status=status.HTTP_403_FORBIDDEN)
try:
# profile = self.get_object() # gets Profile object with pk from URL
profile = Profile.objects.get(pk=pk)
except Profile.DoesNotExist:
return Response({'detail': 'Profile not found'}, status=status.HTTP_404_NOT_FOUND)
user = profile.user
user.is_active = True
user.save()
serializer = self.get_serializer(profile)
return Response(serializer.data, status=status.HTTP_200_OK)
from rest_framework.exceptions import PermissionDenied
class BookViewSet(CustomAdminTokenCheckMixin, ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
def initial(self, request, *args, **kwargs):
super().initial(request, *args, **kwargs)
# Only check admin for write operations (POST, PATCH)
if request.method in ['POST', 'PATCH']:
if not self.is_admin(request):
raise PermissionDenied(detail='Only admins can perform this action.')from rest_framework.authtoken.models import Token
from accounts.models import Profile
class CustomAdminTokenCheckMixin:
def is_admin(self, request):
# its best for safe security
# it will check , Header section has any "Authorization" variable ?
auth_header = request.headers.get('Authorization')
# it will check , Body section has any "token_id" variable ?
token_id = (
request.data.get('token_id') or
request.query_params.get('token_id') or
request.headers.get('token_id')
)
if auth_header and auth_header.startswith('Token '):
token_id = auth_header.split(' ')[1]
if not token_id:
return False
try:
token = Token.objects.get(key=token_id)
user = token.user
profile = Profile.objects.get(user=user)
return profile.role == 'admin'
except (Token.DoesNotExist, Profile.DoesNotExist):
return False-
request.GET→ Query parameters (from ?param=value) → type: QueryDict -
request.POST→ Form data (from POST body) → type: QueryDict -
request.FILES→ Uploaded files -
request.COOKIES→ Cookies dict -
request.META→ All headers + environment info (User-Agent, IP, etc.) -
request.body→ Raw body of request (bytes) -
request.user→ Current logged-in user (if using auth middleware) -
request.META.get("HTTP_AUTHORIZATION")→ # Token 7ce76d81bd3663ee9c1bd47c635e214278a3e888 -
request.user→ # anmamun0 -
request.user.is_authenticated→ #True -
request.user.id→ #1 -
request.user.username→ #anmamun0@gmail.com
# Only check admin for write operations (POST, PATCH)
print("🔍 Request Method:", request.method)
print("🔍 Request Path:", request.path)
print("🔍 Request Query Params:", dict(request.query_params))
print("🔍 Request Headers:")
for key, value in request.headers.items():
print(f" {key}: {value}")
try:
print("🔍 Request Body Data:", request.data.dict()) # For form data
except:
print("🔍 Request Body Data:", request.data) # For JSON body
Quit the server with CTRL-BREAK.
🔍 Request Method: PATCH
🔍 Request Path: /book/books/1/
🔍 Request Query Params: {}
🔍 Request Headers:
Content-Length: 23
Content-Type: application/json
Host: 127.0.0.1:8000
Connection: keep-alive
Sec-Ch-Ua-Platform: "Windows"
Authorization: Token 7ce76d81bd3663ee9c1bd47c635e214278a3e888
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0
Sec-Ch-Ua: "Chromium";v="136", "Microsoft Edge";v="136", "Not.A/Brand";v="99"
Sec-Ch-Ua-Mobile: ?0
Accept: */*
Origin: http://127.0.0.1:5501
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:5501/
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,as;q=0.8
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:5501/
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:5501/
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:5501/
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,as;q=0.8
🔍 Request Body Data: {'title': 'Updated -3 '}
[20/May/2025 12:52:15] "PATCH /book/books/1/ HTTP/1.1" 200 177
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:5501/
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,as;q=0.8
🔍 Request Body Data: {'title': 'Updated -3 '}
[20/May/2025 12:52:15] "PATCH /book/books/1/ HTTP/1.1" 200 177
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:5501/
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,as;q=0.8
🔍 Request Body Data: {'title': 'Updated -3 '}
[20/May/2025 12:52:15] "PATCH /book/books/1/ HTTP/1.1" 200 177
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:5501/
Referer: http://127.0.0.1:5501/
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: en-US,en;q=0.9,as;q=0.8
🔍 Request Body Data: {'title': 'Updated -3 '}
[20/May/2025 12:52:15] "PATCH /book/books/1/ HTTP/1.1" 200 177✅ 1. Get All Active Profiles
fetch('/user/profile/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 7ce76d81bd3663ee9c1bd47c635e214278a3e888' // your admin token here
},
})
.then(res => res.json())
.then(data => console.log(data));🔍 2. Get Inactive Profiles (Admin only)
fetch('/user/profile/unactive/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 7ce76d81bd3663ee9c1bd47c635e214278a3e888' // your admin token here
},
})
.then(res => res.json())
.then(data => console.log(data));➕ 3. Create Profile (Admin only)
fetch('/user/profile/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 7ce76d81bd3663ee9c1bd47c635e214278a3e888' // your admin token here
},,
body: JSON.stringify({
bio: 'New bio',
address: 'Dhaka'
})
})
.then(res => res.json())
.then(data => console.log(data));✏️ 4. Fully Update Profile (PUT)
fetch('/user/profile/5/', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 7ce76d81bd3663ee9c1bd47c635e214278a3e888' // your admin token here
},,
body: JSON.stringify({
bio: 'Updated bio',
address: 'Sylhet'
})
})
.then(res => res.json())
.then(data => console.log(data));🩹 5. Partially Update Profile (PATCH)
fetch('/user/profile/5/', {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 7ce76d81bd3663ee9c1bd47c635e214278a3e888' // your admin token here
},,
body: JSON.stringify({
address: 'Chittagong'
})
})
.then(res => res.json())
.then(data => console.log(data));❌ 6. Delete Profile
fetch('/user/profile/5/', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 7ce76d81bd3663ee9c1bd47c635e214278a3e888' // your admin token here
},
})
.then(res => {
if (res.status === 204) console.log('Profile deleted');
else return res.json();
});🔁 7. Activate Profile by ID
fetch('/user/profile/5/activate/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Token 7ce76d81bd3663ee9c1bd47c635e214278a3e888' // your admin token here
},
})
.then(res => res.json())
.then(data => console.log(data));Let me know if you want this in a downloadable file or as a complete README update.
| Topic | Linkes |
|---|---|
| Django Commands | Go |
| Crispy-bootstrap5 | Go |
| Static files and photos | Go |
| Dynamic Media File Management | Go |
| Backend Email Controll | Go |
| Decorator @login_required | Go |
| Cookie Management | Go |
| Session Management | Go |
| Class Base View (CBv) | Go |
| Connect Django to PostgreSQL Database | Go |
| SSLcommerz payment gateways Developer | Go |
| Model Print key and value | Go |
| Leatest Update of me DRF ModelView | Go1 |
| More security with JWT TOken in Fetch header | Go2 |