Komentarze w Django - wspólny szablon

Używając Django, mamy dostęp do użytecznej aplikacji komentarzy - django.contrib.comments. Pozwala ona powiązać system komentowania z różnymi modelami, w efekcie tę samą aplikację wykorzystamy umożliwiając komentowanie artykułów na blogu, zdjęć w galerii itp. Kilka znaczników pozwala w łatwy sposób osadzić widok komentarzy w szablonie. Często jednak w kilku aplikacjach sekcja komentarzy wygląda tak samo - mamy listę ostatnio dodanych wpisów i formularz pozwalający na dodanie nowej wypowiedzi. Co zrobić, żeby uniknąć kopiowania i wklejania kodu szablonu?

"Problem" wygląda następująco: załóżmy, że mamy 2 aplikacje - blog i galerię zdjęć (wygląda znajomo? ;-) ) W każdej z nich chcemy pozwolić użytkownikom na komentowanie obiektów (artykułów/zdjęć). Nic prostszego, dołączamy django.contrib.comments do zainstalowanych aplikacji, po czym w szablonie widoku artykułu wstawiamy np. taki fragment:

{% get_comment_list for article as comment_list %}
<ol>
  {% for comment in comment_list %}
  <li>
    <h4>{{ comment.user_name }} ({{ comment.submit_date }})</h4>
    <p>{{ comment.comment }}</p>
  </li>
  {% endfor %}
</ol>
<h3>Dodaj komentarz</h3>
{% render_comment_form for article %}

I świetnie, wszystko działa, teraz żeby umożliwić komentowanie zdjęć, do szablonu galerii dodajemy podobny kod, z tą różnicą że zamiast article pojawi się zapewne photo czy jak tam sobie nazwiemy zmienną kontekstu. Jednak jeśli w obu wypadkach komentarze mają wyglądać na stronie tak samo, to miło by było uniknąć duplikacji kodu różniącego się tylko tym drobnym szczegółem. W takim razie radośnie wydzielamy powyższy kod do osobnego szablonu i... No właśnie - w jednym szablonie kluczowym obiektem jest article, w drugim photo, a szablon komentarzy chcemy mieć tylko jeden - na co się zdecydować?

Można przyjąć konwencję, że zmienną kontekstu nazwiemy obj i przekażemy taką nazwę z widoku, np.

def read_article(request, id):
    # coś w stylu: article = get_object_or_404(...)
    return render_to_response('blog/article.html', {'obj': article})

W widoku prezentującym zdjęcie zrobimy podobnie, a w komentarzach będziemy się odwoływać do obiektu przez {% get_comment_list for obj as comment_list %}. Będzie to działać, ale ładniej by było, gdyby zmienna była dostępna w szablonie pod nazwą mówiącą coś więcej. Na ratunek przychodzi nam znacznik {% with %}. Do szablonu przekazujemy dane pod jakąś sensowną nazwą, a w miejscu, gdzie chcemy dołączyć komentarze, wykorzystamy ten znacznik w celu utworzenia aliasu do zmiennej.

{% with article as obj %}{% include "comments_section.html" %}{% endwith %}

A w galerii:

{% with photo as obj %}{% include "comments_section.html" %}{% endwith %}

Gotowe, wykonaliśmy ostatni krok w kierunku maksymalnego uogólnienia systemu komentarzy. Oczywiście ma to sens tylko w przypadku, gdy chcemy mieć identycznie wyglądające sekcje komentarzy w różnych miejscach witryny.