---
title: "Pisanie pierwszej aplikacji Django, część 3."
version: 1.10
locale: pl
source: https://docs.djangoproject.com/pl/1.10/intro/tutorial03/
canonical: https://djangodocs.dev/pl/1.10/intro/tutorial03/
---
# Pisanie pierwszej aplikacji Django, część 3.

Ten tutorial zaczyna się, gdzie skończył się :doc:Tutorial 2 \</intro/tutorial02\>. Kontynuujemy z aplikacją web-ankiet i skupimy się na tworzeniu publicznego interfejsu – „widoków”.

## Przegląd

Widok jest „typem” strony internetowej w tworzej aplikacji Django, który w ogólności służy określonej funkcji i ma określony szablon. Na przykład w aplikacji blogowej, możesz mieć następujące widoki:

- Strona główna bloga – wyświetla kilka najnowszych wpisów.
- Strona „szczegółów” wpisu – strona na pojedynczy wpis.
- Roczna strona archiwum – wyświetla wszystkie miesiące z wpisami w danym roku.
- Miesięczna strona archiwum – wyświetla wszystkie dni z wpisami w danym miesiącu.
- Dzienna strona archiwum – wyświetla wszystkie wpisy z danego dnia.
- Komentowanie – obsługuje dodawanie komentarzy do danego wpisu.

W naszej aplikacji ankietowej będziemy mieć następujące cztery widoki:

- Strona „główna” pytań – wyświetla klika najnowszych pytań.
- Strona „szczegółów” pytania – wyświetla treść pytania, bez wyników, ale z formularzem do głosowania.
- Strona „wyników” pytania – wyświetla wyniki dla wybranego pytania.
- Akcja głosowania – obsługuje głosowanie na konkretny wybór w wybranym pytaniu.

W Django strony i inna treść są dostarczane przez widoki. Każdy widok jest reprezentowany przez prostą funkcję Pythona (lub metodę, w przypadku widoków opartych na klasach). Django wybierze widok sprawdzając URL, który jest zażądany (aby być dokładnym, część URL-a po nazwie domeny).

Teraz w swoim czasie w Internecie można natknąć się na takie piękności jak „ME2/Sites/dirmod.asp?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B”. Będziesz zadowolony wiedząc, że Django pozwala nam na znacznie bardziej eleganckie *wzorce adresów URL* niż ten.

Wzorzec URL jest po prostu ogólną formą URL-a – na przykład: `/newsarchive/<year>/<month>/`.

Aby przejść z URL-a do widoku, Django używa czegoś, co znane jest jako «URLconfs». URLconf mapuje wzorce URL (opisane jako wyrażenia regularne) na widoki.

