Skip to main content

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>&copy; 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 %}