Blog w Django II - Komentarze

Zajmiemy się teraz rozbudową "bloga" zarysowanego we wprowadzającym do django artykule. Obecnie nasza aplikacja listuje wiadomości na stronie głównej wraz z ich stronicowaniem. Teraz dorobimy widok dla danej wiadomości pozwalający na czytanie i dodawanie komentarzy. Źródła do pobrania na końcu artykułu.

Zaczniemy od stworzenia modelu komentarzy (możemy użyć systemu komentarzy z Django, ale dla celów edukacyjnych stworzymy własny system). Do /blog/news/models.py dodaj:
class NewsComments(models.Model):
	news = models.ForeignKey(News)
	text = models.TextField(verbose_name='Treść')
	author = models.CharField(max_length=255, verbose_name='Autor', blank=True)
Stworzyliśmy model komentarzy "NewsComments" powiązany zależnością Many-To-One z modelem wiadomości:
news = models.ForeignKey(News)
Oprócz tego pole na tekst i autora komentarza. Tworzymy tabelę w bazie danych wydając polecenie:
python manage.py syncdb

Teraz zajmijmy się widokiem dane newsa. Każdy news ma pole ID o unikalnej wartości, tak więc załóżmy że wykorzystamy url w postaci /news/ID/ do wyświetlenie wiadomości o podanym ID. W urls.py dodajemy regułę:
(r'^news/(?P<id>[0-9]+)/$', 'news.views.show_news'),
Zmienną liczbową nazwaliśmy "id". URL przypisano został do widoku "show_news" z aplikacji "news". Plik /blog/news/views.py powinien wyglądać teraz tak:
from django.shortcuts import render_to_response
from blog.news.models import *

def show_news(request, id):
	news = News.objects.get(id=id)
	return render_to_response('show.html', {'news':news})
Stworzyliśmy prosty widok wykorzystujący render_to_response. Zmienna "news" przekazywana do szablonu zawiera dane określonego przez "id" newsa. A wykorzystywany szablon /templates/show.html wygląda tak:
{% extends "index.html" %}
{% block content %}
<h3>{{ news.title }}</h3>
<p>{{ news.text }}... {{ news.date|date:"d.m.Y" }}</p>
{% endblock %}
Teraz możemy dodać link na liście wiadomości (/templates/list.html) do szczegółowego widoku dla każdej wiadomości. We wspomnianym szablonie za "{{ new.date|date:"d.m.Y" }}" dodajemy:
 | <b><a href="/news/{{ new.id }}/">Komentarze</a></b>: XYZ
Na razie jeszcze bez licznika komentarzy dla danego newsa. W efekcie powinniśmy otrzymać coś takiego:
djxblog1

Kolejny etap to formularz dodawania komentarzy na szczegółowym widoku wiadomości. Wykorzystamy standardowy manipulator dodawania wpisu. Edytujemy widok w /blog/news/views.py do postaci:
# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from blog.news.models import *
from django import oldforms as forms
from django.http import HttpResponseRedirect

def show_news(request, id):
	news = News.objects.get(id=id)
	# tworzymy manipulator
	manipulator = NewsComments.AddManipulator()
	if request.POST:
		# formularz wysłany
		data = request.POST.copy()
		# dodajemy brakujące dane
		data['author'] = str(request.user)
		data['news'] = id
		errors = manipulator.get_validation_errors(data)
		# jeżeli nie ma błędów zapisz dane i odświerz stronę - przekieruj na ten sam url
		if not errors:
			new = manipulator.save(data)
			return HttpResponseRedirect('/news/'+ str(id) +'/')
	else:
		# formularz nie wysłany
		errors = {}
		data = {}
	# formularz
	form = forms.FormWrapper(manipulator, data, errors)
	return render_to_response('show.html', {'news':news, 'form':form})
Zastosowaliśmy standardowy Manipulator dodawania wpisu (AddManipulator()) z tym że formularz (show.html):
{% extends "index.html" %}
{% block content %}
<h3>{{ news.title }}</h3>
<p>{{ news.text }}... {{ news.date|date:"d.m.Y" }}</p>

<br /><br />
<h3>Dodaj Komentarz</h3>
<form method="post" action=".">
{{ form.text }}{% if form.text.errors %}<br />*** {{ form.text.errors|join:", " }}{% endif %}<br />
<input type="submit" value="Dodaj Komentarz" />
</form>
{% endblock %}
Nie zawiera wszystkich wymaganych pól. Tak więc przed wywołaniem
errors = manipulator.get_validation_errors(data)
Dopisaliśmy brakujące dane do słownika data. W przypadku dodania komentarza strona zostanie odświeżona (przekierowanie na ten sam URL). Efekt:
djxblog2

Teraz dodamy listę komentarzy dla danej wiadomości nad formularzem ich dodawania. W widoku dojdzie jedna linijka i zmieni się wiersz z render_to_response:
comments = NewsComments.objects.filter(news=id)
return render_to_response('show.html', {'news':news, 'form':form, 'comments':comments})
W szablonie natomiast pojawi się pętla:
{% extends "index.html" %}
{% block content %}
<h3>{{ news.title }}</h3>
<p>{{ news.text }}... {{ news.date|date:"d.m.Y" }}</p>
<br />

{% for c in comments %}
<b>{{ c.author }} napisał:</b><br />
{{ c.text }}<br /><br />
{% endfor %}

<br /><br />
<h3>Dodaj Komentarz</h3>
<form method="post" action=".">
{{ form.text }}{% if form.text.errors %}<br />*** {{ form.text.errors|join:", " }}{% endif %}<br />
<input type="submit" value="Dodaj Komentarz" />
</form>
{% endblock %}
Efekt to:
djxblog3

Zanim zajmiemy się ważnymi wykończeniami systemu komentarzy dodamy liczniki komentarzy w list.html. Zamiast "XYZ" wystarczy wstawić {{ new.newscomments_set.count }} i gotowe. Zastosowaliśmy szablonową wersję dostępu do danych z powiązanej tabeli (bez nawiasów po "count"). Teraz wykończmy komentarze. Problem jaki musimy rozwiązać to tagi HTML w komentarza, których obecny kod nie filtruje. By rozwiązać problem wystarczy że zastosujemy jeden z dostępnych filtrów - escape:
{% for c in comments %}
<b>{{ c.author }} napisał:</b><br />
{{ c.text|escape }}<br /><br />
{% endfor %}
Należy zwrócić uwaglę że obecny system komentarzy nie ma zabezpieczeń przed spamem i nawet niezalogowany użytkownik może dodać komentarz. Rozbudową bloga zajmiemy się w dalszych artykułach.

Źródła

Pobierz źródła
Po rozpakowaniu edytuj ścieżkę w urls.py a następnie stwórz tabele i superadmina.
RkBlog

Django, 14 July 2008

Comment article
Comment article RkBlog main page Search RSS Contact