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:
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:
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:
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.
Pobierz źródła
Po rozpakowaniu edytuj ścieżkę w
urls.py a następnie stwórz tabele i superadmina.
- Dodane: 14.07.2008 przez riklaunim