Ten tutorial zawiera podstawowe instrukcje użytkowania URLconfów. Możesz przejść do [`django.urls`](/pl/1.10/ref/urlresolvers/#module-django.urls) po więcej informacji.

## Pisanie kolejnych widoków

Teraz dodajmy kilka więcej widoków do `polls/views.py`. Te widoki są nieco inne, bo biorą argument:

*polls/views.py*

```
def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)

def results(request, question_id):
    response = "You're looking at the results of question %s."
    return HttpResponse(response % question_id)

def vote(request, question_id):
    return HttpResponse("You're voting on question %s." % question_id)
```

Podłącz te nowe widoki do modułu `polls.urls` dodając następujące wywołania [`url()`](/pl/1.10/ref/urls/#django.conf.urls.url):

*polls/urls.py*

```
from django.conf.urls import url

from . import views

urlpatterns = [
    # ex: /polls/
    url(r'^$', views.index, name='index'),
    # ex: /polls/5/
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    # ex: /polls/5/results/
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    # ex: /polls/5/vote/
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
```

Spójrz na „/polls/34/” w swojej przeglądarce. Uruchomi to metodę `detail()` i wyświetli jakiekolwiek ID podasz w URL-u. Spróbuj też „/polls/34/results/” i „/polls/34/vote/” – te wyświetlą strony wyników i głosowania.

Kiedy ktoś żąda strony z twojej witryny – powiedzmy „/polls/34/”, Django załaduje moduł `mysite.urls` Pythona, ponieważ jest wskazany przez ustawienie [`ROOT_URLCONF`](/pl/1.10/ref/settings/#std-setting-ROOT_URLCONF). Odnajduje on zmienną nazwaną `urlpatterns` i trawersuje po kolei wyrażenia regularne. Po odnalezieniu dopasowania w `'^polls/'`, odcina pasujący tekst (`„polls/”`) i wysyła pozostały tekst – `„34/”` – do URLconfa «polls.urls» do dalszego przetwarzania. Tam dopasowuje go do `r'^(?P<question_id>[0-9]+)/$'`, co kończy się wywołaniem widoku `detail()` w ten sposób:

```
detail(request=<HttpRequest object>, question_id='34')
```

Część `question_id='34'` pochodzi z `(?P<question_id>[0-9]+)`. Użycie nawiasów dookoła wzorca „wyłapuje” tekst dopasowany do tego wzorca i wysyła go jako arguement do funkcji widoku; `?P<question_id>` definiuje nazwę, która zostanie użyta, aby zidentyfikować dopasowany wzorzec; a `[0-9]+` jest wyrażeniem regularnym do dopasowania do sekwencji cyfr (na przykład liczby).

Dzięki temu, że wzorce URL są wyrażeniami regularnymi, naprawdę nie ma ograniczenia, co możesz z nimi zrobić. I nie ma potrzeby dodawać wstawek do URL-i typu `.html` – chyba że tego chcesz, w takim przypadku możesz zrobić coś takiego:

```
url(r'^polls/latest\.html$', views.index),
```

Ale nie rób tego. To głupie.

## Pisanie widoków, które faktycznie coś robią

Każdy widok jest odpowiedzialny za zrobienie jednej z dwóch rzeczy: zwrócenie obiektu [`HttpResponse`](/pl/1.10/ref/request-response/#django.http.HttpResponse) zawierającego treść dla żądanej strony lub rzucenie wyjątku takiego jak [`Http404`](/pl/1.10/topics/http/views/#django.http.Http404). Reszta zależy od ciebie.

Twój widok może czytać rekordy z bazy danych lub nie. Może używać systemu szablonów takiego jak Django – lub innego systemu szablonów Python – lub nie. Może generować plik PDF, zwracać XML, tworzyć w locie plik ZIP, cokolwiek chcesz, używając dowolnych bibliotek Pythona, których chcesz.

Wszystko, czego chce Django, to ten [`HttpResponse`](/pl/1.10/ref/request-response/#django.http.HttpResponse). Lub wyjątek.

Użyjmy własnego bazodanowego API Django, które omówiliśmy w [Tutorialu 2](/pl/1.10/intro/tutorial02/), ponieważ jest wygodne. Tu jest próba w nowym widoku `index()`, która wyświetla ostatnie 5 pytań ankietowych w systemie, oddzielone przecinkami, według daty publikacji:

*polls/views.py*

```
from django.http import HttpResponse

from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    output = ', '.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

# Leave the rest of the views (detail, results, vote) unchanged
```

Chociaż mamy tutaj problem: design strony jest zahardcodowany w widoku. Jeśli chcesz zmienić sposób, w jaki wygląda strona, będziesz musiał zmienić ten kod Pythona. Użyjmy systemu szablonów Django, aby oddzielić design od Pythona tworząc szablon, który będzie mógł użyć widok.

Najpierw stwórzmy katalog o nazwie `templates` w twoim katalogu `polls`. Django będzie tam szukał szablonów.

Ustawienie [`TEMPLATES`](/pl/1.10/ref/settings/#std-setting-TEMPLATES) twojego projektu opisuje jak Django będzie ładował i renderował szablony. Domyślny plik ustawień konfiguruje backend `DjangoTemplates`, którego opcja [`APP_DIRS`](/pl/1.10/ref/settings/#std-setting-TEMPLATES-APP_DIRS) jest ustawiona na `True`. Według konwencji `DjangoTemplates` szuka podkatalogu „templates” w każdej z [`INSTALLED_APPS`](/pl/1.10/ref/settings/#std-setting-INSTALLED_APPS).

W katalogu `templates`, który właśnie stworzyłeś, stwórz kolejny katalog o nazwie `polls` i w tym katalogu stwórz plik o nazwie `index.html`. Innymi słowy, twój szablon powinien być pod `polls/templates/polls/index.html`. Ponieważ loader szablonów `app_directories` działa jak opisano powyżej, możesz odwoływać się do tego szablonu w Django po prostu `polls/index.html`.

> **Przestrzeń nazw szablonu**
>
> Teraz *moglibyśmy* poradzić sobie umieszczając nasze szablony bezpośrednio w `polls/templates` (zamiast tworzyć kolejny podkatalog `polls`), ale w rzeczywistości byłoby to złym pomysłem. Django wybierze pierwszy szablon, którego nazwa się zgadza i jeśli miałbyś szablon o takiej samej nazwie w *innej* aplikacji, Django nie byłoby w stanie ich odróżnić. Musimy być w stanie wskazać Django odpowiedni szablon i najprostszym sposobem, aby to zapewnić jest *znamespace’owanie* ich. To znaczy umieszczenie tych szablonów w *innym* katalogu nazwanym dla samej aplikacji.

Umieść następujący kod w tym szablonie:

*polls/templates/polls/index.html*

```html+django
{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}
```

Teraz zaktualizujmy nasz widok `index` w `polls/views.py`, aby używał szablonu:

*polls/views.py*

```
from django.http import HttpResponse
from django.template import loader

from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    template = loader.get_template('polls/index.html')
    context = {
        'latest_question_list': latest_question_list,
    }
    return HttpResponse(template.render(context, request))
```

Ten kod ładuje szablon o nazwie `polls/index.html` i przekazuje mu kontekts. Kontekst jest słownikiem mapującym nazwy zmiennych szablonu do obiektów Pythona.

Załaduj stronę kierując swoją przeglądarkę na „/polls/”. Powinnieneś zobaczyć wypunktowaną listę zawierającą pytanie „What’s up” z [Tutoriala 2](/pl/1.10/intro/tutorial02/). Link kieruje do strony szczegółów pytania.

### Skrót: [`render()`](/pl/1.10/topics/http/shortcuts/#django.shortcuts.render)

To popularny idiom do ładowania szablonu, wypełniania kontekstu i zwracania obiektu [`HttpResponse`](/pl/1.10/ref/request-response/#django.http.HttpResponse) z wynikiem wyrenderowanego szablonu. Djano daje skrót. Tutaj jest pełen widok `index()`, napisany na nowo:

*polls/views.py*

```
from django.shortcuts import render

from .models import Question

def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    context = {'latest_question_list': latest_question_list}
    return render(request, 'polls/index.html', context)
```

Zwróć uwagę, że kiedy zrobiliśmy to w tych wszystkich widokach, nie potrzebujemy już importować [`loader`](/pl/1.10/topics/templates/#module-django.template.loader) i [`HttpResponse`](/pl/1.10/ref/request-response/#django.http.HttpResponse) (będziesz chciał zatrzymać `HttpResponse` jeśli wciąż masz zaczątki metod dla `detail`, `results` i `vote`).

Funkcja [`render()`](/pl/1.10/topics/http/shortcuts/#django.shortcuts.render) bierze obiekt request jako swój pierwszy argument, nazwę szablonu jako drugi argument i słownik jako swój opcjonalny trzeci argument. Zwraca obiekt [`HttpResponse`](/pl/1.10/ref/request-response/#django.http.HttpResponse) danego szablonu wyrenderowany z danym kontekstem.

## Zgłaszanie błędu 404

Teraz zawalczmy z widokiem szczegółów pytania – strony, która wyświetla treść pytania dla danej ankiety. Tutaj jest widok:

*polls/views.py*

```
from django.http import Http404
from django.shortcuts import render

from .models import Question
# ...
def detail(request, question_id):
    try:
        question = Question.objects.get(pk=question_id)
    except Question.DoesNotExist:
        raise Http404("Question does not exist")
    return render(request, 'polls/detail.html', {'question': question})
```

Nowy koncept tutaj: Widok zgłasza wyjątek [`Http404`](/pl/1.10/topics/http/views/#django.http.Http404) jeśli pytanie o żądanym ID nie istnieje.

Omówimy trochę później co mógłbyś umieścić w tym szablonie `polls/detail.html`, ale jeśli chcesz, aby powyższy przykład szybko zaczął działać, plik zawierający tylko:

*polls/templates/polls/detail.html*

```html+django
{{ question }}
```

pomoże ci wystartować na teraz.

### Skrót: [`get_object_or_404()`](/pl/1.10/topics/http/shortcuts/#django.shortcuts.get_object_or_404)

To popularny idiom do używania [`get()`](/pl/1.10/ref/models/querysets/#django.db.models.query.QuerySet.get) i zgłaszania [`Http404`](/pl/1.10/topics/http/views/#django.http.Http404) jeśli obiekt nie istnieje. Django daje skrót. Tutaj jest widok `detail()` przepisany:

*polls/views.py*

```
from django.shortcuts import get_object_or_404, render

from .models import Question
# ...
def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, 'polls/detail.html', {'question': question})
```

Funkcja [`get_object_or_404()`](/pl/1.10/topics/http/shortcuts/#django.shortcuts.get_object_or_404) bierze model Django jako swój pierwszy argument i wyznaczoną wcześniej liczbę arguementów nazwanych, które przekazuje do funkcji [`get()`](/pl/1.10/ref/models/querysets/#django.db.models.query.QuerySet.get) menadżera modelu. Zgłasza [`Http404`](/pl/1.10/topics/http/views/#django.http.Http404) jeśli obiekt nie istnieje.

> **Filozofia**
>
> Dlaczego używamy funkcji pomocniczej [`get_object_or_404()`](/pl/1.10/topics/http/shortcuts/#django.shortcuts.get_object_or_404) zamiast automatycznie wyłapywać wyjątki [`ObjectDoesNotExist`](/pl/1.10/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist) na wyższym poziomie lub powodując, że API modelu będzie zgłaszać [`Http404`](/pl/1.10/topics/http/views/#django.http.Http404) zamiast [`ObjectDoesNotExist`](/pl/1.10/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist)?
>
> Ponieważ to związałoby warstwę modelu z warstwą widoku. Jednym z najważniejszych celów projektowych Django było utrzymywania luźnych więzów. Trochę kontrolowanego wiązania jest wprowadzone w module [`django.shortcuts`](/pl/1.10/topics/http/shortcuts/#module-django.shortcuts).

Jest też funkcja [`get_list_or_404()`](/pl/1.10/topics/http/shortcuts/#django.shortcuts.get_list_or_404), która działa tak samo jak [`get_object_or_404()`](/pl/1.10/topics/http/shortcuts/#django.shortcuts.get_object_or_404) – z wyjątkiem używania [`filter()`](/pl/1.10/ref/models/querysets/#django.db.models.query.QuerySet.filter) zamiast [`get()`](/pl/1.10/ref/models/querysets/#django.db.models.query.QuerySet.get). Zgłasza wyjątek [`Http404`](/pl/1.10/topics/http/views/#django.http.Http404) gdy lista jest pusta.

## Użyj systemu szablonów

Wracamy do widoku `detail()` naszej aplikacji ankietowej. Mając zmienną kontekstową `question`, tak mógłby wyglądać nasz szablon `polls/detail.html`:

*polls/templates/polls/detail.html*

```html+django
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
```

System szablonów używa składni kropkowego lookupu, aby dostać się do atrybutów zmiennej. W przykładzie `{{ question.question_text }}`, najpierw Django robi słownikowy lookup na obiekcie `question`. Gdy to się nie uda, próbuje atrybutowego lookupu – który w tym przypadku działa. Gdyby atrybutowy lookup się nie powiódł, spróbowałoby lookupu przez indeks listy.

Wywoływanie metod dzieje się w pętli [`{% for %}`](/pl/1.10/ref/templates/builtins/#std-templatetag-for): `question.choice_set.all` jest interpretowane jako kod Pythona `question.choice_set.all()`, który zwraca iterator obiektów `Choice` i jest odpowiedni do użycia w tagu [`{% for %}`](/pl/1.10/ref/templates/builtins/#std-templatetag-for).

Zobacz [przewodnik po szablonach](/pl/1.10/topics/templates/) po więcej informacji na temat szablonów.

## Usuwanie wstawionych na szytwno URL-i z szablonów

Pamiętasz, kiedy wpisaliśmy link do pytania w szablonie `polls/index.html`, link był częściowo wpisany na sztywno, w ten sposób:

```html+django
<li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
```

Problem z tym podejściem z hardkodowaniem jest taki, że staje się niezwykle trudna zmiana URL-i w projektach z dużą liczbą szablonów. Jednakże, odkąd zdefiniowałeś nazwany argument w funkcjach [`url()`](/pl/1.10/ref/urls/#django.conf.urls.url) w module `polls.urls`, możesz usunąć poleganie na poszczególnych ścieżkach URL zdefiniowanych w twoich konfiguracjach URL-i używając szablonowego taga `{% url %}`:

```html+django
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
```

Działa to przez sprawdzenie definicji URL-a według specyfikacji w module `polls.urls`. Możesz zobaczyć poniżej, gdzie dokładnie nazwa «detail» jest zdefiniowana w URL-u:

```
...
# the 'name' value as called by the {% url %} template tag
url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...
```

Jeśli chcesz zmienić URL widoku szczegółów ankiety na jakiś inny, na przykład na coś w stylu `polls/specifics/12/`, zamiast robić to w szablonie (lub szablonach), zmieniłbyś to w `polls/urls.py`:

```
...
# added the word 'specifics'
url(r'^specifics/(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
...
```

## Przestrzenie nazw dla nazw URL-i

Projekt tutorialowy ma tylko jedną aplikację, `polls`. W prawdziwych projektach Django może być pięć, dziesięć, dwadzieścia lub więcej aplikacji. Jak Django odróżnia nazwy URL pomiędzy nimi? Na przykład aplikacja `polls` ma widok `detail` i tak samo mogłaby mieć aplikacja blogowa w tym samym projekcie. Jak zrobić, aby Django wiedziało, której aplikacji widok stworzyć dla urla w przypadku użycia taga `{% url %}`?

Odpowiedzią jest dodanie przestrzeni nazw do twojego URLconfa. W pliku `polls/urls.py` dodaj `app_name`, aby ustawić przestrzeń nazw aplikacji:

*polls/urls.py*

```
from django.conf.urls import url

from . import views

app_name = 'polls'
urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^(?P<question_id>[0-9]+)/$', views.detail, name='detail'),
    url(r'^(?P<question_id>[0-9]+)/results/$', views.results, name='results'),
    url(r'^(?P<question_id>[0-9]+)/vote/$', views.vote, name='vote'),
]
```

Teraz zmień swój szablon `polls/index.html` z:

*polls/templates/polls/index.html*

```html+django
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
```

aby wskazywał na widok szczegółów w przestrzeni nazw:

*polls/templates/polls/index.html*

```html+django
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
```

Jeśli czujesz się dobrze z pisaniem widoków, przeczytaj [część czwartą tego tutoriala](/pl/1.10/intro/tutorial04/), aby dowiedzieć się na temat przetwarzania prostych formularzy i widokach generycznych.
