A Django, mint az egyik legnépszerűbb Python alapú webfejlesztési keretrendszer, hihetetlenül hatékony és rugalmas. Sablonrendszere lehetővé teszi, hogy elegáns és újrahasznosítható módon válasszuk szét a logikát a megjelenítéstől. Azonban előfordulhat, hogy a beépített sablon tagek és filterek nem elegendőek ahhoz a specifikus feladathoz, amit meg szeretnénk oldani. Ekkor jönnek képbe az egyedi template tagek és filterek, amelyekkel szinte határtalanul testreszabhatjuk a sablonjaink viselkedését.
Ez a cikk részletesen bemutatja, hogyan hozhatunk létre saját sablon tageket és filtereket Djangóban. Megvizsgáljuk a különböző típusokat, konkrét kódpéldákon keresztül illusztrálva a működésüket, és tippeket adunk a legjobb gyakorlatokhoz.
Miért van szükség egyedi template tagekre és filterekre?
Képzeljük el, hogy egy webalkalmazáson dolgozunk, ahol gyakran van szükségünk speciális dátumformázásra, szövegfeldolgozásra, vagy éppen komplexebb logikát igénylő tartalom megjelenítésére. Ahelyett, hogy minden egyes helyen megismételnénk ugyanazt a Python kódot a nézetekben (views), vagy bonyolult if/else
szerkezeteket használnánk a sablonban, létrehozhatunk egyetlen, elegáns sablon filtert vagy taget, ami elvégzi a munkát. Ezáltal a kódunk sokkal tisztább, olvashatóbb és könnyebben karbantartható lesz.
- Újrafelhasználhatóság: Írj meg egyszer, használd bárhol a sablonjaidban.
- Tisztább sablonok: Csökkenti a sablonokban lévő redundáns vagy komplex logikát.
- Prezentáció és logika szétválasztása: Hozzájárul a MVC (Model-View-Controller) vagy MTV (Model-Template-View) paradigma betartásához.
- Saját specifikus funkciók: Megoldhatunk olyan egyedi problémákat, amire a beépített elemek nem nyújtanak megoldást.
A Django Sablonrendszer Alapjai és a templatetags Könyvtár
Mielőtt belevágnánk az egyedi elemek írásába, érdemes megérteni, hogyan működik a Django sablonrendszere. A sablonok két fő típust tartalmaznak:
- Változók:
{{ variable }}
– adatokat jelenítenek meg. - Tagek:
{% tag %}
– valamilyen logikát hajtanak végre, például ciklusokat, feltételeket, vagy más adatokat töltenek be.
Ahhoz, hogy a Django megtalálja az egyedi sablon tagjeinket és filtereinket, egy speciális mappaszerkezetet kell követnünk:
- Az alkalmazásunk gyökérkönyvtárában (ahol a
models.py
,views.py
stb. fájlok vannak) hozzunk létre egytemplatetags
nevű könyvtárat. Fontos, hogy ez a név pontosan így íródjon! - Ebbe a
templatetags
könyvtárba tegyünk egy üres__init__.py
fájlt, hogy a Python modulnak ismerje fel. - Hozzuk létre a Python fájlunkat (pl.
my_custom_tags.py
), ebben fogjuk definiálni az egyedi tagjeinket és filtereinket.
Példa mappaszerkezet:
my_app/ __init__.py models.py views.py templatetags/ __init__.py my_custom_tags.py templates/ my_app/ my_template.html
Miután létrehoztuk a fájlt, az egyedi tagjeinket és filtereinket a sablonunkban a {% load %}
taggel tudjuk betölteni. Például:
{% load my_custom_tags %}
<!-- Itt használhatjuk az egyedi tagjeinket és filtereinket -->
Egyedi Filterek Írása
A custom filterek (egyedi filterek) olyan funkciók, amelyek egy változó értékét alakítják át. Például egy dátumot formáznak, egy szöveget módosítanak, vagy egy számot kerekítenek. A filterek Python függvények, amelyek legalább egy argumentumot kapnak (azt az értéket, amit átalakítanak), és egy értéket adnak vissza.
A filterek regisztrálásához a django.template
modulból importálnunk kell a Library
osztályt, és annak egy példányát létrehoznunk.
my_custom_tags.py
:
from django import template
register = template.Library()
@register.filter
def my_upper(value):
"""
Minden karaktert nagybetűre alakít.
Használat: {{ "hello world"|my_upper }}
Eredmény: HELLO WORLD
"""
return str(value).upper()
@register.filter
def cut_text(value, arg):
"""
Egy szöveget levág egy adott hossz után, és ...-t fűz hozzá.
Használat: {{ "Ez egy hosszú szöveg"|cut_text:10 }}
Eredmény: Ez egy hos...
"""
if len(value) > arg:
return value[:arg] + '...'
return value
A @register.filter
dekorátor automatikusan regisztrálja a függvényünket filterként. A filterek neve megegyezik a függvény nevével. Ha más nevet szeretnénk használni, azt is megadhatjuk a dekorátorban: @register.filter(name='felso_eset')
.
Használat a sablonban:
{% load my_custom_tags %}
<p>Nagybetűs szöveg: {{ "szia vilag"|my_upper }}</p>
<p>Rövidített szöveg: {{ "Ez egy nagyon hosszú szöveg, amit le kellene vágni."|cut_text:20 }}</p>
Eredmény:
<p>Nagybetűs szöveg: SZIA VILAG</p> <p>Rövidített szöveg: Ez egy nagyon hosszú...</p>
Egyedi Sablon Tagek Írása
A custom template tagok (egyedi sablon tagek) sokkal sokoldalúbbak, mint a filterek. Képesek komplexebb logikát végrehajtani, további sablonokat renderelni, vagy akár blokkokat feldolgozni. Három fő típusa van:
1. Egyszerű Tagek (Simple Tags)
Az egyszerű tagek a leggyakrabban használt és legkönnyebben írható tag típusok. Olyan Python függvények, amelyek közvetlenül egy stringet adnak vissza a sablonba. Nincs szükség bonyolult parserekre vagy Node osztályokra. Ideálisak olyan esetekre, amikor csak egy értéket kell megjeleníteni, ami valamilyen számítás eredménye, vagy egy adatbázisból származó információ.
my_custom_tags.py
:
from django import template
from datetime import datetime
register = template.Library()
@register.simple_tag
def current_time(format_string="%Y-%m-%d %H:%M:%S"):
"""
Visszaadja az aktuális dátumot és időt a megadott formátumban.
Használat: {% current_time %} vagy {% current_time "%H:%M" %}
"""
return datetime.now().strftime(format_string)
@register.simple_tag
def get_user_full_name(user):
"""
Visszaadja a felhasználó teljes nevét.
Használat: {% get_user_full_name request.user %}
"""
return f"{user.first_name} {user.last_name}" if user.first_name and user.last_name else user.username
Használat a sablonban:
{% load my_custom_tags %}
<p>Az aktuális idő: {% current_time %}</p>
<p>Rövid időformátum: {% current_time "%H:%M" %}</p>
{% if request.user.is_authenticated %}
<p>Üdvözlöm, {% get_user_full_name request.user %}!</p>
{% endif %}
Az egyszerű tageket használhatjuk úgy is, hogy a kimenetüket egy változóba mentjük az as
kulcsszóval:
{% load my_custom_tags %}
{% current_time "%A, %d %B %Y" as today_date %}
<p>Ma van: {{ today_date }}</p>
2. Inclusion Tagek (Inclusion Tags)
Az inclusion tagek ideálisak arra, ha egy kis, önálló sablonrészletet (snippet) szeretnénk renderelni, és ahhoz valamilyen kontextust (adatot) átadni. Gondoljunk rájuk úgy, mint egy miniatűr nézetre a sablonunkon belül. Különösen hasznosak ismétlődő komponensek (pl. menüpontok, bejegyzéskártyák) megjelenítésére.
Létre kell hoznunk egy külön sablonfájlt a templates
könyvtárunkban, pl. my_app/latest_articles.html
.
my_app/templates/my_app/latest_articles.html
:
<div class="latest-articles">
<h4>Legújabb cikkek:</h4>
<ul>
{% for article in articles %}
<li><a href="{{ article.get_absolute_url }}">{{ article.title }}</a></li>
{% empty %}
<li>Nincsenek elérhető cikkek.</li>
{% endfor %}
</ul>
</div>
Most definiáljuk az inclusion taget a my_custom_tags.py
fájlban:
from django import template
from my_app.models import Article # Feltételezve, hogy van egy Article modellünk
register = template.Library()
@register.inclusion_tag('my_app/latest_articles.html', takes_context=False)
def show_latest_articles(count=5):
"""
Megjeleníti a legújabb cikkeket.
Használat: {% show_latest_articles 3 %}
"""
articles = Article.objects.order_by('-published_date')[:count]
return {'articles': articles} # Ezt a dictionary-t adja át a sablonnak kontextusként
A takes_context=False
azt jelenti, hogy a tag nem kapja meg automatikusan a szülő sablon kontextusát. Ha szeretnénk, hogy hozzáférjen, állítsuk True
-ra. Ekkor a tag függvény első argumentuma a kontextus objektum lesz.
Használat a sablonban:
{% load my_custom_tags %}
<h2>Fő tartalom</h2>
<!-- A legújabb 3 cikket jeleníti meg -->
{% show_latest_articles 3 %}
<!-- A legújabb 5 cikket jeleníti meg (alapértelmezett) -->
{% show_latest_articles %}
3. Komplex Sablon Tagek (Block Tags)
Ez a típus a legösszetettebb, de egyben a legerősebb is. Akkor van rájuk szükség, ha a tagnek feldolgoznia kell a nyitó és záró tagjei közötti tartalmat (blokkot), vagy ha bonyolultabb logikára, a parserrel való közvetlen interakcióra van szükség. Például, ha egy egyedi feltételes blokkot, egy speciális formázó blokkot vagy egy változó-beállító taget szeretnénk létrehozni.
A komplex tagek írásakor két fő komponensre van szükségünk:
- Egy parse függvényre, amely felelős a tag argumentumainak értelmezéséért és egy
Node
objektum létrehozásáért. - Egy Node osztályra, amely tárolja a tag állapotát és végrehajtja a logikáját a
render()
metódusában.
Vegyünk egy példát: egy {% set %}
taget, ami lehetővé teszi, hogy egy változó értékét beállítsuk a sablonon belül (a Django {% with %}
tagje hasonló, de ez illusztrálja a mechanizmust).
my_custom_tags.py
:
from django import template
from django.template.base import Node, Token, Parser
from django.template import VariableDoesNotExist # Fontos importálni a kivételeket
register = template.Library()
class SetVarNode(Node):
"""
Egy változó értékét állítja be a sablon kontextusában.
"""
def __init__(self, var_name, var_value):
self.var_name = var_name
self.var_value = var_value # Ez egy Variable objektum lesz
def render(self, context):
try:
# Kiértékeljük a változó értékét a jelenlegi kontextusban
value = self.var_value.resolve(context)
except VariableDoesNotExist:
value = '' # Vagy kezeljük hibaként, attól függően, mit szeretnénk
# Beállítjuk a változót a kontextusban
context[self.var_name] = value
return '' # A "set" tag nem generál közvetlenül kimenetet
# A parse függvény, ami feldolgozza a taget a sablonban
@register.tag(name="set")
def do_set_var(parser: Parser, token: Token):
"""
Beállít egy változót a sablonon belül.
Használat: {% set var_name = "érték" %}
{% set másik_var = object.property %}
"""
try:
# A token.split_contents() felosztja a tag tartalmát szóközök mentén.
# Pl. ['set', 'my_var', '=', '"hello"']
tag_name, var_name, eq, var_value = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError(
f"'{token.contents.split()[0]}' tag requires the format "
f"'{token.contents.split()[0]} var_name = value'"
)
if eq != '=':
raise template.TemplateSyntaxError(
f"'{tag_name}' tag arguments must include an '=' sign."
)
# A parser.compile_filter() egy Variable objektumot ad vissza,
# ami ki tudja értékelni az értéket a rendereléskor.
return SetVarNode(var_name, parser.compile_filter(var_value))
A fenti kódmagyarázatok:
- A
SetVarNode
osztály tárolja a változó nevét (amit beállítunk) és az értékét (amit beállítunk). Fontos, hogy az érték egyVariable
objektumként van tárolva, nem közvetlenül az érték. - A
render()
metódus a tényleges végrehajtás helye. Itt hívjuk meg aself.var_value.resolve(context)
metódust, ami kiértékeli a változó értékét a jelenlegi sablon kontextusában (pl. haobject.property
volt megadva, akkor feloldja azt azobject
-ből). Ezután az eredményt hozzárendeli acontext
-hez a megadott változónévvel. - A
do_set_var
függvény a parser függvény. Ezt hívja meg a Django, amikor találkozik a{% set ... %}
taggel. Feladata a tag argumentumainak feldolgozása, szintaktikai hibák ellenőrzése, és végül egySetVarNode
példány visszaadása. - A
parser.compile_filter(var_value)
egy nagyon fontos lépés, ez alakítja át a stringet (pl."hello"
vagyobject.property
) egy olyan objektté, ami a renderelés során feloldható. - A
@register.tag(name="set")
regisztrálja ado_set_var
függvényt aset
nevű taghez.
Használat a sablonban:
{% load my_custom_tags %}
{% set my_variable = "Ez egy test érték." %}
<p>Beállított változó: {{ my_variable }}</p>
{% set username = request.user.username|default:"Vendég" %}
<p>Felhasználónév: {{ username }}</p>
Gyakori Hibák és Tippek a Fejlesztéshez
- Elnevezési konvenciók: Használjunk egyértelmű és konzisztens neveket. A filterek általában kisbetűsek, alulvonással elválasztva (pl.
my_filter
), a tagek szintén (pl.my_tag
). - Dokumentáció (Docstrings): Mindig írjunk docstringeket a tagjeinkhez és filtereinkhez. Ezek nemcsak a kód olvashatóságát javítják, hanem a Django
{% comment %}
tagjével is megjeleníthetőek. - Hibaellenőrzés: A komplex tagek írásakor kiemelten fontos a bemenet ellenőrzése és a megfelelő
TemplateSyntaxError
kivételek dobása, hogy a fejlesztő azonnal értesüljön a hibákról. - Tesztelés: Ahogy minden kódot, az egyedi tageket és filtereket is érdemes tesztelni. A Django biztosít eszközöket a sablonok tesztelésére, ami segít a hibák felderítésében.
- Ne tegyünk túl sok logikát a sablonba: Az egyedi tagek és filterek célja a megjelenítéssel kapcsolatos logika kezelése. Ne vigyünk át ide komplex üzleti logikát, annak továbbra is a nézetekben vagy a modellekben a helye.
- Performance: Különösen komplex tageknél figyeljünk a teljesítményre. Ha egy tag adatbázis-lekérdezéseket végez, győződjünk meg róla, hogy hatékonyan teszi azt, elkerülve az N+1 lekérdezési problémát.
- Biztonság (Escaping): Ha a tagünk olyan tartalmat generál, ami felhasználói bemeneten alapul, győződjünk meg róla, hogy megfelelően escapeljük azt a biztonsági rések (pl. XSS) elkerülése érdekében. A Django sablonrendszer alapvetően automatikusan escapel, de ha nyers HTML-t adunk vissza, ezt tudatosan kell kezelni.
Összefoglalás
Az egyedi template tagek és filterek írása Djangóban egy rendkívül hasznos készség, amely lehetővé teszi, hogy a webalkalmazásaink sablonjai sokkal rugalmasabbak, tisztábbak és hatékonyabbak legyenek. Akár egyszerű adatformázásra van szükségünk egy custom filterrel, akár komplexebb sablonkomponenseket szeretnénk létrehozni inclusion tag segítségével, vagy egyedi blokklogikát megvalósítani egy komplex taggel, a Django mindehhez biztosítja az eszközöket.
Bár a komplex tagek kezdetben ijesztőnek tűnhetnek a Node
osztályokkal és a parserrel való interakcióval, a mögöttes elvek megértése hatalmas szabadságot ad a kezünkbe. Ne feledjük, hogy a cél mindig a kódunk olvashatóságának, karbantarthatóságának és újrafelhasználhatóságának növelése. Kezdjünk kis lépésekkel, kísérletezzünk, és hamarosan profin fogunk saját Django sablonbővítményeket írni!
Reméljük, ez a részletes útmutató segít elindulni az egyedi sablon tagjeid és filtereid megalkotásában. Sok sikert a fejlesztéshez!
Leave a Reply