Sposób używania tzw. procesorów kontekstu w Django jest niestety niezbyt intuicyjny. Zacznijmy jednak od omówienia czym jest kontekst i procesor kontekstu w Django.
Jak wiadomo, Django oddziela warstwę prezentacji od logiki oprogramowania (oraz od danych).
Przypuśćmy, że mamy listę książek, przechowywaną w obiekcie books
.
Chcemy wyświetlić ich tytuły zapisane w polu books.title
.
Robimy szablon np. mytemplate.html:
Jak widać, w szablonie mamy pętlę, która iteruje po danych z listy oznaczonej books_list. Ta lista musi być jakoś do szablonu przekazana. Przekazanie następuje właśnie poprzez kontekst. Może on być zwykłym słownikiem pythona.
Słownik ten musimy zdefiniować w funkcji widoku. Na przykład:
def show_books(request): from myproject.myapp.models import Book books_list = Book.objects.all() context = {'books_list':books_list} return render_to_response('mytemplate.html', context)
Jaki sens ma ten słownik? Jeśli w szablonie jest jakaś zmienna, to Django szuka w słowniku kontekstu klucza o identycznym brzmieniu i przrekazuje w to miejsce wartość ze słownika odpowiadającą temu kluczowi. W tym przypadku jest to lista książek.
Innymi słowy, jeśli chcemy, żeby coś zostało przekazane do szablonu, musimy to umieścić w słowniku. Oczywiście bywa i tak, że takie przekazywanie byłoby niewygodne. Funkcji widoku w rozbudowanym serwisie www będzie bardzo wiele, a niektóre zmienne powinny być przekazane do każdej z nich. Na przykład jeśli chcemy wyświetlić w okienku z boku na każdej stronie portalu nowości wydawnicze
Newest.objects.all(), to musielibyśmy je wpisywać za każdym razem do słownika kontekstu gdy wywołujemy funkcję render_to_response. Jest to nie tylko niewygodne, ale i sprzeczne z zasadą DRY (don't repeat yourself).
Do tego właśnie służą procesory kontekstu. Taki procesor umieszczamy gdzieś w pliku np: processors.py.
Jest on funkcją:
from myproject.myapp.models import Newest def myproc(request): return {'newest': Newest.objects.all()}
Ten procesor kontekstu sprawi, że nowości będą widoczne w każdym widoku, nawet gdy nie zostaną jawnie przekazane. Ale żeby to zadziałało musimy spełnić jeszcze dwa warunki.
1. Zaglądamy do pliku settings.py. Odnajdujemy tam zmienną TEMPLATE_CONTEXT_PROCESSORS
.
Domyślnie ma ona postać takiej krotki:
TEMPLATE_CONTEXT_PROCESSORS = ( "django.core.context_processors.auth", "django.core.context_processors.debug", "django.core.context_processors.i18n", "django.core.context_processors.media", )
Zmienna ta określa (jak łatwo się domyslić) procesory kontekstu, które mają być uzywane w projekcie. Oczywiście trzeba do tej krotki dodać nasz procesor: "myapp.processors.myproc"
. Widać też, że domyślnie używane są pewne predefiniowane procesory, które postaram się omówić przy innej okazji. Pozostał tam nam jeszcze drugi warunek by procesor kontekstu działał.
2. Jeśli w wywołaniu render_to_response użyjemy jako kontekstu zwykłego słownika, to procesory kontekstu (nawet te wymienione w settings.py) nie będą działać. To jest właśnie ten bardzo nieintuicyjny element, o którym pisałem na początku. Musimy przy wywołaniu render_to_response
użyć obiektu RequestContext. Można to zrobić na kilka sposobów:
a)
return render_to_response('template.html', {'foo':'bar'}, context_instance=RequestContext(request) )
context = RequestContext(request, {'foo':'bar'}) return render_to_response('template.html', context)
return render_to_response('template.html', RequestContext(request, {'foo':'bar'}))
Gwoli ścisłości należy dodać, że w wywołaniu render_to_response można też zmusić do działania procesory kontekstu nie wymienione w settings.py:
return render_to_response('template.html', {'foo':'bar'}, context_instance=RequestContext(request, processors = extra_processors) )