Learn Django framework fundamentals including installation, project structure, settings configuration, and URL routing for web development.
Learn Django framework fundamentals including installation, project structure, settings configuration, and URL routing for web development.
Learn how to install Django, set up a virtual environment, and create a new Django project.
Content by: Manali Trivedi
Python Django Developer
Django is a high-level Python web framework that encourages rapid development and clean, pragmatic design. It follows the Model-View-Template (MVT) pattern and includes many built-in features.
# Install Django using pip
pip install django
# Check Django version
python -m django --version
# Create a virtual environment (recommended)
python -m venv myenv
# Activate virtual environment
# On Windows:
myenv\Scripts\activate
# On macOS/Linux:
source myenv/bin/activate
# Install Django in virtual environment
pip install django
# Create a new Django project
django-admin startproject myproject
# Navigate to project directory
cd myproject
# Run the development server
python manage.py runserver
# Access your site at http://127.0.0.1:8000/
# Django Project Setup Script
import os
import subprocess
import sys
def create_django_project():
"""Automated Django project setup"""
project_name = input("Enter project name: ")
# Create virtual environment
print(f"Creating virtual environment for {project_name}...")
subprocess.run([sys.executable, "-m", "venv", f"{project_name}_env"])
# Activate virtual environment and install Django
if os.name == 'nt': # Windows
activate_script = f"{project_name}_env\Scripts\activate"
pip_path = f"{project_name}_env\Scripts\pip"
else: # macOS/Linux
activate_script = f"{project_name}_env/bin/activate"
pip_path = f"{project_name}_env/bin/pip"
print("Installing Django...")
subprocess.run([pip_path, "install", "django"])
# Create Django project
print(f"Creating Django project: {project_name}")
subprocess.run([pip_path, "run", "django-admin", "startproject", project_name])
print(f"\nProject {project_name} created successfully!")
print(f"To get started:")
print(f"1. cd {project_name}")
print(f"2. Activate virtual environment: {activate_script}")
print(f"3. Run: python manage.py runserver")
if __name__ == "__main__":
create_django_project()
Test your understanding of this topic:
Understand the structure of a Django project and how to organize apps within it.
Content by: Manali Trivedi
Python Django Developer
Django projects have a specific structure that helps organize code and follows best practices for web development.
myproject/
āāā manage.py # Django's command-line utility
āāā myproject/ # Project configuration directory
ā āāā __init__.py
ā āāā settings.py # Project settings
ā āāā urls.py # URL declarations
ā āāā asgi.py # ASGI config
ā āāā wsgi.py # WSGI config
āāā apps/ # Application directory (custom)
āāā blog/ # Example app
āāā __init__.py
āāā admin.py # Admin interface
āāā apps.py # App configuration
āāā models.py # Database models
āāā tests.py # Unit tests
āāā urls.py # App URL patterns
āāā views.py # View functions
# Create a new app
python manage.py startapp blog
# Add app to INSTALLED_APPS in settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog', # Add your app here
]
# Django App Generator
import os
import re
class DjangoAppGenerator:
def __init__(self, project_root):
self.project_root = project_root
self.apps_dir = os.path.join(project_root, 'apps')
# Create apps directory if it doesn't exist
if not os.path.exists(self.apps_dir):
os.makedirs(self.apps_dir)
def create_app(self, app_name):
"""Create a new Django app with proper structure"""
app_path = os.path.join(self.apps_dir, app_name)
if os.path.exists(app_path):
print(f"App {app_name} already exists!")
return False
# Create app directory
os.makedirs(app_path)
# Create __init__.py
with open(os.path.join(app_path, '__init__.py'), 'w') as f:
f.write("# Django app initialization\n")
# Create apps.py
apps_content = f'''from django.apps import AppConfig
class {app_name.capitalize()}Config(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.{app_name}'
verbose_name = '{app_name.replace("_", " ").title()}'
'''
with open(os.path.join(app_path, 'apps.py'), 'w') as f:
f.write(apps_content)
# Create models.py
models_content = '''from django.db import models
# Define your models here
class ExampleModel(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Meta:
verbose_name = "Example Model"
verbose_name_plural = "Example Models"
'''
with open(os.path.join(app_path, 'models.py'), 'w') as f:
f.write(models_content)
# Create views.py
views_content = '''from django.shortcuts import render
from django.http import HttpResponse
# Define your views here
def index(request):
return HttpResponse(f"Welcome to {app_name} app!")
def about(request):
return HttpResponse(f"This is the about page for {app_name} app.")
'''
with open(os.path.join(app_path, 'views.py'), 'w') as f:
f.write(views_content)
# Create urls.py
urls_content = f'''from django.urls import path
from . import views
app_name = '{app_name}'
urlpatterns = [
path('', views.index, name='index'),
path('about/', views.about, name='about'),
]
'''
with open(os.path.join(app_path, 'urls.py'), 'w') as f:
f.write(urls_content)
# Create admin.py
admin_content = f'''from django.contrib import admin
from .models import ExampleModel
@admin.register(ExampleModel)
class ExampleModelAdmin(admin.ModelAdmin):
list_display = ['name', 'created_at']
list_filter = ['created_at']
search_fields = ['name', 'description']
'''
with open(os.path.join(app_path, 'admin.py'), 'w') as f:
f.write(admin_content)
# Create tests.py
tests_content = f'''from django.test import TestCase
from .models import ExampleModel
class {app_name.capitalize()}ModelTests(TestCase):
def test_example_model_creation(self):
model = ExampleModel.objects.create(
name="Test Model",
description="Test Description"
)
self.assertEqual(model.name, "Test Model")
self.assertEqual(model.description, "Test Description")
'''
with open(os.path.join(app_path, 'tests.py'), 'w') as f:
f.write(tests_content)
print(f"App {app_name} created successfully in {app_path}")
return True
# Usage example
if __name__ == "__main__":
generator = DjangoAppGenerator(".")
generator.create_app("blog")
generator.create_app("users")
Test your understanding of this topic:
Explore the configuration options in Django's settings.py file for customizing your project.
Content by: Manali Trivedi
Python Django Developer
The settings.py file contains all the configuration for your Django project. Understanding these settings is crucial for proper project setup.
# settings.py
import os
from pathlib import Path
# Build paths inside the project
BASE_DIR = Path(__file__).resolve().parent.parent
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'your-secret-key-here'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog', # Your app
]
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',
]
ROOT_URLCONF = 'myproject.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'myproject.wsgi.application'
# Database
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Static files (CSS, JavaScript, Images)
STATIC_URL = '/static/'
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
# Internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Environment-based Django settings
import os
from pathlib import Path
from decouple import config
# Build paths inside the project
BASE_DIR = Path(__file__).resolve().parent.parent
# Environment configuration
ENVIRONMENT = config('ENVIRONMENT', default='development')
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config('SECRET_KEY', default='your-secret-key-here')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = config('DEBUG', default=True, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='localhost,127.0.0.1', cast=lambda v: [s.strip() for s in v.split(',')])
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
'users',
]
# Database configuration based on environment
if ENVIRONMENT == 'production':
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('DB_NAME'),
'USER': config('DB_USER'),
'PASSWORD': config('DB_PASSWORD'),
'HOST': config('DB_HOST'),
'PORT': config('DB_PORT', default='5432'),
}
}
# Production-specific settings
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
else:
# Development database
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Static files configuration
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
# Media files
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
# Logging configuration
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
'style': '{',
},
},
'handlers': {
'file': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': BASE_DIR / 'logs' / 'django.log',
'formatter': 'verbose',
},
},
'root': {
'handlers': ['file'],
'level': 'INFO',
},
}
# Create logs directory if it doesn't exist
os.makedirs(BASE_DIR / 'logs', exist_ok=True)
Test your understanding of this topic:
Master Django's URL routing system to map requests to views and handle dynamic URLs.
Content by: Manali Trivedi
Python Django Developer
Django uses URL patterns to route requests to the appropriate views. Understanding URL configuration is essential for building web applications.
# myproject/urls.py (Main URL configuration)
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls')), # Include app URLs
path('', include('home.urls')), # Home page URLs
]
# Serve static and media files in development
if settings.DEBUG:
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
# blog/urls.py (App-specific URLs)
from django.urls import path
from . import views
app_name = 'blog' # URL namespace
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
path('post/new/', views.post_new, name='post_new'),
path('post/<int:pk>/edit/', views.post_edit, name='post_edit'),
]
# home/urls.py (Home page URLs)
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path('about/', views.about, name='about'),
path('contact/', views.contact, name='contact'),
]
# URL Patterns with Parameters
# Integer parameters
path('post/<int:pk>/', views.post_detail, name='post_detail'),
# String parameters
path('category/<str:category>/', views.category_posts, name='category_posts'),
# Slug parameters
path('post/<slug:slug>/', views.post_detail, name='post_detail'),
# UUID parameters
path('user/<uuid:user_id>/', views.user_profile, name='user_profile'),
# Multiple parameters
path('post/<int:year>/<int:month>/<slug:slug>/', views.post_detail, name='post_detail'),
# Dynamic URL Router for Django
from django.urls import path, re_path
from django.http import HttpResponse
from django.views.generic import TemplateView
class DynamicRouter:
"""A dynamic URL router that can generate URLs based on patterns"""
def __init__(self):
self.routes = {}
def add_route(self, pattern, view_func, name=None):
"""Add a new route pattern"""
self.routes[pattern] = {
'view': view_func,
'name': name or pattern
}
def get_urlpatterns(self):
"""Convert routes to Django URL patterns"""
urlpatterns = []
for pattern, route_info in self.routes.items():
# Convert pattern to Django path
if '<' in pattern and '>' in pattern:
# Dynamic parameter pattern
django_pattern = self._convert_pattern(pattern)
urlpatterns.append(
path(django_pattern, route_info['view'], name=route_info['name'])
)
else:
# Static pattern
urlpatterns.append(
path(pattern, route_info['view'], name=route_info['name'])
)
return urlpatterns
def _convert_pattern(self, pattern):
"""Convert custom pattern to Django URL pattern"""
# Example: /user/{id}/profile -> /user/<int:id>/profile
import re
# Replace {param} with <type:param>
pattern = re.sub(r'\{([^}]+)\}', r'<str:\1>', pattern)
# Add type hints for common patterns
pattern = re.sub(r'<str:id>', '<int:id>', pattern)
pattern = re.sub(r'<str:pk>', '<int:pk>', pattern)
pattern = re.sub(r'<str:slug>', '<slug:slug>', pattern)
return pattern
# Example usage
def user_profile(request, user_id):
return HttpResponse(f"User Profile: {user_id}")
def post_detail(request, post_id):
return HttpResponse(f"Post Detail: {post_id}")
def category_posts(request, category):
return HttpResponse(f"Category: {category}")
# Create router and add routes
router = DynamicRouter()
router.add_route('user/{id}/profile', user_profile, 'user_profile')
router.add_route('post/{id}', post_detail, 'post_detail')
router.add_route('category/{category}', category_posts, 'category_posts')
# Generate URL patterns
urlpatterns = router.get_urlpatterns()
# This would be used in your urls.py like:
# from .router import urlpatterns
# urlpatterns += urlpatterns
Test your understanding of this topic:
Learn to work with Django templates, static files, and the template language for building dynamic web pages.
Content by: Manali Trivedi
Python Django Developer
Django templates are HTML files that can contain Django template language syntax for dynamic content rendering.
<!-- base.html - Base template -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}My Django Site{% endblock %}</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<header>
<nav>
<ul>
<li><a href="{% url 'home' %}">Home</a></li>
<li><a href="{% url 'blog:post_list' %}">Blog</a></li>
<li><a href="{% url 'about' %}">About</a></li>
<li><a href="{% url 'contact' %}">Contact</a></li>
</ul>
</nav>
</header>
<main>
{% block content %}
{% endblock %}
</main>
<footer>
<p>© 2024 My Django Site. All rights reserved.</p>
</footer>
<script src="{% static 'js/main.js' %}"></script>
</body>
</html>
<!-- post_list.html - Extends base template -->
{% extends 'base.html' %}
{% load static %}
{% block title %}Blog Posts{% endblock %}
{% block content %}
<div class="container">
<h1>Blog Posts</h1>
{% if posts %}
<div class="posts-grid">
{% for post in posts %}
<article class="post-card">
<h2><a href="{% url 'blog:post_detail' post.pk %}">{{ post.title }}</a></h2>
<p class="post-meta">
By {{ post.author }} on {{ post.published_date|date:"F j, Y" }}
</p>
<p class="post-excerpt">{{ post.excerpt|truncatewords:30 }}</p>
<div class="post-tags">
{% for tag in post.tags.all %}
<span class="tag">{{ tag.name }}</span>
{% endfor %}
</div>
</article>
{% endfor %}
</div>
{% if is_paginated %}
<div class="pagination">
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">« Previous</a>
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.num_pages }}
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">Next »</a>
{% endif %}
</div>
{% endif %}
{% else %}
<p>No posts available.</p>
{% endif %}
</div>
{% endblock %}
# Custom template tags for Django
from django import template
from django.utils.safestring import mark_safe
import markdown
from datetime import datetime, timedelta
register = template.Library()
@register.filter(name='markdown')
def markdown_filter(text):
"""Convert markdown text to HTML"""
return mark_safe(markdown.markdown(text))
@register.filter(name='time_ago')
def time_ago_filter(value):
"""Show relative time (e.g., '2 hours ago')"""
if not value:
return ""
now = datetime.now()
if value.tzinfo:
now = now.replace(tzinfo=value.tzinfo)
diff = now - value
if diff.days > 0:
return f"{diff.days} day{'s' if diff.days != 1 else ''} ago"
elif diff.seconds > 3600:
hours = diff.seconds // 3600
return f"{hours} hour{'s' if hours != 1 else ''} ago"
elif diff.seconds > 60:
minutes = diff.seconds // 60
return f"{minutes} minute{'s' if minutes != 1 else ''} ago"
else:
return "Just now"
@register.simple_tag
def get_recent_posts(count=5):
"""Get recent blog posts"""
from blog.models import Post
return Post.objects.filter(status='published').order_by('-published_date')[:count]
@register.inclusion_tag('blog/tags/post_tags.html')
def show_post_tags(post):
"""Display post tags with custom styling"""
return {'tags': post.tags.all()}
# Usage in templates:
# {{ post.content|markdown }}
# {{ post.published_date|time_ago }}
# {% get_recent_posts 3 as recent_posts %}
# {% show_post_tags post %}
# post_tags.html template:
"""
<div class="post-tags">
{% for tag in tags %}
<a href="{% url 'blog:tag_posts' tag.slug %}" class="tag tag-{{ tag.color }}">
{{ tag.name }}
</a>
{% endfor %}
</div>
"""
Test your understanding of this topic:
Continue your learning journey and master the next set of concepts.
Continue to Module 3