Understanding Web Frameworks
A web framework is a structured foundation designed to solve common development problems, providing constraints and support for building specific systems efficiently. Essentially, it offers a pre-built platform for application development.
At its core, every web application functions as a socket server, with user browsers acting as socket clients.
import socket
def process_request(client_socket):
request_data = client_socket.recv(1024)
client_socket.send("HTTP/1.1 200 OK\r\n\r\n".encode("utf8"))
client_socket.send("<h1 style='color:blue'>Hello World</h1>".encode("utf8"))
def start_server():
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('localhost', 8000))
server_socket.listen(5)
while True:
connection, addr = server_socket.accept()
process_request(connection)
connection.close()
if __name__ == '__main__':
start_server()
The simplest web applications serve static HTML files through existing HTTP server software. For dynamic contant generation, handling HTTP requests, parsing, and response sending becomes necessary. These low-level tasks are typically handled by specialized server software, allowing developers to focus on business logic using interfaces like WSGI (Web Server Gateway Interface).
Building a Basic Web Framework
Step 1: WSGI Implementation
from wsgiref.simple_server import make_server
def wsgi_app(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html')])
return [b'<h1>Hello, Web!</h1>']
server = make_server('', 8080, wsgi_app)
print('Server running on port 8080...')
server.serve_forever()
The wsgi_app function receives two parameters: environ (a dictionary containing HTTP request information) and start_response (a function for sending HTTP response headers). Headers can only be sent once per response.
Step 2: Path-Based Routing
path = environ['PATH_INFO']
start_response('200 OK', [('Content-Type', 'text/html')])
if path == "/home":
with open("home.html", "rb") as f:
return [f.read()]
elif path == "/about":
with open("about.html", "rb") as f:
return [f.read()]
else:
return ["<h1>404 Not Found</h1>".encode('utf8')]
Step 3: Modular Handler Functions
from wsgiref.simple_server import make_server
def home_handler():
with open("home.html", "rb") as f:
return [f.read()]
def about_handler():
with open("about.html", "rb") as f:
return [f.read()]
def application(environ, start_response):
path = environ['PATH_INFO']
start_response('200 OK', [('Content-Type', 'text/html')])
if path == "/home":
return home_handler()
elif path == "/about":
return about_handler()
else:
return ["<h1>404</h1>".encode("utf8")]
httpd = make_server('', 8502, application)
httpd.serve_forever()
Step 4: Advanced Routing with Templates
from wsgiref.simple_server import make_server
import time
def home_handler(request):
with open("home.html", "rb") as f:
return [f.read()]
def about_handler(request):
with open("about.html", "rb") as f:
return [f.read()]
def time_handler(request):
with open("time.html", "rb") as f:
content = str(f.read(), "utf8")
current_time = time.strftime("%Y-%m-%d %X", time.localtime())
return [content.replace("!time!", current_time).encode("utf8")]
def setup_routes():
return (
('/home', home_handler),
('/about', about_handler),
("/current_time", time_handler)
)
def application(environ, start_response):
path = environ['PATH_INFO']
start_response('200 OK', [('Content-Type', 'text/html')])
routes = setup_routes()
handler = None
for route_path, route_handler in routes:
if route_path == path:
handler = route_handler
break
if handler:
return handler(environ)
else:
return ["<h1>404</h1>".encode("utf8")]
server = make_server('', 8518, application)
server.serve_forever()
MVC and MTV Patterns
Django's MTV pattern maintains loose coupling between components:
- Model: Handles business objects and database operations (ORM)
- Template: Manages presentation layer and user interface
- View: Implements business logic and coordinates Model and Template
Additionally, Django includes a URL dispatcher that routes requests to appropriate views.
Django Basic Commands
Create a Django project:
django-admin startproject myproject
Create an application:
python manage.py startapp blog
Start development server:
python manage.py runserver 8080
Database migrations:
python manage.py makemigrations
python manage.py migrate
Create superuser:
python manage.py createsuperuser
Django shell:
python manage.py shell
Static File Configuration
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static_files"),
)
URL Configuration System
URL patterns map URLs to view functions:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
Named Groups
urlpatterns = [
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
]
Including Other URLconfs
from django.conf.urls import include, url
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^blog/', include('blog.urls')),
]
Named URLs
urlpatterns = [
url(r'^index', views.index, name='index_page'),
]
View Functions
Views receive web requests and return responses:
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>Current time: %s</body></html>" % now
return HttpResponse(html)
Shortcut Functions
Render template:
from django.shortcuts import render
def my_view(request):
return render(request, 'template.html', {'variable': 'value'})
Redirect:
from django.shortcuts import redirect
def login_view(request):
if request.method == "POST":
return redirect("/dashboard/")
return render(request, "login.html")
Template System
Templates combine HTML with logic control code using variables {{ variable }} and tags {% tag %}.
Variable Filters
{{ value|upper }}
{{ value|add:3 }}
{{ value|date:'Y-m-d' }}
{{ value|default:'empty' }}
Template Tags
Conditional statements:
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}</p>
{% else %}
<p>Please log in.</p>
{% endif %}
Loops:
<ul>
{% for item in item_list %}
<li>{{ forloop.counter }}: {{ item.name }}</li>
{% endfor %}
</ul>
CSRF protection:
<form method="post">
{% csrf_token %}
<!-- form fields -->
</form>
URL references:
<a href="{% url 'index_page' %}">Home</a>
Template Inheritance
Base template (base.html):
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>Site Header</h1>
{% block content %}{% endblock %}
{% block footer %}
<p>Thanks for visiting.</p>
{% endblock %}
</body>
</html>
Child template:
{% extends "base.html" %}
{% block title %}Page Title{% endblock %}
{% block content %}
<p>Page content goes here.</p>
{% endblock %}
Database and ORM
Database Configuraton
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydatabase',
'USER': 'myuser',
'PASSWORD': 'mypassword',
'HOST': 'localhost',
'PORT': '3306',
}
}
Model Definition
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
class Meta:
verbose_name = 'Publisher'
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
price = models.DecimalField(max_digits=5, decimal_places=2, default=10)
def __str__(self):
return self.title
ORM Operations
Create records:
# Method 1
Author.objects.create(name='John')
# Method 2
author = Author(name='Jane')
author.save()
Query records:
# Get all authors
authors = Author.objects.all()
# Filter authors
authors = Author.objects.filter(name__startswith='J')
# Get single object
author = Author.objects.get(id=1)
Update records:
Author.objects.filter(id=1).update(name='Updated Name')
Delete records:
Author.objects.filter(id=1).delete()
Complex queries:
from django.db.models import Q, F
# OR queries
books = Book.objects.filter(Q(title__startswith='P') | Q(title__startswith='J'))
# Field comparisons
Book.objects.filter(price__gt=F('discount_price'))
Admin Interface Configuration
from django.contrib import admin
from .models import Book, Author, Publisher
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ("title", "price", "publisher")
search_fields = ("title", "publisher")
list_filter = ("publisher",)
ordering = ("price",)
fieldsets = [
(None, {'fields': ['title']}),
('Pricing', {'fields': ['price', 'publisher'], 'classes': ['collapse']}),
]
admin.site.register(Author)
admin.site.register(Publisher)