Dynamiczne menu nawigacyjne w Django
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.
Strona Internetowa
Potrzebujesz Å‚adnej strony internetowej? Zobacz demo na: tej stronie
Komentarze