Tvoříme blog v Djangu – krok za krokem
V tomto článku začneme s tvorbou naší první aplikace – jednoduchého blogu. Série článků bude zaměřená primárně na backendovou logiku, takže co se týče vzhledu, použijeme pouze Bootstrap. Nebudeme tedy používat žádný frontendový framework jako React, Vue.js nebo Angular – těm se budeme věnovat až později, až budeme řešit pokročilejší integraci s Djangem.
Co nás čeká?
Celý proces tvorby blogu rozdělíme do tří hlavních částí:
- Část 1: Základní CRUD funkce – vytvoření, úprava a mazání článků.
- Část 2: Kategorie a vyhledávání – filtrování podle kategorií a fulltextové hledání.
- Část 3: Komentáře – diskuse pod články včetně odpovědí.
Po dokončení těchto kroků přidáme správu uživatelů – registraci, přihlášení a oprávnění k článkům.
Začínáme s aplikací
Založení aplikace:
python manage.py startapp blog
Nezapomeňte přidat aplikaci do INSTALLED_APPS
v settings.py
.
Model příspěvku
V souboru models.py vytvoříme model, který bude reprezentovat jeden blogový příspěvek:
from django.db import models
from django_extensions.db.fields import AutoSlugField
class Post(models.Model):
title = models.CharField(max_length=200)
body = models.TextField()
slug = AutoSlugField(populate_from="title")
created = models.DateField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
ordering = ['-created']
Vysvětlení polí
- CharField – krátký text (např. název článku). V tomto poly je povinný paramter max_length, který definuje maximální počet znaků.
- TextField – Vícero řádkový text bez omezení délky.
- AutoSlugField – Automatické generování URL-friendly názvu. Pro jeho použití je nutné nainstalovat knihovnu django-extensions
pip install django-extensions
. - DateField – Datum vytvoření. Díky parametru auto_now_add=True se vyplní automaticky při vytvoření.
- __str__() – Vrací název článku při jeho reprezentaci (např. v adminu nebo konzoli).
- Meta.ordering – Nastaví výchozí řazení podle data vytvoření, od nejnovějšího k nejstaršímu (prefix - značí sestupné řazení).
Formulář pro článek
Pro jednodušší práci s články přes webové rozhraní si ve složce blog
vytvoříme soubor forms.py
:
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'body']
labels = {
'title': 'Název článku',
'body': 'Obsah článku',
}
- Importujeme potřebné třídy a náš model Post.
- Vytváříme formulář jako
ModelForm
, čímž Django automaticky vygeneruje vstupní pole podle modelu. - V
Meta
třídě určíme, že budeme pracovat s modelemPost
a že chceme zobrazit pouze poletitle
abody
. - Pomocí
labels
upravíme popisky polí ve formuláři.
Views – logika blogu (CRUD)
Po definování modelů a formulářů je čas přejít k "mozku" celé aplikace – views. Právě zde bude probíhat hlavní logika naší blogové aplikace: zobrazování příspěvků, jejich vytváření, úprava i mazání. Jinými slovy: CRUD operace (Create, Read, Update, Delete).
Podíváme se společně na jednotlivé funkce v souboru views.py
a vysvětlíme si, co přesně dělají.
Importy
from django.shortcuts import render, get_object_or_404, redirect
from .models import Post
from .forms import PostForm
render
slouží k vykreslení HTML šablon s daty.get_object_or_404
zjednodušuje získání objektu z databáze – pokud nenajde, vrátí automaticky 404.redirect
přesměruje uživatele na jinou stránku.- Dále importujeme náš model
Post
a formulářPostForm
.
Jednotlivé funkce
1. Zobrazení seznamu:
def home_view(request):
posts = Post.objects.all()
return render(request, "blog/home.html", {"posts": posts})
Získáme všechny příspěvky (Post.objects.all()
) a předáme je do šablony home.html
, kde se zobrazí seznam článků. Tento view funguje jako hlavní stránka blogu.
2. Detail příspěvku:
def post_detail_view(request, slug):
post = get_object_or_404(Post, slug=slug)
return render(request, "blog/post_detail.html", {"post": post})
Zde načítáme konkrétní příspěvek podle jeho slugu. Pokud neexistuje, vrátí se 404. Výsledek se předá do šablony post_detail.html
.
3. Vytvoření příspěvku:
def post_create_view(request):
if request.method == "POST":
form = PostForm(request.POST)
if form.is_valid():
form.save()
return redirect(home_view)
else:
form = PostForm()
return render(request, "blog/post_form.html", {"form": form})
- Pokud je metoda požadavku
POST
, vytvoříme formulář s daty odeslanými uživatelem. - Pokud je formulář validní, uložíme nový příspěvek a přesměrujeme uživatele na domovskou stránku.
- Pokud jsme na stránku přišli přes
GET
, zobrazíme prázdný formulář. - Používáme šablonu
post_form.html
, kterou lze využít i pro úpravy.
4. Úprava příspěvku:
def post_update_view(request, slug):
post = get_object_or_404(Post, slug=slug)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
form.save()
return redirect("post_detail", slug=post.slug)
else:
form = PostForm(instance=post)
return render(request, "blog/post_form.html", {"form": form})
- Načteme příspěvek podle slugu.
- Pokud přichází
POST
požadavek, vytvoříme formulář s existujícím objektem a novými daty. - Pokud je vše validní, příspěvek se aktualizuje a přesměrujeme uživatele na detail článku.
- Pokud neproběhl
POST
, jen zobrazíme formulář s předvyplněnými daty.
5. Smazání příspěvku:
def post_delete_view(request, slug):
post = get_object_or_404(Post, slug=slug)
if request.method == "POST":
post.delete()
return redirect("post_list")
return render(request, "blog/post_confirm_delete.html", {"post": post})
- Načteme příspěvek podle slugu.
- Pokud uživatel potvrdí smazání pomocí
POST
požadavku, příspěvek se smaže a přesměrujeme ho na seznam příspěvků. - Jinak zobrazíme potvrzovací stránku
post_confirm_delete.html
Tento soubor views.py obsahuje kompletní logiku pro správu příspěvků v našem blogu. Každý view
je přehledně oddělen a plní jasně danou roli:
home_view
– přehled příspěvkůpost_detail_view
– zobrazení detailu jednoho příspěvku,post_create_view
– přidání nového článku,post_update_view
– úprava existujícího článku,post_delete_view
– smazání článku.
Kde se definují URL adresy?
Ve výchozím Django projektu najdeme soubor urls.py
ve složce s názvem hlavní aplikace (často core, config, nebo dle vlastního pojmenování). Právě zde budeme definovat všechny cesty, které povedou na příslušné view funkce.
Routing – URL adresy
from django.contrib import admin
from django.urls import path
from blog.views import (home_view, post_detail_view, post_create_view, post_update_view, post_delete_view)
urlpatterns = [
path("admin/", admin.site.urls),
path("", home_view, name="home"),
path("post/new", post_create_view, name="post_create"),
path("post/<str:slug>", post_detail_view, name="post_detail"),
path("post/<str:slug>/edit", post_update_view, name="post_update"),
path("post/<str:slug>/delete", post_delete_view, name="post_delete"),
]
Co se tady děje?
1. Importy
from blog.views import ...
Importujeme všechny potřebné funkce ze souboru views.py
, které jsme vytvořili dříve.
2. urlpatterns
Toto je seznam všech cest, které bude naše aplikace obsluhovat.
path('', home_view, name='home')
- Kořenová URL adresa (např.
http://localhost:8000/
) - Zobrazí výpis všech příspěvků pomocí
home_view
.
path('post/new', post_create_view, name='post_create')
- Cesta pro vytvoření nového příspěvku.
- Šablona
post_form.html
bude zobrazena s prázdným formulářem.
path('post/', post_detail_view, name='post_detail')
- Dynamická URL –
<str:slug>
je proměnná, která se dosadí ze slugu článku. - Např.
post/muj-prvni-clanek
načte detail článku s tímto slugem.
path('post//edit', post_update_view, name='post_update')
- Slouží k editaci existujícího článku.
- Na základě slugu načte článek, předvyplní formulář
post_form.html
a po odeslání provede update.
path('post//delete', post_delete_view, name='post_delete')
- Zobrazí potvrzovací stránku pro smazání článku.
- Při potvrzení příspěvek smaže.
S tímto nastavením máme plně funkční routování pro náš blog. Všechny view funkce jsou propojeny s odpovídajícími URL adresami a připraveny přijímat požadavky od uživatelů.
Michal Šanda
13. května 2025