0 Tage Serie
python / expert
Snippet

Django Benutzerdefinierte Template-Filter mit Registrierung

Django Template-Filter transformieren Variablenausgabe in Templates, während benutzerdefinierte Tags komplexe Template-Logik ermöglichen. Dieses Beispiel zeigt mehrere Filtertypen: String-Manipulationsfilter (truncate, highlight), Formatierungsfilter (percentage, phone) und Inclusion-Tags für wiederverwendbare Template-Komponenten. Die Registrierungs-Dekorator-Muster demonstrieren sowohl @register.filter für einfache Transformationen als auch @register.inclusion_tag für Template-Rendering mit Kontextdaten.

snippet.py
python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import re
from django import template
from django.utils.safestring import mark_safe
from django.utils.html import strip_tags
register = template.Library()
@register.filter(name='truncate_words_html')
def truncate_words_html(value, arg):
"""Truncate HTML string to given word count without breaking tags."""
from bs4 import BeautifulSoup
soup = BeautifulSoup(value, 'html.parser')
text = soup.get_text()
words = text.split()
if len(words) <= arg:
return value
truncated_text = ' '.join(words[:arg]) + '...'
return mark_safe(truncated_text)
@register.filter
def highlight_search(text, search_term):
"""Highlight search term in text with HTML markup."""
if not search_term:
return text
pattern = re.compile(re.escape(search_term), re.IGNORECASE)
highlighted = pattern.sub(lambda m: f'<mark>{m.group()}</mark>', text)
return mark_safe(highlighted)
@register.filter
def percentage(value, decimals=0):
"""Format number as percentage string."""
try:
return f'{float(value) * 100:.{decimals}f}%'
except (ValueError, TypeError):
return '0%'
@register.filter
def phone_format(value):
"""Format phone number with country code grouping."""
digits = re.sub(r'\D', '', value)
if len(digits) == 10:
return f'({digits[:3]}) {digits[3:6]}-{digits[6:]}'
elif len(digits) == 11 and digits[0] == '1':
return f'+1 ({digits[1:4]}) {digits[4:7]}-{digits[7:]}'
return value
@register.inclusion_tag('tags/breadcrumb.html')
def render_breadcrumb(items):
"""Render navigation breadcrumb from list of (url, label) tuples."""
return {'items': items}
@register.simple_tag
def get_menu_items(menu_name, user=None):
"""Retrieve and cache menu items from database."""
from django.core.cache import cache
from .models import MenuItem
cache_key = f'menu_{menu_name}'
items = cache.get(cache_key)
if items is None:
queryset = MenuItem.objects.filter(menu_name=menu_name, is_active=True)
if user and not user.is_superuser:
queryset = queryset.filter(requires_auth=False)
items = list(queryset.select_related('parent').order_by('sort_order'))
cache.set(cache_key, items, 3600)
return items
django
Erklärung
1
register = template.Library()
Erstelle Template-Bibliothek Instanz zum Registrieren von Filtern/Tags
2
@register.filter(name='truncate_words_html')
Registriere Filter mit benutzerdefiniertem Namen für Template-Nutzung
3
def truncate_words_html(value, arg):
Filter-Funktion erhält Wert und optionales Argument
4
return mark_safe(truncated_text)
Markiere HTML als sicher um Auto-Escaping zu verhindern
5
@register.filter def highlight_search(text, search_term):
Hebe Suchtreffer mit Regex-Substitution hervor
6
pattern = re.compile(re.escape(search_term), re.IGNORECASE)
Baue sicheres Regex-Muster ohne Special-Char-Injection
7
@register.inclusion_tag('tags/breadcrumb.html')
Registriere Template-Tag das eingeschlossenes Template rendert
8
@register.simple_tag def get_menu_items(menu_name, user=None):
Simple Tag für komplexe Datenabfrage mit Caching