Generic Views - "Ogólne" widoki Django wykonują z góry określoną czynność i są bardzo poręczne przy tworzeniu widoków o "popularnej" funkcjonalności. Generyczne widoki nie zostały stworzone jako zastępstwo własnych widoków. Jeżeli potrzebujemy coś więcej, niż to, co oferuje generyczny widok to musimy napisać własny widok. Oto lista generycznych widoków:
- django.views.generic.simple.direct_to_template
- django.views.generic.simple.redirect_to
- django.views.generic.date_based.archive_index
- django.views.generic.date_based.archive_year
- django.views.generic.date_based.archive_month
- django.views.generic.date_based.archive_week
- django.views.generic.date_based.archive_day
- django.views.generic.date_based.archive_today
- django.views.generic.date_based.object_detail
- django.views.generic.list_detail.object_list
- django.views.generic.list_detail.object_detail
- django.views.generic.create_update.create_object
- django.views.generic.create_update.update_object
- django.views.generic.create_update.delete_object
Funkcja
django.views.generic.simple.direct_to_template parsuje podany szablon przekazując do szablonu słownik
{{ params }} zawierający parametry złapane z URLa. Przykład:
urlpatterns = patterns('django.views.generic.simple',
(r'^foo/$', 'direct_to_template', {'template': 'foo_index.html'}),
(r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template': 'foo_detail.html'}),
)
Żądanie
/foo/ wyświetliłoby szablon
foo_index.html, a żądanie
/foo/15/ szablon
foo_detail.html ze zmienną
{{ params.id }} o wartości 15. Argument
template jest wymagany i wskazuje szablon.
Funkcja
django.views.generic.simple.redirect_to przekierowuje na podany URL. Podany URL może zawierać formatowanie łańcuchów podobne do słownikowego, które będzie interpolowane względem złapanych z URLa zmiennych. Jeżeli za URL podane będzie None Django zwróci HTTP 410 (Gone). Poniższy przykład przekierowuje z
/foo/(id)/ na
/bar/(id)/:
urlpatterns = patterns('django.views.generic.simple',
('^foo/(?p<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
)
Argument
url jest wymagany i wskazuje URL, na który ma nastąpić przekierowanie.
Kolejne, bardziej złożone widoki przyjmują sporą liczbę dodatkowych argumentów, takie jak:
- allow_empty - Wartość logiczna, określająca czy wyświetlać stronę w przypadku braku obiektów do wyświetlania. W przypadku ich braku i wartości False widok zwróci błąd 404
- context_processors - Lista parserów template-context, jakie mają być nałożone na szablon widoku.
- extra_context - Słownik z dodatkowymi zmiennymi, jakie mają być przekazane do szablonu
- mimetype - Typ MIME dla wyniku. Domyślnie przyjmuje wartość DEFAULT_MIME_TYPE.
- template_loader - Określa nazwę modułu ładującego szablon. Domyślnie jest to django.template.loader i nie wymaga modyfikacji
- template_name - Nazwa szablonu do wykorzystania.
django.views.generic.list_detail.object_list listuje wpisy danego modelu z możliwością listowania. Wymagany argument to
queryset - czyli "zapytanie" ORMa Django zwracające określony wynik. Przykładowo, mamy prosty model:
class News(models.Model):
title = models.CharField(maxlength=255, verbose_name='Tytuł')
text = models.TextField(verbose_name='Treść')
date = models.DateTimeField(auto_now_add = True, blank=True, verbose_name='Data dodania')
A do urls.py dodajemy:
from django.conf.urls.defaults import *
from projekt.aplikacja.models import *
urlpatterns = patterns('',
(r'^/?$', 'django.views.generic.list_detail.object_list', {'queryset':News.objects.all().order_by('-id'), 'paginate_by':10, 'allow_empty':True, 'template_name':'content/news_list.html'}),)
Przypisujemy listowanie news wraz ze stronicowaniem na stronie głównej (/). Zmienna
paginate_by określa ile wpisów wyświetlać na jednej stronie. Do szablonu przekazanie zostanie zmienna
object_list zawierająca wpisy. Przykładowy szablon:
{% for new in object_list %}
<h1>{{ new.title }}</h1><div class="htimeauth">{{ new.date|truncatewords:"1" }}</div>
<p>{{ new.text }}</p>
{% endfor %}
{% if has_previous %}
<div style="text-align:center;"><a href="/?page={{ previous }}"><b>Nowsze Wiadomości</b></a></div>
{% endif %}
{% if has_next %}
<div style="text-align:center;"><a href="/?page={{ next }}"><b>Starsze Wiadomości</b></a></div>
{% endif %}
Zmienna QueryString
page określa stronę stronicowania dla tego generycznego widoku. Oprócz tego w szablonie mamy zmienne:
- is_paginated - Wartość logiczna, True jeżeli lista jest stronicowana (i jest wystarczająca ilość wpisów)
- has_next - Wartość logiczna, czy jest kolejna strona stronicowania
- has_previous - Wartość logiczna, czy jest wcześniejsza strona stronicowania
- page - Numer obecnej strony stronicowania
- next, previous - Numer następnej, poprzedniej strony stronicowania
- pages - Liczba wszystkich stron stronicowania
Zmienną stronicowania zamiast w QueryString można wpisać w URL podając go w wyrażeniu:
(r'^/?$', 'django.views.generic.list_detail.object_list', {'queryset':News.objects.all().order_by('-id'), 'paginate_by':10, 'allow_empty':True, 'template_name':'content/news_list.html'}),
(r'^(?P<page>[0-9]+)/?$', 'django.views.generic.list_detail.object_list', {'queryset':News.objects.all().order_by('-id'), 'paginate_by':10, 'allow_empty':True, 'template_name':'content/news_list.html'}),
I http://localhost:8080/2/ będzie równoznaczne z http://localhost:8080/?page=2
django.views.generic.list_detail.object_detail wyświetla określony wpis identyfikowany po ID lub polu typu slugField. Do szablonu przekazana zostanie zmienna
{{ object }} zawierająca wszystkie dane wybranego wpisu. Przykładowo prosty model z polem SlugField:
class Page(models.Model):
title = models.CharField(maxlength=255, verbose_name='Tytuł')
slug = models.SlugField(maxlength=255, unique=True, verbose_name='Odnośnik', prepopulate_from=['title'])
description = models.CharField(maxlength=255, verbose_name='Opis')
text = models.TextField(verbose_name='Treść')
I generyczny widok:
from projekt.aplikacja.models import *
....
(r'^p/(?P<slug>[\w\-_]+)/', 'django.views.generic.list_detail.object_detail', {'queryset':Page.objects.all() , 'slug_field':'slug', 'template_name':'content/page_show.html'}),
- slug_field - Określa wartość pola typu SlugField, po której odnaleziony ma być wpis (nazwa zmiennej z URLa jak i nazwa pola typu SlugField modelu)
- slug - Ustawiona wartość pola typu SlugField w modelu
- object_id - Określa wartość pola "id" modelu, po której odnaleziony ma być wpis (nazwa zmiennej z URLa)
Widoki generyczne zebrane w
django.views.generic.date_based pozwalają wyświetlać wpisy na podstawie dany - sposób na prezencję archiwalnej zawartości.
django.views.generic.date_based.archive_index tworzy "stronę główną" dla archiwum - generuję listę lat, dla których istnieją wpisy oraz wyświetla listę najnowszych wpisów.
book_info = {
"queryset" : Book.objects.all(),
"date_field" : "publication_date"
}
......
(r'^books/$', date_based.archive_index, book_info),
queryset, jak i
date_field są wymagane.
date_field Określa nazwę pola typu DateField lub DateTimeField modelu. Dodatkowe argumenty:
allow_future - Wartość logiczna, określająca czy dołączyć obiekty z "przyszłości",
num_latest - liczba ostatnich wpisów jakie mają być przekazane do szablonu, domyślnie 15. Oprócz tego obsługiwane są: allow_empty, context_processors, extra_context, mimetype, template_loader, template_name.
Jeżeli template_name nie będzie określone przyjęta zostanie domyślna wartość [etykieta_aplikacji]/[nazwa_modelu]_archive.html
Do szablonu przekazane zostaną dwie zmienne:
date_list - listę obiektów datetime.date dla poszczególnych lat, dla których istnieją wpisy.
latest - lista ostatnich wpisów.
django.views.generic.date_based.archive_year umożliwia tworzenie archiwów dla poszczególnych lat pokazując miesiące, dla których istnieją wpisy. Dochodzi trzeci wymagany argument
year określający rok (czterocyfrowy zapis). Argument opcjonalny
make_object_list przyjmuje wartość logiczną i w przypadku True do szablonu przekazana zostanie pełna lista obiektów pod zmienną
{{ object_list }}. Przykładowy URLconf:
(r'^books/(?P<year>\d{4})/?$', date_based.archive_year, book_info),
Do szablonu zostanie przekazana zmienna
date_list, lista obiektów datetime.date miesięcy, dla których istnieją wpisy.
django.views.generic.date_based.archive_month umożliwia tworzenie archiwów dla poszczególnych dni miesiąca. Przykładowy URLconf:
(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', date_based.archive_month, book_info),
Wymagany argument
month określa dany miesiąc. Domyślny format to trzyliterowy skrót nazwy miesiąca (angielskiej nazwy) np.: "jan", "feb". By stosować zapisu liczbowego należy podać argument opcjonalny
month_format o wartości
"%m". Do szablonu przekazane zostaną zmienne:
- month - obiekt datetime.date reprezentujący bieżący miesiąc
- next_month - to samo dla kolejnego miesiąca. Jeżeli wypada w przyszłości zmienna przyjmie wartość None.
- previous_month - to samo dla wcześniejszego miesiąca
- object_list - lista obiektów dostępna dla danego miesiąca. Nazwa zmiennej zależy od wartości template_object_name (domyślnie "object"). W przypadku przypisania innej wartości do template_object_name otrzymamy WARTOŚĆ_list
Generyczny widok
django.views.generic.list_detail.object_list jest bardzo poręczny. Ten jak i inne widoki generyczne można wykorzystać w zwykłych widokach (gdy chcemy jego funkcjonalności ale musimy także wykonać inny dodatkowy kod uniemożliwiający bezpośrednie zastosowanie generycznego widoku). Oto przykład widoku listującego posty danego tematu:
def post_list(request, topic_id, pagination_id):
# importujemy generyczny widok
from django.views.generic.list_detail import object_list
# czy temat istnieje
try:
topic = Topic.objects.get(id=topic_id)
except Topic.DoesNotExist:
return HttpResponseRedirect('/forum/')
return object_list(request, topic.post_set.all().order_by('post_date'), paginate_by = 10, page = pagination_id, extra_context = {}, template_name = 'myghtyboard/post_list.html')
Z regułą URLconf:
(r'^topic/(?P<pagination_id>[0-9]+)/(?P<topic_id>[0-9]+)/$', 'views.post_list'),
Widok
post_list zwraca
object_list czyli generyczny widok listujący wpisy ze stronicowaniem. Podane są takie argumenty jak "paginate_by" czy
extra_context zawierający dodatkowe zmienne przekazywane do szablonu. W porównaniu do wersji z URLconf
pierwszy argument to "request", a drugi - nasz queryset - te argumenty są wymagane, w takiej kolejności. Po nich możemy podać pozostałe.
- Dodane: 14.07.2008 przez riklaunim