Blog w Django III - Kategorie
14 July 2008
Comments
W tym artykule zajmiemy się rozbudową samego modułu wiadomości. Dodamy kategorie oraz kilka dodatkowych pól. Jeżeli chodzi o kategorie to możemy zrobić prosty system - dana wiadomość w jednej kategorii (Many-To-One) lub skorzystać z relacji Many-To-Many by móc przypisać jedną wiadomość wielu kategoriom. By nie było za łatwo skorzystamy z tej drugiej możliwości. Oto jak wygląda model aplikacji "news" po zmianach:
# -*- coding: utf-8 -*-
from django.db import models
class NewsCategories(models.Model):
name = models.CharField(max_length=255, verbose_name='Nazwa Kategorii')
slug = models.SlugField(max_length=255, unique=True, prepopulate_from=("name", ), verbose_name='Odnośnik')
icon = models.ImageField(upload_to='icons', verbose_name='Ikonka Kategorii')
class Meta:
verbose_name = "Kategoria"
verbose_name_plural = "Kategorie"
class Admin:
list_display = ('name',)
def __str__(self):
return self.name
class News(models.Model):
category = models.ManyToManyField(NewsCategories, verbose_name='Kategorie')
title = models.CharField(max_length=255, verbose_name='Tytuł')
slug = models.SlugField(max_length=255, unique=True, prepopulate_from=("title", ), verbose_name='Odnośnik')
text = models.TextField(verbose_name='Treść')
date = models.DateTimeField(blank=True, verbose_name='Data dodania')
wykop = models.CharField(max_length=255, verbose_name='Wykop', blank=True)
class Meta:
verbose_name = "Wiadomość"
verbose_name_plural = "Wiadomości"
class Admin:
list_display = ('title', 'date')
list_filter = ['date']
search_fields = ['title', 'text']
date_hierarchy = 'date'
def __str__(self):
return self.title
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)
class Meta:
verbose_name = "Komentarze"
verbose_name_plural = "Komentarze"
class Admin:
list_display = ('text', 'author')
def __str__(self):
return self.text
Po utworzeniu tabel i uruchomieniu serwera deweloperskiego, w Panelu Admina powinniśmy zobaczyć coś takiego:



Dodaj kilka wiadomości, kilka z nich przypisz do więcej niż jednej kategorii. Gdy już mamy przykładowe dane możemy zabrać się za aktualizację skryptu. Zaczniemy od odnośnika do szczegółowego widoku wiadomości. Obecnie jest to /news/ID/. W urls.py zmieniamy wyrażenie regularne:
(r'^news/(?P<slug>[\w\-_]+)/$', 'news.views.show_news'),
def show_news(request, slug):
news = News.objects.get(slug=slug)
# 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'] = 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(slug) +'/')
else:
# formularz nie wysłany
errors = {}
data = {}
# formularz
form = forms.FormWrapper(manipulator, data, errors)
comments = NewsComments.objects.filter(news=news.id)
return render_to_response('show.html', {'news':news, 'form':form, 'comments':comments})

<h3>{% for c in news.category.all %}
<a href="/news/cat/{{ c.slug }}/">{{ c }}</a>
{% endfor %}</h3>
def by_category(request, slug):
from django.views.generic.list_detail import object_list
cat = NewsCategories.objects.get(slug=slug)
news = cat.set.all().order_by('-id')
return object_list(request, news, paginate_by = 5, allow_empty = True, template_name = 'category_list.html', extra_context={'cat': slug})
(r'^news/cat/(?P<slug>[\w\-_]+)/?$','news.views.by_category'),
{% extends "index.html" %}
{% block content %}
{% if object_list %}
{% for new in object_list %}
<h3>{{ new.title }}</h3>
<p>{{ new.text }}<br />{{ new.date|truncatewords:"1" }} | <b><a href="/news/{{ new.slug }}/">Komentarze</a></b>: {{ new.newscomments_set.count }} | <b>Kategorie</b>: {% for c in new.category.all %}<a href="/news/cat/{{ c.slug }}/">{{ c }}</a> {% endfor %}</p>
{% endfor %}
{% if has_previous %}
<div style="text-align:center;"><a href="/news/cat/{{ cat }}/?page={{ previous }}"><b>Nowsze Wiadomości</b></a></div>
{% endif %}
{% if has_next %}
<div style="text-align:center;"><a href="/news/cat/{{ cat }}/?page={{ next }}"><b>Starsze Wiadomości</b></a></div>
{% endif %}
{% else %}
Brak wiadomości
{% endif %}
{% endblock %}
Teraz zajmiemy się wyświetleniem listy kategorii po prawej stronie strony. Wystarczy pobrać listę kategorii. Jednakże by była widoczna na każdej podstronie to każdy widok musiałby przekazywać zmienną z taką listą. By uniknąć takiego problemu zastosujemy własny TEMPLATE_CONTEXT_PROCESSORS, który będzie przekazywał do szablonów określone zmienne, niezależnie od tego co przekazują widoki. W katalogu projektu ("blog") stwórz plik o nazwie globals.py, o kodzie:
from django.conf import settings
from blog.news.models import *
def blog(request):
return {'categories': NewsCategories.objects.all()}
TEMPLATE_CONTEXT_PROCESSORS = ("django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"globals.blog",)
<h3>Kategorie</h3>
<ul>
{% for c in categories %}
<li><img src="/site_media/{{ c.icon }}" alt="" /> <a href="/news/cat/{{ c.slug }}/">{{ c.name }}</a></li>
{% endfor %}
</ul>
from django.template import RequestContext
A do "render_to_response" dodaj , context_instance=RequestContext(request):
return render_to_response('show.html', {'news':news, 'form':form, 'comments':comments}, context_instance=RequestContext(request))
Gotowe:

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