Part 1: Django Project Setup & Model Optimization
📑 Table of Contents
- ধাপ ০: Environment Setup
- ধাপ ১: Project Creation
- ধাপ ২: Settings Configuration
- Normal Model vs Optimized Model
- Model Optimization Explained
- Migrations
- Next Steps
ধাপ ০: Environment Setup
প্রথমে আমরা আমাদের development environment তৈরি করব। Virtual environment ব্যবহার করা জরুরি, কারণ এটি আপনার project dependencies আলাদা রাখে এবং system-wide Python environment কে affect করে না।
# Virtual environment তৈরি
python3 -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windows
# প্রয়োজনীয় packages install
pip install django djangorestframework django-debug-toolbar django-extensions
pip install psycopg2-binary # PostgreSQL এর জন্য (optional)
ব্যাখ্যা / কেন দরকার:
django– Main frameworkdjangorestframework– API বানানোর জন্যdjango-debug-toolbar– Query optimization দেখার জন্য (N+1 problem ধরার জন্য)django-extensions– Extra tools যেমন shell_pluspsycopg2-binary– PostgreSQL connect করার জন্য
রিয়েল স্টোরি সমস্যা:
আমি একবার large dataset সহ project চালাচ্ছিলাম, এবং ডিফল্ট SQLite ব্যবহার করছিলাম। যখন PostgreSQL switch করলাম, তখন performance অনেক ভালো হয়ে গেল।
ধাপ ১: Project Creation
django-admin startproject optimization_project
cd optimization_project
python manage.py startapp shop
ব্যাখ্যা:
- Project name:
optimization_project– মূল Django project - App name:
shop– আমাদের ecommerce-like app
কেন app আলাদা: Django তে একাধিক app রাখা modular এবং maintainable হয়।
রিয়েল সমস্যা:
ছোট project এ সব model same app এ রাখলে code messy হয়ে যায়। বড় project এ modular approach maintain করা সহজ হয়।
ধাপ ২: Settings Configuration
optimization_project/settings.py এ আমাদের apps, middleware, debug tools এবং REST framework configure করতে হবে।
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Third party
'rest_framework',
'debug_toolbar', # Query debugging এর জন্য
'django_extensions',
# Local apps
'shop',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware', # Debug toolbar
]
# Debug Toolbar
INTERNAL_IPS = [
'127.0.0.1',
]
# REST Framework
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100,
}
ব্যাখ্যা / কেন দরকার:
debug_toolbarmiddleware: slow queries detect করার জন্য- REST Framework Pagination: বড় dataset হলে memory explode না করার জন্য
urls.py:
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('shop.urls')),
]
if settings.DEBUG:
import debug_toolbar
urlpatterns = [
path('__debug__/', include(debug_toolbar.urls)),
] + urlpatterns
ব্যাখ্যা:
- Admin panel এবং API route আলাদা করা clean architecture এর জন্য
- Debug toolbar শুধুমাত্র debug mode এ load হয়
Normal Model vs Optimized Model
Normal Model (Slow & Inefficient)
shop/models.py – Normal Version
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Brand(models.Model):
name = models.CharField(max_length=100)
country = models.CharField(max_length=50)
website = models.URLField()
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.IntegerField(default=0)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return self.name
# ❌ সমস্যা: প্রতিবার call হলে database query হয়
def get_category_name(self):
return self.category.name # Extra query!
def get_brand_name(self):
return self.brand.name # Extra query!
সমস্যা:
- N+1 query problem: ForeignKey access এ extra query হয়
- কোনো index নেই → search slow
- কোন caching নেই → বারবার same data fetch
রিয়েল উদাহরণ:
Shop এ 1000 product list fetch করলে 1 request এ 1000 extra query! Slow এবং CPU heavy।
Optimized Model (Fast & Efficient)
from django.db import models
from django.contrib.auth.models import User
from django.core.cache import cache
from django.db.models import Avg, Count, Q
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
# Category - Optimized
class Category(models.Model):
name = models.CharField(max_length=100, db_index=True)
slug = models.SlugField(unique=True, db_index=True)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True, db_index=True)
class Meta:
verbose_name_plural = "Categories"
ordering = ['name']
indexes = [
models.Index(fields=['name', 'created_at']),
]
def __str__(self):
return self.name
# Cache method
def get_product_count(self):
cache_key = f'category_{self.id}_product_count'
count = cache.get(cache_key)
if count is None:
count = self.products.filter(is_active=True).count()
cache.set(cache_key, count, 300)
return count
ব্যাখ্যা / Feature Why Use:
db_index=True→ Query fastSlugField→ SEO friendly URLsCache→ Database load কমানো
Real-world Problem → Solution:
অনেক time আগেই Django shop এ category product count দেখানোর query প্রতিবার slow ছিল। Cache use করলে query time 500ms → 5ms।
(Similar optimization applied to Brand, Product, Review, Order, OrderItem – all N+1 solved, caching applied, proper indexing.)
Model Optimization Explained
Database Indexing
name = models.CharField(max_length=200, db_index=True)
- Why: WHERE clause, ORDER BY fast
- Problem: No index → slow search
Composite Index
indexes = [models.Index(fields=['category', 'is_active'])]
- Why: Frequently filter by category + is_active
- Problem: Single index slower for multi-column filters
Custom Manager & QuerySet
products = Product.objects.active().with_relations()
- Clean & reusable queries
- Solves N+1 queries
Denormalized Fields
average_rating = models.DecimalField(default=0.00)
- Stores aggregate data
- Avoid repeated database queries
Database Constraints
constraints = [models.CheckConstraint(check=Q(price__gte=0), name='price_non_negative')]
- Ensures data integrity at DB level
Migrations
python manage.py makemigrations
python manage.py migrate