আমি windows 10 use করি।এখন আমি আমার desktop এ djnagosite নামে একটা ফোল্ডার এ তোমার ইচ্ছামত নাম দিয়ে একটা ৩ পেইজের ওয়েবসাইট বানিয়ে দাও। আমি windows powershell and vs code editor ইউজ করতে চাই। একেবারে শূন্য থেকে খুব ভালো করে সহজ করে শিখিয়ে দাও কোডের ব্যাখ্যা সহ ।আমার লক্ষ্য django দিয়ে যেকোনো এডুকেশন ওয়েবসাইট এবং ই কমার্স যেন বানাতে পারি,এখন শুরু করো। কোন ভুল করবে না। একেবারে সঠিক তথ্য ও কোড দিবে যেন ভবিষ্যতে vps এ সাইট বানাতে পারি djnago দিয়ে
Django দিয়ে প্রথম ৩-পেইজ ওয়েবসাইট (শূন্য থেকে) — Windows 10 + PowerShell + VS Code
আমি সাইটের নাম দিলাম: ShikkhaBazar (শিক্ষা + বাজার) — কারণ আপনার লক্ষ্য একদিকে এডুকেশন সাইট, অন্যদিকে ই-কমার্স। তাই এই একটা প্রজেক্টেই দুটোর ভিত্তি (Course model + Price + Admin + Form + Media/Image) শিখে ফেলবেন।
যে ৩টি পেইজ বানাব: Home (হোম), Courses (কোর্স/প্রোডাক্ট লিস্ট), Contact (যোগাযোগ ফর্ম — ডেটাবেজে সেভ হবে)।
০. আগে বুঝে নিন: Django আসলে কীভাবে কাজ করে
Django হলো Python-এর একটা web framework — মানে রেডিমেড যন্ত্রপাতি সহ কারখানা। এটি MTV প্যাটার্ন ফলো করে:
| অংশ | মানে | কাজ | ফাইল |
|---|---|---|---|
| M – Model | ডেটার গঠন | ডেটাবেজ টেবিল (কোর্স, প্রোডাক্ট, অর্ডার) | models.py |
| T – Template | চেহারা | HTML পেইজ | templates/*.html |
| V – View | লজিক | রিকোয়েস্ট নেয়, ডেটা আনে, টেমপ্লেট রিটার্ন করে | views.py |
| URLconf | রাউটার | কোন লিংকে কোন view চলবে | urls.py |
একটা রিকোয়েস্টের যাত্রাপথ:
এই ছবিটা মাথায় গেঁথে নিন — Django-র ৯০% কাজ এই ৪টা ফাইলেই।
১. কোন ভার্সন ইনস্টল করব? (২০২৬ সালের সঠিক তথ্য)
| সফটওয়্যার | যা ব্যবহার করবেন | কেন |
|---|---|---|
| Python | 3.13.x (3.12–3.14 চলবে) | সব প্যাকেজের সাপোর্ট আছে |
| Django | 5.2 LTS | LTS = Long Term Support, সিকিউরিটি আপডেট এপ্রিল ২০২৮ পর্যন্ত। VPS/প্রোডাকশনের জন্য আদর্শ |
| (বিকল্প) | Django 6.1 | সর্বশেষ ভার্সন (আগস্ট ২০২৬), কিন্তু সাপোর্ট উইন্ডো ছোট |
| Editor | VS Code | ফ্রি ও সেরা |
| Database | SQLite (শেখার সময়) → PostgreSQL (VPS-এ) | Django-তে ডিফল্ট SQLite, কনফিগ ছাড়াই চলে |
🔒 ছোট নোট: Windows 10-এর অফিসিয়াল সাপোর্ট ২০২৫ সালের অক্টোবরে শেষ হয়েছে। শেখার জন্য কোনো সমস্যা নেই, তবে ভবিষ্যতে Windows 11-এ যাওয়ার পরিকল্পনা রাখুন।
১.১ Python ইনস্টল
- python.org/downloads → Windows installer (64-bit) ডাউনলোড করুন (Python 3.13.x)।
- ইনস্টলারে অবশ্যই ☑️
Add python.exe to PATHটিক দিন →Install Now।
১.২ VS Code ইনস্টল
code.visualstudio.com থেকে ইনস্টল করে এই এক্সটেনশনগুলো নিন:
| এক্সটেনশন | কাজ |
|---|---|
| Python (Microsoft) | কোড রান, IntelliSense, ডিবাগ |
| Pylance | দ্রুত অটো-কমপ্লিট |
| Django (Baptiste Darthenay) | {% %} ট্যাগে কালার ও স্নিপেট |
২. PowerShell খুলে প্রস্তুতি
Start menu → powershell লিখে Windows PowerShell খুলুন। প্রথমে চেক করুন:
powershell
py --version
pip --version
Python 3.13.x দেখালে ঠিক আছে। (না দেখালে PC রিস্টার্ট দিন — PATH আপডেট হবে।)
২.১ একটি জরুরি সেটিং (এটা না করলে পরে আটকে যাবেন)
PowerShell ডিফল্টভাবে স্ক্রিপ্ট চালাতে দেয় না, ফলে virtual environment চালু হয় না। একবার এই কমান্ডটি দিন:
powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Y চাপুন। এটি শুধু আপনার ইউজারের জন্য, নিরাপদ।
⚠️ PowerShell টিপস: পুরনো Windows PowerShell 5.1-এ
&&কাজ করে না। দুটো কমান্ড একসাথে দিতে;ব্যবহার করুন, নাহয় আলাদা আলাদা লাইনে দিন।
৩. ফোল্ডার তৈরি ও ভার্চুয়াল এনভায়রনমেন্ট
powershell
cd $HOME\Desktop
mkdir djnagosite
cd djnagosite
এখন virtual environment (venv) বানান:
powershell
py -m venv venv
venv কী? এটা একটা আলাদা বক্স, যেখানে শুধু এই প্রজেক্টের প্যাকেজ (Django ইত্যাদি) থাকবে। ফলে অন্য প্রজেক্টে অন্য ভার্সন ব্যবহার করতে পারবেন, কোনো সংঘর্ষ হবে না। প্রফেশনাল কাজে venv ছাড়া কেউ কাজ করে না।
চালু (activate) করুন:
powershell
.\venv\Scripts\Activate.ps1
সফল হলে লাইনের শুরুতে দেখবেন:
(venv) PS C:\Users\YourName\Desktop\djnagosite>
বন্ধ করতে চাইলে:
deactivate। কম্পিউটার বন্ধ করে আবার কাজ শুরু করলে প্রতিবার উপরের activate কমান্ডটি দিতে হবে — এটাই সবচেয়ে বেশি ভুলে যাওয়া ধাপ।
৪. Django ইনস্টল
powershell
python -m pip install --upgrade pip
pip install "Django==5.2.*"
চেক করুন:
powershell
python -m django --version
আউটপুট: 5.2.x ✅
৫. প্রজেক্ট তৈরি (খেয়াল করুন শেষের ডট .)
powershell
django-admin startproject shikkhabazar .
শেষের . মানে: "এখানেই বানাও, বাড়তি ফোল্ডার বানিও না"। এটা না দিলে djnagosite\shikkhabazar\shikkhabazar\... এভাবে ডাবল ফোল্ডার হয়ে বিভ্রান্তি তৈরি করে।
VS Code-এ খুলুন:
powershell
code .
৫.১ VS Code-এ Python interpreter সিলেক্ট করুন (গুরুত্বপূর্ণ)
Ctrl + Shift + P → লিখুন Python: Select Interpreter → যেটার নামে ('venv': venv) লেখা আছে সেটি বাছুন। এতে VS Code-এর ভেতরের টার্মিনালও অটো-activate হবে এবং import-এ লাল দাগ পড়বে না।
৫.২ এখন যেসব ফাইল তৈরি হয়েছে — প্রতিটির ব্যাখ্যা
djnagosite/
├── venv/ ← ভার্চুয়াল এনভায়রনমেন্ট (কখনো এডিট করবেন না, GitHub-এ দেবেন না)
├── manage.py ← প্রজেক্ট চালানোর রিমোট কন্ট্রোল
└── shikkhabazar/ ← প্রজেক্টের "মগজ" (কনফিগারেশন)
├── __init__.py ← এটি ফোল্ডারটিকে Python প্যাকেজ বানায় (খালি ফাইল)
├── settings.py ← সব সেটিং: অ্যাপ লিস্ট, ডেটাবেজ, টেমপ্লেট, static
├── urls.py ← মেইন রাউটার (কোন লিংক কোথায় যাবে)
├── asgi.py ← async সার্ভারে (Daphne/Uvicorn) চালানোর ঢোকার দরজা
└── wsgi.py ← VPS-এ Gunicorn এই ফাইল দিয়েই সাইট চালাবে
৫.৩ প্রথম রান
powershell
python manage.py migrate
python manage.py runserver
migrate= Django-র বিল্ট-ইন টেবিলগুলো (ইউজার, সেশন, অ্যাডমিন লগ) ডেটাবেজে বানিয়ে দেয় →db.sqlite3ফাইল তৈরি হবে।runserver= ডেভেলপমেন্ট সার্ভার চালু করে।
ব্রাউজারে যান 👉 http://127.0.0.1:8000/ — রকেটের ছবিসহ "The install worked successfully!" দেখলে অভিনন্দন! 🎉
সার্ভার বন্ধ করতে টার্মিনালে Ctrl + C।
৬. অ্যাপ (app) তৈরি
Django-তে প্রজেক্ট = পুরো সাইট, অ্যাপ = সাইটের একটা বিভাগ। ভবিষ্যতে ই-কমার্সে আপনার থাকবে products, cart, orders — আলাদা আলাদা অ্যাপ।
নতুন টার্মিনাল ট্যাবে (বা Ctrl+C দিয়ে সার্ভার থামিয়ে):
powershell
python manage.py startapp pages
৬.১ অ্যাপের ফাইলগুলোর কাজ
| ফাইল | কাজ |
|---|---|
models.py | ডেটাবেজ টেবিলের ডিজাইন |
views.py | পেইজের লজিক |
admin.py | অ্যাডমিন প্যানেলে কোন model দেখাবে |
apps.py | অ্যাপের কনফিগ (হাত দিতে হয় না) |
tests.py | অটোমেটেড টেস্ট |
migrations/ | model পরিবর্তনের ইতিহাস |
urls.py | নেই — আমরা নিজে বানাব |
৭. settings.py সেটআপ (লাইন ধরে ব্যাখ্যা)
shikkhabazar/settings.py খুলে নিচের অংশগুলো খুঁজে এভাবে বদলান:
৭.১ অ্যাপ রেজিস্টার
python
INSTALLED_APPS = [
"django.contrib.admin", # অ্যাডমিন প্যানেল
"django.contrib.auth", # লগইন/ইউজার সিস্টেম
"django.contrib.contenttypes",
"django.contrib.sessions", # সেশন (কার্টের জন্য দরকার হবে)
"django.contrib.messages", # সাকসেস/এরর মেসেজ দেখানো
"django.contrib.staticfiles", # CSS/JS/Image হ্যান্ডলিং
# আমার নিজের অ্যাপ
"pages",
]
👉 নতুন অ্যাপ বানালে এখানে নাম না লিখলে Django সেটি চিনবে না — নতুনদের #১ ভুল।
৭.২ টেমপ্লেট ফোল্ডার জানিয়ে দিন
python
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"], # 👈 শুধু এই লাইনটি বদলান
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
DIRS= প্রজেক্টের রুটে যেtemplatesফোল্ডার বানাব, সেখানে Django HTML খুঁজবে।BASE_DIR= প্রজেক্টের মূল ফোল্ডার (djnagosite), ফাইলের উপরে আগেই ডিফাইন করা আছে।
৭.৩ ভাষা ও সময়
python
LANGUAGE_CODE = "en-us"
TIME_ZONE = "Asia/Dhaka" # 👈 বাংলাদেশ সময়
USE_I18N = True
USE_TZ = True
৭.৪ Static ও Media (ফাইলের নিচের দিকে)
STATIC_URL = "static/" লাইনটি খুঁজে সেটিকে এভাবে সম্পূর্ণ করুন:
python
# ---------- Static files (CSS, JS, নিজের বানানো ছবি) ----------
STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / "static"] # ডেভেলপমেন্টে এখান থেকে পড়বে
STATIC_ROOT = BASE_DIR / "staticfiles" # VPS-এ collectstatic এখানে জমা করবে
# ---------- Media files (ইউজার/অ্যাডমিন যে ছবি আপলোড করবে) ----------
MEDIA_URL = "media/"
MEDIA_ROOT = BASE_DIR / "media"
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
| সেটিং | পার্থক্য |
|---|---|
STATICFILES_DIRS | আপনি যে CSS/JS লেখেন |
STATIC_ROOT | সব static এক জায়গায় জমা করার গুদাম (শুধু প্রোডাকশন) |
MEDIA_ROOT | ইউজার আপলোড করা ফাইল (প্রোডাক্ট/কোর্সের ছবি) |
৮. Model তৈরি (ডেটাবেজ — এডুকেশন ও ই-কমার্স দুটোরই ভিত্তি)
ছবি আপলোডের জন্য Pillow লাগবে:
powershell
pip install Pillow
pages/models.py — পুরোটা রিপ্লেস করুন:
python
from django.db import models
from django.urls import reverse
class Course(models.Model):
"""একটি কোর্স = ই-কমার্সের একটি প্রোডাক্টের মতোই।"""
title = models.CharField("কোর্সের নাম", max_length=200)
slug = models.SlugField(max_length=220, unique=True,
help_text="URL-এ ব্যবহার হবে, যেমন: python-basic")
short_description = models.CharField(max_length=300, blank=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2, default=0)
thumbnail = models.ImageField(upload_to="courses/", blank=True, null=True)
is_published = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = "Course"
verbose_name_plural = "Courses"
ordering = ["-created_at"] # নতুন কোর্স আগে দেখাবে
def __str__(self):
return self.title
class ContactMessage(models.Model):
"""Contact পেইজের ফর্ম থেকে আসা মেসেজ এখানে জমা হবে।"""
name = models.CharField(max_length=100)
email = models.EmailField()
subject = models.CharField(max_length=150, blank=True)
message = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ["-created_at"]
def __str__(self):
return f"{self.name} — {self.subject or 'No subject'}"
Field-গুলোর ব্যাখ্যা
| Field | ব্যবহার | মনে রাখার কথা |
|---|---|---|
CharField | ছোট টেক্সট | max_length বাধ্যতামূলক |
TextField | বড় টেক্সট | লিমিট নেই |
SlugField | URL-বান্ধব টেক্সট | unique=True দিলে ডুপ্লিকেট হবে না |
DecimalField | টাকা/দাম | টাকার জন্য FloatField নয়, সবসময় DecimalField (হিসাবে ভুল হয় না) |
ImageField | ছবি | Pillow লাগে; upload_to = MEDIA_ROOT-এর ভেতরের সাব-ফোল্ডার |
BooleanField | হ্যাঁ/না | ড্রাফট-পাবলিশ কন্ট্রোলের জন্য দারুণ |
auto_now_add=True | তৈরির সময় একবার বসে | auto_now=True হলে প্রতিবার সেভে আপডেট হয় |
blank=True | ফর্মে খালি রাখা যাবে | null=True = ডেটাবেজে NULL রাখা যাবে |
৮.১ মাইগ্রেশন (model → আসল টেবিল)
powershell
python manage.py makemigrations
python manage.py migrate
| কমান্ড | কাজ |
|---|---|
makemigrations | আপনার Python কোড দেখে পরিবর্তনের "নকশা" ফাইল বানায় |
migrate | সেই নকশা ডেটাবেজে প্রয়োগ করে |
👉 নিয়ম: models.py-তে যেকোনো পরিবর্তন করলেই এই দুটো কমান্ড চালাতে হবে।
৯. Admin প্যানেল সেটআপ (Django-র সবচেয়ে বড় সুবিধা)
pages/admin.py:
python
from django.contrib import admin
from .models import ContactMessage, Course
@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
list_display = ("title", "price", "is_published", "created_at")
list_filter = ("is_published",)
search_fields = ("title", "short_description")
prepopulated_fields = {"slug": ("title",)} # নাম লিখলেই slug অটো তৈরি হবে
list_editable = ("price", "is_published") # লিস্ট থেকেই এডিট করা যাবে
@admin.register(ContactMessage)
class ContactMessageAdmin(admin.ModelAdmin):
list_display = ("name", "email", "subject", "created_at")
search_fields = ("name", "email", "message")
readonly_fields = ("name", "email", "subject", "message", "created_at")
অ্যাডমিন ইউজার (superuser) বানান:
powershell
python manage.py createsuperuser
Username, Email, Password দিন (পাসওয়ার্ড টাইপ করলে স্ক্রিনে কিছু দেখাবে না — এটা স্বাভাবিক, লিখে Enter চাপুন)।
সার্ভার চালু করে যান 👉 http://127.0.0.1:8000/admin/ → লগইন করে ২-৩টি কোর্স যোগ করুন (দাম ও ছবি সহ)। এই ডেটাই পরে ওয়েবসাইটে দেখাবে।
১০. View তৈরি (লজিক)
pages/views.py — পুরোটা রিপ্লেস:
python
from django.contrib import messages
from django.shortcuts import redirect, render
from .forms import ContactForm
from .models import Course
def home(request):
"""হোম পেইজ — সর্বশেষ ৩টি কোর্স দেখাবে।"""
latest_courses = Course.objects.filter(is_published=True)[:3]
context = {
"page_title": "হোম",
"courses": latest_courses,
}
return render(request, "pages/home.html", context)
def course_list(request):
"""সব কোর্সের লিস্ট + সার্চ সুবিধা।"""
query = request.GET.get("q", "").strip()
courses = Course.objects.filter(is_published=True)
if query:
courses = courses.filter(title__icontains=query)
context = {
"page_title": "কোর্সসমূহ",
"courses": courses,
"query": query,
}
return render(request, "pages/courses.html", context)
def contact(request):
"""যোগাযোগ ফর্ম — POST হলে ডেটাবেজে সেভ করে।"""
if request.method == "POST":
form = ContactForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, "ধন্যবাদ! আপনার মেসেজ আমরা পেয়েছি।")
return redirect("pages:contact") # PRG প্যাটার্ন: রিফ্রেশে ডাবল সাবমিট হবে না
else:
form = ContactForm()
return render(request, "pages/contact.html", {"page_title": "যোগাযোগ", "form": form})
লাইন-বাই-লাইন মূল ধারণা
| কোড | অর্থ |
|---|---|
def home(request) | প্রতিটি view একটি ফাংশন, প্রথম আর্গুমেন্ট সবসময় request |
Course.objects.filter(...) | SQL না লিখেই ডেটাবেজ কুয়েরি (ORM) |
[:3] | মাত্র ৩টি রেকর্ড (SQL LIMIT 3) |
title__icontains=query | নামের মধ্যে খোঁজা, বড়-ছোট হাতের অক্ষর ধরবে না |
context | টেমপ্লেটে পাঠানো ডেটার ডিকশনারি |
render(request, template, context) | HTML বানিয়ে রেসপন্স দেয় |
redirect("pages:contact") | অন্য URL-এ পাঠায় |
১১. Form তৈরি
নতুন ফাইল বানান: pages/forms.py
python
from django import forms
from .models import ContactMessage
class ContactForm(forms.ModelForm):
class Meta:
model = ContactMessage
fields = ["name", "email", "subject", "message"]
widgets = {
"name": forms.TextInput(attrs={"class": "input", "placeholder": "আপনার নাম"}),
"email": forms.EmailInput(attrs={"class": "input", "placeholder": "you@example.com"}),
"subject": forms.TextInput(attrs={"class": "input", "placeholder": "বিষয়"}),
"message": forms.Textarea(attrs={"class": "input", "rows": 5,
"placeholder": "আপনার মেসেজ লিখুন..."}),
}
def clean_message(self):
"""কাস্টম ভ্যালিডেশন: মেসেজ খুব ছোট হলে গ্রহণ করব না।"""
message = self.cleaned_data["message"]
if len(message) < 10:
raise forms.ValidationError("মেসেজ কমপক্ষে ১০ অক্ষরের হতে হবে।")
return message
ModelForm কেন? model-এর ফিল্ড দেখে Django নিজেই ফর্ম, ভ্যালিডেশন আর .save() বানিয়ে দেয় — হাতে HTML ফর্ম ও ভ্যালিডেশন লিখতে হয় না। এটাই Django-র "DRY" (Don't Repeat Yourself) দর্শন।
১২. URL রাউটিং (২ ধাপে)
১২.১ অ্যাপের URL — নতুন ফাইল pages/urls.py
python
from django.urls import path
from . import views
app_name = "pages" # namespace: টেমপ্লেটে 'pages:home' লিখতে পারব
urlpatterns = [
path("", views.home, name="home"),
path("courses/", views.course_list, name="courses"),
path("contact/", views.contact, name="contact"),
]
১২.২ মেইন URL — shikkhabazar/urls.py পুরোটা রিপ্লেস
python
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("", include("pages.urls")), # সব রুট pages অ্যাপে পাঠিয়ে দিলাম
]
# ডেভেলপমেন্টে আপলোড করা ছবি দেখানোর জন্য (প্রোডাকশনে Nginx এই কাজ করবে)
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
| ধারণা | ব্যাখ্যা |
|---|---|
path("courses/", view, name=...) | /courses/ লিংকে ওই view চলবে |
name="courses" | টেমপ্লেটে {% url 'pages:courses' %} লিখে লিংক বানাব |
include() | অ্যাপের urls.py-কে জুড়ে দেয় — প্রজেক্ট বড় হলেও গোছানো থাকে |
| হার্ডকোড লিংক? ❌ | href="/courses/" না লিখে {% url %} ব্যবহার করুন; URL বদলালেও সাইট ভাঙবে না |
১৩. Template তৈরি (চেহারা)
VS Code-এ প্রজেক্টের রুটে (যেখানে manage.py আছে) এই ফোল্ডারগুলো বানান:
templates/
├── base.html
└── pages/
├── home.html
├── courses.html
└── contact.html
১৩.১ templates/base.html — সব পেইজের কমন কাঠামো
html
{% load static %}
<!DOCTYPE html>
<html lang="bn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}ShikkhaBazar{% endblock %}</title>
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<header class="navbar">
<a class="logo" href="{% url 'pages:home' %}">Shikkha<span>Bazar</span></a>
<nav>
<a href="{% url 'pages:home' %}">হোম</a>
<a href="{% url 'pages:courses' %}">কোর্স</a>
<a href="{% url 'pages:contact' %}">যোগাযোগ</a>
</nav>
</header>
<main class="container">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">{{ message }}</div>
{% endfor %}
{% endif %}
{% block content %}{% endblock %}
</main>
<footer class="footer">
<p>© {% now "Y" %} ShikkhaBazar — Django দিয়ে তৈরি।</p>
</footer>
</body>
</html>
টেমপ্লেট সিনট্যাক্সের ৩টি নিয়ম:
| লেখা | কাজ | উদাহরণ |
|---|---|---|
{{ ... }} | ভ্যালু দেখায় | {{ course.title }} |
{% ... %} | লজিক/ট্যাগ | {% if %}, {% for %}, {% url %} |
{# ... #} | কমেন্ট | {# এটা দেখাবে না #} |
{% block content %} = "ফাঁকা জায়গা"; প্রতিটি পেইজ এখানে নিজের কনটেন্ট বসাবে। এটাই template inheritance — নেভবার/ফুটার একবার লিখলেই সব পেইজে চলে আসবে।
১৩.২ templates/pages/home.html
html
{% extends "base.html" %}
{% load static %}
{% block title %}হোম | ShikkhaBazar{% endblock %}
{% block content %}
<section class="hero">
<h1>ঘরে বসে দক্ষতা অর্জন করুন</h1>
<p>প্রোগ্রামিং, ডিজাইন ও ব্যবসা — সবকিছুর কোর্স একই জায়গায়।</p>
<a class="btn" href="{% url 'pages:courses' %}">সব কোর্স দেখুন</a>
</section>
<h2 class="section-title">সর্বশেষ কোর্স</h2>
<div class="grid">
{% for course in courses %}
<article class="card">
{% if course.thumbnail %}
<img src="{{ course.thumbnail.url }}" alt="{{ course.title }}">
{% endif %}
<h3>{{ course.title }}</h3>
<p>{{ course.short_description }}</p>
<div class="card-foot">
<span class="price">৳ {{ course.price }}</span>
</div>
</article>
{% empty %}
<p class="muted">এখনো কোনো কোর্স যোগ করা হয়নি। অ্যাডমিন প্যানেল থেকে যোগ করুন।</p>
{% endfor %}
</div>
{% endblock %}
👉 {% empty %} = লিস্ট খালি থাকলে যা দেখাবে। খুব কাজের ট্যাগ।
১৩.৩ templates/pages/courses.html
html
{% extends "base.html" %}
{% block title %}কোর্সসমূহ | ShikkhaBazar{% endblock %}
{% block content %}
<h1 class="section-title">সকল কোর্স</h1>
<form class="search" method="get" action="{% url 'pages:courses' %}">
<input class="input" type="text" name="q" value="{{ query }}" placeholder="কোর্স খুঁজুন...">
<button class="btn" type="submit">খুঁজুন</button>
</form>
{% if query %}
<p class="muted">"{{ query }}" — এর জন্য {{ courses|length }} টি ফলাফল।</p>
{% endif %}
<div class="grid">
{% for course in courses %}
<article class="card">
{% if course.thumbnail %}
<img src="{{ course.thumbnail.url }}" alt="{{ course.title }}">
{% endif %}
<h3>{{ course.title }}</h3>
<p>{{ course.short_description }}</p>
<p class="muted">{{ course.description|truncatewords:18 }}</p>
<div class="card-foot">
<span class="price">৳ {{ course.price }}</span>
<span class="muted">{{ course.created_at|date:"d M Y" }}</span>
</div>
</article>
{% empty %}
<p class="muted">কোনো কোর্স পাওয়া যায়নি।</p>
{% endfor %}
</div>
{% endblock %}
Template filter (| চিহ্ন) দিয়ে ডেটা সাজানো যায়:
| ফিল্টার | কাজ |
|---|---|
|truncatewords:18 | ১৮ শব্দের পর ... |
|date:"d M Y" | তারিখ ফরম্যাট |
|length | সংখ্যা গোনা |
|default:"নেই" | খালি হলে বিকল্প লেখা |
১৩.৪ templates/pages/contact.html
html
{% extends "base.html" %}
{% block title %}যোগাযোগ | ShikkhaBazar{% endblock %}
{% block content %}
<h1 class="section-title">যোগাযোগ করুন</h1>
<div class="two-col">
<form class="card form" method="post" novalidate>
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-error">{{ form.non_field_errors }}</div>
{% endif %}
{% for field in form %}
<div class="field">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
{% if field.errors %}
<small class="error">{{ field.errors|join:", " }}</small>
{% endif %}
</div>
{% endfor %}
<button class="btn" type="submit">মেসেজ পাঠান</button>
</form>
<aside class="card">
<h3>আমাদের ঠিকানা</h3>
<p>ঢাকা, বাংলাদেশ</p>
<p>ইমেইল: support@shikkhabazar.test</p>
<p>ফোন: +880 1XXX-XXXXXX</p>
</aside>
</div>
{% endblock %}
🔐
{% csrf_token %}ছাড়া POST ফর্ম কাজ করবে না (403 Forbidden দেবে)। এটি Django-র সিকিউরিটি — অন্য সাইট থেকে জাল রিকোয়েস্ট আটকায়। প্রতিটিmethod="post"ফর্মে এটি বাধ্যতামূলক।
১৪. CSS যোগ করা (static file)
ফোল্ডার বানান: static/css/style.css (প্রজেক্টের রুটে)।
static/css/style.css
css
:root {
--brand: #0f766e;
--dark: #0f172a;
--muted: #64748b;
--bg: #f8fafc;
--line: #e2e8f0;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: "Segoe UI", "Nirmala UI", system-ui, sans-serif;
background: var(--bg);
color: var(--dark);
line-height: 1.7;
}
/* ---------- Navbar ---------- */
.navbar {
display: flex; justify-content: space-between; align-items: center;
padding: 16px 32px; background: #fff;
border-bottom: 1px solid var(--line);
position: sticky; top: 0; z-index: 10;
}
.logo { font-size: 22px; font-weight: 700; color: var(--dark); text-decoration: none; }
.logo span { color: var(--brand); }
.navbar nav a {
margin-left: 18px; color: var(--muted);
text-decoration: none; font-weight: 600;
}
.navbar nav a:hover { color: var(--brand); }
/* ---------- Layout ---------- */
.container { max-width: 1060px; margin: 0 auto; padding: 32px 20px 60px; }
.section-title { font-size: 26px; margin: 26px 0 18px; }
.muted { color: var(--muted); font-size: 14px; }
.hero {
background: linear-gradient(135deg, var(--brand), #115e59);
color: #fff; padding: 56px 32px; border-radius: 16px; text-align: center;
}
.hero h1 { font-size: 34px; margin-bottom: 10px; }
.btn {
display: inline-block; margin-top: 14px; padding: 11px 22px;
background: #fff; color: var(--brand); border: 0; border-radius: 8px;
font-weight: 700; cursor: pointer; text-decoration: none;
}
.hero .btn:hover { opacity: .9; }
form .btn { background: var(--brand); color: #fff; }
/* ---------- Cards ---------- */
.grid {
display: grid; gap: 20px;
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.card {
background: #fff; border: 1px solid var(--line);
border-radius: 14px; padding: 18px;
}
.card img { width: 100%; height: 160px; object-fit: cover; border-radius: 10px; margin-bottom: 12px; }
.card h3 { font-size: 18px; margin-bottom: 6px; }
.card-foot { display: flex; justify-content: space-between; align-items: center; margin-top: 12px; }
.price { color: var(--brand); font-weight: 700; }
/* ---------- Forms ---------- */
.two-col { display: grid; gap: 20px; grid-template-columns: 2fr 1fr; }
.field { margin-bottom: 14px; }
.field label { display: block; font-weight: 600; margin-bottom: 5px; font-size: 14px; }
.input {
width: 100%; padding: 10px 12px;
border: 1px solid var(--line); border-radius: 8px; font-size: 15px;
font-family: inherit;
}
.input:focus { outline: 2px solid var(--brand); border-color: transparent; }
.search { display: flex; gap: 10px; margin-bottom: 20px; }
.error { color: #dc2626; font-size: 13px; }
/* ---------- Alerts ---------- */
.alert { padding: 12px 16px; border-radius: 10px; margin-bottom: 18px; font-weight: 600; }
.alert-success { background: #dcfce7; color: #166534; }
.alert-error { background: #fee2e2; color: #991b1b; }
/* ---------- Footer ---------- */
.footer { text-align: center; padding: 22px; color: var(--muted);
border-top: 1px solid var(--line); background: #fff; }
@media (max-width: 720px) {
.two-col { grid-template-columns: 1fr; }
.navbar { flex-direction: column; gap: 10px; }
}
গুরুত্বপূর্ণ: HTML-এ CSS লিংক করতে হলে টেমপ্লেটের একদম উপরে {% load static %} থাকতে হবে, তারপর {% static 'css/style.css' %}। সরাসরি href="/static/css/style.css" লিখবেন না — VPS-এ CDN/পাথ বদলালে ভেঙে যাবে।
১৫. সাইট চালান 🚀
powershell
python manage.py runserver
| পেইজ | লিংক |
|---|---|
| হোম | http://127.0.0.1:8000/ |
| কোর্স | http://127.0.0.1:8000/courses/ |
| যোগাযোগ | http://127.0.0.1:8000/contact/ |
| অ্যাডমিন | http://127.0.0.1:8000/admin/ |
টেস্ট করুন: অ্যাডমিন থেকে কোর্স যোগ করুন → হোম/কোর্স পেইজে দেখাবে। Contact ফর্ম সাবমিট করুন → সবুজ সাকসেস মেসেজ আসবে এবং অ্যাডমিনের Contact messages-এ জমা হবে। ✅
চূড়ান্ত ফোল্ডার স্ট্রাকচার
djnagosite/
├── venv/
├── db.sqlite3
├── manage.py
├── requirements.txt
├── media/ ← আপলোড করা ছবি (অটো তৈরি হবে)
├── shikkhabazar/
│ ├── __init__.py settings.py urls.py asgi.py wsgi.py
├── pages/
│ ├── migrations/ __init__.py admin.py apps.py
│ ├── forms.py models.py tests.py urls.py views.py
├── static/css/style.css
└── templates/
├── base.html
└── pages/home.html courses.html contact.html
শেষে প্যাকেজ লিস্ট সেভ করে রাখুন (VPS-এ হুবহু একই এনভায়রনমেন্ট বানাতে লাগবে):
powershell
pip freeze > requirements.txt
১৬. সাধারণ এরর ও সমাধান
| এরর | কারণ | সমাধান |
|---|---|---|
Activate.ps1 cannot be loaded | Execution policy | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser |
django-admin : not recognized | venv activate করা হয়নি | .\venv\Scripts\Activate.ps1 |
TemplateDoesNotExist | পাথ ভুল / DIRS সেট করা হয়নি | templates/pages/home.html পাথ ও settings.py-এর DIRS চেক করুন |
NoReverseMatch | {% url %}-এর নাম ভুল | app_name + name মিলিয়ে দেখুন: 'pages:home' |
no such table: pages_course | migrate করা হয়নি | makemigrations → migrate |
CSRF verification failed | ফর্মে {% csrf_token %} নেই | ফর্মের ভেতরে যোগ করুন |
| CSS কাজ করছে না | {% load static %} নেই, বা ফোল্ডার ভুল | পাথ ঠিক করে Ctrl+F5 দিয়ে হার্ড রিফ্রেশ |
ModuleNotFoundError: No module named 'pages' | INSTALLED_APPS-এ নেই | অ্যাপ নাম যোগ করুন |
Port already in use | আগের সার্ভার চলছে | Ctrl+C, বা python manage.py runserver 8001 |
| ছবি দেখা যাচ্ছে না | MEDIA কনফিগ/urls.py | MEDIA_URL, MEDIA_ROOT এবং urls.py-এর static(...) লাইন চেক করুন |
১৭. VPS-এ (প্রোডাকশন) যাওয়ার প্রস্তুতি — এখনই যা ঠিক করতে হবে
ডেভেলপমেন্ট আর প্রোডাকশন এক নয়। runserver কখনোই প্রোডাকশনে ব্যবহার করবেন না।
১৭.১ গোপন তথ্য .env ফাইলে সরান
powershell
pip install python-dotenv
settings.py-এর উপরের দিকে:
python
import os
from pathlib import Path
from dotenv import load_dotenv
BASE_DIR = Path(__file__).resolve().parent.parent
load_dotenv(BASE_DIR / ".env")
SECRET_KEY = os.environ.get("DJANGO_SECRET_KEY", "dev-only-unsafe-key")
DEBUG = os.environ.get("DJANGO_DEBUG", "True") == "True"
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "127.0.0.1,localhost").split(",")
CSRF_TRUSTED_ORIGINS = [
o for o in os.environ.get("DJANGO_CSRF_TRUSTED", "").split(",") if o
]
প্রজেক্ট রুটে .env ফাইল (লোকাল):
DJANGO_SECRET_KEY=local-dev-key-change-me
DJANGO_DEBUG=True
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost
VPS-এর .env:
DJANGO_SECRET_KEY=<নতুন-লম্বা-র্যান্ডম-কি>
DJANGO_DEBUG=False
DJANGO_ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
DJANGO_CSRF_TRUSTED=https://yourdomain.com,https://www.yourdomain.com
নতুন SECRET_KEY বানানোর কমান্ড:
powershell
python -c "from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())"
.gitignore ফাইল (রুটে) বানিয়ে লিখুন:
venv/
__pycache__/
*.pyc
db.sqlite3
.env
media/
staticfiles/
১৭.২ প্রোডাকশনে যা যোগ করবেন (DEBUG = False হলে)
python
if not DEBUG:
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
X_FRAME_OPTIONS = "DENY"
ডিপ্লয়ের আগে সবসময় চালাবেন:
powershell
python manage.py check --deploy
১৭.৩ VPS-এর রোডম্যাপ (Ubuntu 24.04 LTS)
| ধাপ | কমান্ড/কাজ |
|---|---|
| ১ | sudo apt update && sudo apt install python3-venv python3-pip nginx postgresql -y |
| ২ | PostgreSQL-এ ডেটাবেজ ও ইউজার তৈরি; pip install psycopg[binary]; settings.py-এ DATABASES বদল |
| ৩ | কোড আপলোড (git clone) → python3 -m venv venv → pip install -r requirements.txt |
| ৪ | python manage.py migrate → python manage.py collectstatic → createsuperuser |
| ৫ | pip install gunicorn; systemd service বানিয়ে gunicorn shikkhabazar.wsgi:application চালান (socket দিয়ে) |
| ৬ | Nginx-এ reverse proxy + /static/ ও /media/ সার্ভ করার কনফিগ |
| ৭ | sudo apt install certbot python3-certbot-nginx → sudo certbot --nginx (ফ্রি HTTPS) |
| ৮ | sudo ufw allow OpenSSH; sudo ufw allow 'Nginx Full'; sudo ufw enable |
Nginx-এর মূল অংশটা দেখতে এমন হবে:
nginx
server {
server_name yourdomain.com www.yourdomain.com;
location /static/ { alias /home/ubuntu/djnagosite/staticfiles/; }
location /media/ { alias /home/ubuntu/djnagosite/media/; }
location / {
include proxy_params;
proxy_pass http://unix:/run/gunicorn.sock;
}
}
মনে রাখবেন: Nginx = দরজার দরবান (static ফাইল ও HTTPS), Gunicorn = Python কোড চালানোর ইঞ্জিন, Django = আপনার অ্যাপ।
১৮. এরপর কী শিখবেন (আপনার লক্ষ্য অনুযায়ী ক্রম)
| ধাপ | বিষয় | এডুকেশন সাইটে | ই-কমার্সে |
|---|---|---|---|
| ১ | Detail view + slug URL (path("courses/<slug:slug>/"), get_object_or_404) | কোর্স ডিটেইল | প্রোডাক্ট ডিটেইল |
| ২ | Model relations (ForeignKey, ManyToManyField) | Category, Lesson, Instructor | Category, Variant |
| ৩ | Pagination (Paginator) | কোর্স লিস্ট | প্রোডাক্ট লিস্ট |
| ৪ | User auth (django.contrib.auth, login/signup) | স্টুডেন্ট অ্যাকাউন্ট | কাস্টমার অ্যাকাউন্ট |
| ৫ | Session | কোর্স প্রগ্রেস | কার্ট |
| ৬ | Forms + Email (send_mail, SMTP) | ভর্তি ফর্ম | অর্ডার কনফার্মেশন |
| ৭ | Class-Based Views (ListView, DetailView) | কম কোডে বেশি কাজ | ঐ |
| ৮ | Payment gateway (SSLCOMMERZ/bKash/Stripe API) | কোর্স কেনা | চেকআউট |
| ৯ | Django REST Framework | মোবাইল অ্যাপ/API | ঐ |
শেখার সবচেয়ে ভালো রেফারেন্স: অফিসিয়াল ডকুমেন্টেশন — https://docs.djangoproject.com/en/5.2/ এবং টিউটোরিয়াল (Polls app): https://docs.djangoproject.com/en/5.2/intro/tutorial01/
১৯. রোজকার কমান্ড চিটশিট
powershell
cd $HOME\Desktop\djnagosite # প্রজেক্টে ঢোকা
.\venv\Scripts\Activate.ps1 # venv চালু (প্রতিদিন প্রথম কাজ)
python manage.py runserver # সার্ভার চালু (বন্ধ: Ctrl+C)
python manage.py makemigrations # model বদলালে
python manage.py migrate # ডেটাবেজে প্রয়োগ
python manage.py createsuperuser # অ্যাডমিন ইউজার
python manage.py shell # ডেটাবেজ নিয়ে পরীক্ষা
python manage.py collectstatic # প্রোডাকশনের আগে
python manage.py check --deploy # ডিপ্লয়ের আগে সিকিউরিটি চেক
pip freeze > requirements.txt # প্যাকেজ লিস্ট সেভ
deactivate # venv বন্ধ
ধাপগুলো ঠিক ক্রমে করলে কোনো এরর আসবে না। কোনো ধাপে আটকে গেলে PowerShell-এর পুরো লাল এরর মেসেজটা আমাকে কপি করে পাঠিয়ে দিন — ঠিক করে দেব।
পরের ধাপে কী করতে চান — (ক) কোর্স ডিটেইল পেইজ + Category যোগ করা, (খ) লগইন/রেজিস্ট্রেশন সিস্টেম, নাকি (গ) ই-কমার্স কার্ট? বলুন, সেটাই একইভাবে শূন্য থেকে ব্যাখ্যা করে দেব।