Views & Templates
Views are Python functions or classes that receive web requests and return web responses. Templates are text files that define the structure and layout of the response.
Function-Based Views
Basic Views
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from .models import Article
def hello_world(request):
return HttpResponse("Hello, World!")
def article_list(request):
articles = Article.objects.all()
context = {'articles': articles}
return render(request, 'articles/list.html', context)
def article_detail(request, article_id):
article = get_object_or_404(Article, id=article_id)
return render(request, 'articles/detail.html', {'article': article})
Handling Different HTTP Methods
from django.views.decorators.http import require_http_methods
from django.http import JsonResponse
import json
@require_http_methods(["GET", "POST"])
def api_articles(request):
if request.method == 'GET':
articles = Article.objects.values('id', 'title', 'content')
return JsonResponse({'articles': list(articles)})
elif request.method == 'POST':
data = json.loads(request.body)
article = Article.objects.create(
title=data['title'],
content=data['content']
)
return JsonResponse({'id': article.id, 'status': 'created'})
Class-Based Views
Generic Views
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Article
from .forms import ArticleForm
class ArticleListView(ListView):
model = Article
template_name = 'articles/list.html'
context_object_name = 'articles'
paginate_by = 10
def get_queryset(self):
return Article.objects.filter(published=True)
class ArticleDetailView(DetailView):
model = Article
template_name = 'articles/detail.html'
context_object_name = 'article'
class ArticleCreateView(CreateView):
model = Article
form_class = ArticleForm
template_name = 'articles/create.html'
success_url = reverse_lazy('article_list')
class ArticleUpdateView(UpdateView):
model = Article
form_class = ArticleForm
template_name = 'articles/update.html'
def get_success_url(self):
return reverse_lazy('article_detail', kwargs={'pk': self.object.pk})
class ArticleDeleteView(DeleteView):
model = Article
template_name = 'articles/confirm_delete.html'
success_url = reverse_lazy('article_list')
Custom Class-Based Views
from django.views import View
from django.http import JsonResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
@method_decorator(csrf_exempt, name='dispatch')
class ArticleAPIView(View):
def get(self, request, *args, **kwargs):
articles = Article.objects.values('id', 'title', 'published')
return JsonResponse({'articles': list(articles)})
def post(self, request, *args, **kwargs):
import json
data = json.loads(request.body)
article = Article.objects.create(**data)
return JsonResponse({'id': article.id, 'status': 'created'})
Templates
Template Syntax
Variables
<!-- Display variable -->
<h1>{{ article.title }}</h1>
<p>{{ article.content }}</p>
<!-- Attribute access -->
<p>Author: {{ article.author.full_name }}</p>
<!-- Dictionary access -->
<p>{{ user.profile.bio }}</p>
Tags
<!-- Conditionals -->
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}!</p>
{% else %}
<p>Please log in.</p>
{% endif %}
<!-- Loops -->
{% for article in articles %}
<div class="article">
<h3>{{ article.title }}</h3>
<p>{{ article.summary }}</p>
</div>
{% empty %}
<p>No articles found.</p>
{% endfor %}
<!-- URL generation -->
<a href="{% url 'article_detail' article.id %}">Read more</a>
Filters
<!-- String filters -->
{{ article.title|title }} {{ article.content|truncatewords:50 }} {{
article.content|linebreaks }}
<!-- Date filters -->
{{ article.created_at|date:"F d, Y" }} {{ article.created_at|timesince }}
<!-- Numeric filters -->
{{ price|floatformat:2 }} {{ total|default:0 }}
<!-- List filters -->
{{ tags|join:", " }} {{ articles|length }}
Template Inheritance
Base Template (base.html)
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}" />
{% block extra_css %}{% endblock %}
</head>
<body>
<header>
<nav>
<a href="{% url 'home' %}">Home</a>
<a href="{% url 'article_list' %}">Articles</a>
{% if user.is_authenticated %}
<a href="{% url 'logout' %}">Logout</a>
{% else %}
<a href="{% url 'login' %}">Login</a>
{% endif %}
</nav>
</header>
<main>{% block content %} {% endblock %}</main>
<footer>
<p>© 2024 My Site</p>
</footer>
{% block extra_js %}{% endblock %}
</body>
</html>
Child Template
{% extends 'base.html' %} {% load static %} {% block title %}{{ article.title }}
- My Site{% endblock %} {% block extra_css %}
<link rel="stylesheet" href="{% static 'css/articles.css' %}" />
{% endblock %} {% block content %}
<article>
<header>
<h1>{{ article.title }}</h1>
<p class="meta">
By {{ article.author.full_name }} on {{ article.created_at|date:"F d, Y"
}}
</p>
</header>
<div class="content">{{ article.content|linebreaks }}</div>
<footer>
<div class="tags">
{% for tag in article.tags.all %}
<span class="tag">{{ tag.name }}</span>
{% endfor %}
</div>
</footer>
</article>
{% endblock %}
Template Tags and Filters
Custom Template Tags
# templatetags/article_tags.py
from django import template
from ..models import Article
register = template.Library()
@register.simple_tag
def recent_articles(count=5):
return Article.objects.filter(published=True)[:count]
@register.inclusion_tag('articles/recent_list.html')
def show_recent_articles(count=5):
articles = Article.objects.filter(published=True)[:count]
return {'articles': articles}
@register.filter
def multiply(value, arg):
return value * arg
Using Custom Tags
{% load article_tags %}
<!-- Simple tag -->
{% recent_articles 3 as recent %} {% for article in recent %}
<p>{{ article.title }}</p>
{% endfor %}
<!-- Inclusion tag -->
{% show_recent_articles 5 %}
<!-- Custom filter -->
{{ price|multiply:1.2 }}
Static Files
Configuration
# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
STATIC_ROOT = BASE_DIR / 'staticfiles' # For production
MEDIA_URL = '/media/'
MEDIA_ROOT = BASE_DIR / 'media'
Using Static Files
{% load static %}
<!-- CSS -->
<link rel="stylesheet" href="{% static 'css/style.css' %}" />
<!-- JavaScript -->
<script src="{% static 'js/app.js' %}"></script>
<!-- Images -->
<img src="{% static 'images/logo.png' %}" alt="Logo" />
<!-- User uploaded media -->
<img src="{{ article.image.url }}" alt="{{ article.title }}" />
Request and Response Objects
Request Object
def my_view(request):
# HTTP method
if request.method == 'POST':
# Form data
title = request.POST.get('title')
# Files
uploaded_file = request.FILES.get('file')
# Query parameters
search = request.GET.get('search', '')
# Headers
user_agent = request.META.get('HTTP_USER_AGENT')
# User
if request.user.is_authenticated:
user_id = request.user.id
# Session
request.session['key'] = 'value'
value = request.session.get('key')
Response Types
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.shortcuts import redirect, render
from django.urls import reverse
# HTML response
return render(request, 'template.html', context)
# JSON response
return JsonResponse({'status': 'success', 'data': data})
# Plain text
return HttpResponse('Plain text response', content_type='text/plain')
# Redirect
return redirect('view_name')
return redirect('view_name', pk=object.pk)
return HttpResponseRedirect(reverse('view_name'))
# File download
response = HttpResponse(file_content, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="file.pdf"'
return response
Error Handling
Custom Error Views
# views.py
def handler404(request, exception):
return render(request, '404.html', status=404)
def handler500(request):
return render(request, '500.html', status=500)
# urls.py
handler404 = 'myapp.views.handler404'
handler500 = 'myapp.views.handler500'
Error Templates
<!-- 404.html -->
{% extends 'base.html' %} {% block title %}Page Not Found{% endblock %} {% block
content %}
<h1>Page Not Found</h1>
<p>The page you're looking for doesn't exist.</p>
<a href="{% url 'home' %}">Go Home</a>
{% endblock %}