Widok jest odpowiedzialny za przygotowanie danych dla danego szablonu i zwróceniu wygenerowanej żądanej strony. Co jednak gdy potrzebujemy wygenerować dynamiczną zawartość już na etapie głównego szablonu, na którym bazują pozostałe strony? W niniejszym wpisie pokażę użycie własnego template context processor na przykładzie dynamicznego wygenerowania menu nawigacyjnego w szablonie głównym.

Model

Załóżmy że posiadamy w bazie danych listę produktów oraz kategorie. W szablonie głównym mamy zdefiniowane menu nawigacyjne ze statycznymi linkami do poszczególnych podstron naszej witryny. Jednakże, chcemy uzupełnić menu o dynamiczne linki do kategorii produktów. Każda podstrona naszego serwisu będzie bazować na szablonie głównym, więc nie będzie trzeba się martwić o ten aspekt na poszczególnych stronach.

Przykładowy model kategorii w aplikacji products wygląda następująco:

class Category(models.Model):
name = models.CharField(max_length=50)
description = models.TextField()
slug = models.SlugField(max_length=50, db_index = True)

Pole name posłuży do prezentacji nazwy kategorii a description np. jako opis kategorii. Natomiast pole slug będzie polem do zbudowania linka do tej kategorii. Można go łatwo wygenerować za pomocą funkcji slugify z modułu django.template.defaultfilters.

Oraz model produktu:

class Product(models.Model):
name = models.CharField(max_length=70)
category = models.ForeignKey(Category)
slug = models.SlugField(max_length=70, db_index = True)

Analogicznie jak w klasie Category, zdefiniujemy pole slug służące do wygenerowania linka produktu.

Widok

W module views.py aplikacji products, zdefiniujemy widoki służące do wyświetlenia kategorii z listą produktów oraz strony produktu. Parametry slug będą przekazane przez URL dispatcher.

def products_list(request, cat_slug):
cat = get_object_or_404(Category, slug__iexact = cat_slug)
prod_list = cat.product_set.order_by('name')
return render(request, 'products.html', {'products' : prod_list, 'cat': cat})

def product(request, product_slug):
prod = get_object_or_404(Product, slug__iexact = product_slug)
return render('product.html', {'product': prod })

Przy użyciu ieaxact można wyszukać dany obiekt na podstawie pola tekstowego, ingorując wielkość znaków.

Template context processor

Następnym krokiem jest utworzenie własnego template context processor, w którym zdefiniujemy, że do każdego szablonu będą przekazywane instancje klasy Category. W szablonie głównym utworzymy linki do kategorii produktów, na podstawie pola slug. Definicja pliku categories_context.py wygląda następująco (lokalizacja pliku dowolna):

from products.models import Category

def cats(context):
return {'cats': Category.objects.all()}

W każdym szablonie pod zmienną cats będą dostępne instancje klasy Category. W tym przykładzie zwracane są wszystkie kategorie. Można oczywiście je posortować wg nazwy lub ilości produktów, które w tej kategorii się znajdują.

Następnie należy zarejestrować utworzony template context processor. W pliku konfiguracyjnym Django settings.py należy podać pełną ścieżkę do funkcji:

TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'<APP_NAME>.context_processors.cats',)

Ważne aby nie nadpisywać bieżących ustawień, lecz dodać na koniec listy nasz własny template context processor.

Menu nawigacyjne

Teraz w głównym szablonie np. template_master.html mozna wykorzystać listę obiektów cats aby wygenerować menu nawigacyjne z linkami do poszczególnych kategorii. Przykładowe menu nawigacyjne może wyglądać następujaco:

<header>
	<nav>
	<ul>
		<li><a href="/main/">Main page</a></li>
		<li>
			<a href="/products/">Products</a>
			<ul> {% for cat in cats %}
				<li><a href="/products/{{ cat.slug }}">{{ cat.name }}</a></li> {% endfor %}
			</ul>
		</li>
		<li><a href="/contact/">Contact</a></li>
	</ul>
	</nav>
</header>

URL dispatcher

Ostatnim krokiem jest uzupełnienie reguł o trasowanie linków do kategorii oraz produktów w module urls.py. Akceptowane będą jedynie znaki alfanumeryczne oraz „-” dla nazw kategorii i produktów.

urlpatterns += patterns('',
url(r'^products/([w-]+)?/$', 'products.views.products_list', name='products'),
url(r'^products/[w-]+/([w-]+)/$', 'products.views.product', name='product'))

Podsumowanie

Utworzenie własnego Template context processor’a jest łatwym sposobem na przekazanie zmiennych globalnie do wszystkich szablonów. Bez wykorzystania tego mechanizmu, w każdym widoku należałoby przekazać listę kategorii jako parametr szablonu i na jej podstawie generować menu nawigacyjne. W powyższym przykładzie, zrobione to zostało raz w głównym szablonie witryny.


Podobne artykuły

Komentarze

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *