Web Framework Architecture
A web framework essentially consists of a socket server that communicates with browsers. The server-side responsibilities break down into three functional areas:
- Message handling - exchanging data with browsers via socket communication (handled by wsgiref, uWSGI, or Gunicorn)
- Request routing - mapping user requests to specific handler functions
- Template rendering - loading HTML content and performing string substitution (typically using Jinja2)
WSGI Specification
WSGI (Web Server Gateway Interface) defines a standardized interface between web applications and web servers. This specification enables loose coupling between application code and server implementations.
Common WSGI server options:
- uwsgi and Gunicorn - production-grade servers
- wsgiref - Python's built-in reference implementation, used by Django's development server
ORM Operations
Querying Records
all_users = models.UserInfo.objects.all()
filtered_users = models.User.objects.filter(status='active')
Creating Records
models.UserInfo.objects.create(username="alice", email="alice@example.com")
Ordering Results
publishers = models.Publisher.objects.all().order_by("-id") # descending
Deleting Records
# Method 1: fetch then delete
target = models.Publisher.objects.get(id=record_id)
target.delete()
# Method 2: direct deletion
models.Publisher.objects.filter(id=7).delete()
Updating Records
target_id = request.POST.get("publisher_id")
new_name = request.POST.get("publisher_name")
publisher = models.Publisher.objects.get(id=target_id)
publisher.name = new_name
publisher.save()
Database Schema Design
from django.db import models
class Publisher(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=64, null=False, unique=True)
address = models.CharField(max_length=128)
established_date = models.DateField(auto_now_add=True)
def __str__(self):
return f"<Publisher: {self.name}>"
class Book(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=64, null=False, unique=True)
publication_year = models.IntegerField(default=2023)
publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE)
def __str__(self):
return f"<Book: {self.title}>"
class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32, null=False, unique=True)
bio = models.TextField(blank=True)
# Many-to-many relationship managed automatically by Django ORM
written_books = models.ManyToManyField(to="Book", related_name="authors")
def __str__(self):
return f"<Author: {self.name}>"
Relationship Types
| Relationship | Implementation | Example |
|---|---|---|
| One-to-Many | ForeignKey | Book → Publisher |
| Many-to-Many | ManyToManyField | Author ↔ Book |
Creating Books
# Using foreign key ID directly
models.Book.objects.create(
title="New Title",
publisher_id=selected_publisher_id
)
# Using related object
publisher_instance = models.Publisher.objects.get(id=selected_publisher_id)
models.Book.objects.create(
title="Another Title",
publisher=publisher_instance
)
Querying Many-to-Many Relationships
{% for author in author_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ author.id }}</td>
<td>{{ author.name }}</td>
<td>
{% for book in author.written_books.all %}
<span>{{ book.title }}</span>
{% endfor %}
</td>
</tr>
{% endfor %}
Custom Template Filters
Template filters are functions that accept one or two parameters. In {{ variable|filter_name:argument }}, the filter receives variable and argument.
Project Structure
myapp/
__init__.py
models.py
templatetags/
__init__.py
custom_filters.py
views.py
Defining Filters
from django import template
register = template.Library()
@register.filter(name="truncate_wrapped")
def truncate_wrapped(text):
"""Wraps text with suffix"""
return f"{text} [filtered]"
@register.filter(name="greet")
def greet_user(name, greeting):
"""
First parameter: value before the pipe operator
Second parameter: value after the colon
"""
return f"{greeting}, {name}!"
Using Filters in Templates
{% load custom_filters %}
{{ username|truncate_wrapped }}
{{ username|greet:"Hello" }}
Custom Simple Tags
Simple tags offer more flexibility than filters, accepting multiple parameters.
Definition
@register.simple_tag(name="calculate")
def calculate_sum(a, b, c):
return f"{a} + {b} + {c} = {a + b + c}"
Usage
{% load custom_filters %}
{% calculate 10 20 30 %}
Inclusion Tags
Inclusion tags render HTML fragments, useful for reusable components.
Definition
@register.inclusion_tag('components/list_items.html')
def render_list(count):
count = max(1, int(count))
items = [f"Item #{i}" for i in range(1, count + 1)]
return {"items": items}
Template (components/list_items.html)
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
Usage
{% load custom_filters %}
{% render_list 5 %}
Class-Based Views
from django.views import View
class PublisherCreate(View):
def get(self, request):
return render(request, 'create_publisher.html')
def post(self, request):
name = request.POST.get('name')
models.Publisher.objects.create(name=name)
return redirect('/publishers')
URL Reverse Resolution
Named URL patterns enable dynamic URL generation, decoupling templates and views from hardcoded paths.
Defining Named Routes
urlpatterns = [
url(r'^publishers/$', views.publisher_list, name='publisher_list'),
url(r'^publishers/(?P<pk>\d+)/$', views.publisher_detail, name='publisher_detail'),
]
In Templates
<a href="{% url 'publisher_list' %}">All Publishers</a>
<a href="{% url 'publisher_detail' publisher.id %}">View Details</a>
In Views
from django.urls import reverse
# Without parameters
list_url = reverse('publisher_list')
# With positional arguments
detail_url = reverse('publisher_detail', args=(42,))
# With keyword arguments
detail_url = reverse('publisher_detail', kwargs={'pk': 42})
URL Routing Patterns
Positional Regex Groups
url(r'^books/([0-9]{4})/([a-z]+)/$', views.book_detail, name='book_detail'),
# Captures: year, category
Named Regex Groups
url(r'^books/(?P<year>[0-9]{4})/(?P<category>[a-z]+)/$',
views.book_detail,
name='book_detail'),
# Captures: year, category as keyword arguments
ORM Field Reference
Common Field Types
class ExampleModel(models.Model):
# Auto-incrementing primary key
id = models.AutoField(primary_key=True)
# Variable-length string
name = models.CharField(max_length=100)
# Foreign key relationship
category = models.ForeignKey(
to='Category',
on_delete=models.CASCADE,
related_name='items'
)
# Many-to-many relationship
tags = models.ManyToManyField(to='Tag')
# Date and time fields
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
event_date = models.DateField()
event_time = models.TimeField()
# Numeric fields
quantity = models.IntegerField(default=0)
price = models.DecimalField(max_digits=10, decimal_places=2)
Field Parameters
| Parameter | Purpose | Example |
|---|---|---|
null |
Allow NULL in database | null=True |
blank |
Allow empty in forms | blank=True |
default |
Default value | default='pending' |
unique |
Enforce uniqueness | unique=True |
db_index |
Create database index | db_index=True |
choices |
Limit to predefined values | choices=STATUS_CHOICES |
Meta Options
class Meta:
db_table = 'custom_table_name'
ordering = ['-created_at']
verbose_name = 'Custom Name'
verbose_name_plural = 'Custom Names'
CRUD Operations Summary
Single Table Operations
# Create
publisher = models.Publisher.objects.create(name="New Publisher")
# Read
publisher = models.Publisher.objects.get(id=1)
all_publishers = models.Publisher.objects.all()
# Update
publisher = models.Publisher.objects.get(id=1)
publisher.name = "Updated Name"
publisher.save()
# Delete
models.Publisher.objects.get(id=1).delete()
Foreign Key Access
book = models.Book.objects.get(id=1)
# Access related object
book.publisher.name
# Access foreign key value directly
book.publisher_id
# Set relationship
book.publisher = new_publisher
book.save()
Many-to-Many Operations
author = models.Author.objects.get(id=1)
# Get all books by author
author.written_books.all()
# Set multiple books
author.written_books.set([book1, book2, book3])
# Add single book
author.written_books.add(book4)
# Remove book
author.written_books.remove(book4)
# Clear all relationships
author.written_books.clear()
DateTime Utilities
import datetime
current_time = datetime.datetime.now()
print(f"Now: {current_time}")
# Time delta calculations
one_day = datetime.timedelta(days=1)
one_week = datetime.timedelta(weeks=1)
expiry_date = current_time + datetime.timedelta(days=7)
# Date formatting
formatted = current_time.strftime("%Y-%m-%d %H:%M:%S")
Running Django Outside Management Script
#!/usr/bin/env python
import os
import sys
if __name__ == '__main__':
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project_name.settings")
import django
django.setup()
from myapp import models
# Now you can use ORM here
all_books = models.Book.objects.select_related('publisher').all()
for book in all_books:
print(f"{book.title} - {book.publisher.name}")