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

Ten tutorial zaczyna się, gdzie skończył się [Tutorial 2](/pl/4.2/intro/tutorial02/). Kontynuujemy z aplikacją web-ankiet i skupimy się na tworzeniu publicznego interfejsu – „widoków”.

> **Gdzie szukać pomocy:**
>
> Jeśli masz trudności w przejściu tego tutorialu, przejdź do sekcji [Uzyskiwanie pomocy](/pl/4.2/faq/help/) często zadawanych pytań.

## 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 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.htm?sid=&type=gen&mod=Core+Pages&gid=A6CD4967199A42D9B65B1B`. Ucieszysz się wiedząc, że Django pozwala nam na znacznie bardziej eleganckie *wzorce adresów URL* niż ten.

Wzorzec URL jest 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 na widoki.

Ten tutorial zawiera podstawowe instrukcje użytkowania URLconfów. Możesz przejść do [URL dispatcher](/pl/4.2/topics/http/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`*

```python
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 [`path()`](/pl/4.2/ref/urls/#django.urls.path):

*`polls/urls.py`*

```python
from django.urls import path

from . import views

urlpatterns = [
    # ex: /polls/
    path("", views.index, name="index"),
    # ex: /polls/5/
    path("<int:question_id>/", views.detail, name="detail"),
    # ex: /polls/5/results/
    path("<int:question_id>/results/", views.results, name="results"),
    # ex: /polls/5/vote/
    path("<int:question_id>/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/4.2/ref/settings/#std-setting-ROOT_URLCONF). Odnajduje on zmienną nazwaną `urlpatterns` i trawersuje po kolei wzorce. 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 `'<int:question_id>/'`, co kończy się wywołaniem widoku `detail()` w ten sposób:

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

Część `question_id=34` pochodzi z `<int:question_id>`. Użycie nawiasów trójkątnych  „wyłapuje” część URL-a i wysyła ją jako argument do funkcji widoku. Część `:question_id>` ciągu znaków określa nazwę, która zostanie użyta, aby zidentyfikować dopasowany wzorzec, a część `<int:` jest konwerterem, który określa jakie wzorce powinny pasować do tej części ścieżki URL. Dwukropek (`:`) rozdziela nazwy konwertera i wzorca.

## 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/4.2/ref/request-response/#django.http.HttpResponse) zawierającego treść dla żądanej strony lub rzucenie wyjątku takiego jak [`Http404`](/pl/4.2/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/4.2/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/4.2/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`*

```python
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/4.2/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/4.2/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/4.2/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 `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 najlepszym 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 %}
```

> **Note**
>
> Aby skrócić tutorial, wszystkie przykłady szablonów używają niepełnego HTML-a. W swoich projektach powinieneś używać [pełnych dokumentów HTML](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started#anatomy_of_an_html_document).

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

*`polls/views.py`*

```python
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/4.2/intro/tutorial02/). Link kieruje do strony szczegółów pytania.

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

To popularny idiom do ładowania szablonu, wypełniania kontekstu i zwracania obiektu [`HttpResponse`](/pl/4.2/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`*

```python
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/4.2/topics/templates/#module-django.template.loader) i [`HttpResponse`](/pl/4.2/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/4.2/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/4.2/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`*

```python
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/4.2/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/4.2/topics/http/shortcuts/#django.shortcuts.get_object_or_404)

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

*`polls/views.py`*

```python
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/4.2/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/4.2/ref/models/querysets/#django.db.models.query.QuerySet.get) menadżera modelu. Zgłasza [`Http404`](/pl/4.2/topics/http/views/#django.http.Http404) jeśli obiekt nie istnieje.

> **Filozofia**
>
> Dlaczego używamy funkcji pomocniczej [`get_object_or_404()`](/pl/4.2/topics/http/shortcuts/#django.shortcuts.get_object_or_404) zamiast automatycznie wyłapywać wyjątki [`ObjectDoesNotExist`](/pl/4.2/ref/exceptions/#django.core.exceptions.ObjectDoesNotExist) na wyższym poziomie lub powodując, że API modelu będzie zgłaszać [`Http404`](/pl/4.2/topics/http/views/#django.http.Http404) zamiast [`ObjectDoesNotExist`](/pl/4.2/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/4.2/topics/http/shortcuts/#module-django.shortcuts).

Jest też funkcja [`get_list_or_404()`](/pl/4.2/topics/http/shortcuts/#django.shortcuts.get_list_or_404), która działa tak samo jak [`get_object_or_404()`](/pl/4.2/topics/http/shortcuts/#django.shortcuts.get_object_or_404) – z wyjątkiem używania [`filter()`](/pl/4.2/ref/models/querysets/#django.db.models.query.QuerySet.filter) zamiast [`get()`](/pl/4.2/ref/models/querysets/#django.db.models.query.QuerySet.get). Zgłasza wyjątek [`Http404`](/pl/4.2/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/4.2/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/4.2/ref/templates/builtins/#std-templatetag-for).

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

## Usuwanie wstawionych na sztywno 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 [`path()`](/pl/4.2/ref/urls/#django.urls.path) 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
path("<int:question_id>/", 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'
path("specifics/<int:question_id>/", 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`*

```python
from django.urls import path

from . import views

app_name = "polls"
urlpatterns = [
    path("", views.index, name="index"),
    path("<int:question_id>/", views.detail, name="detail"),
    path("<int:question_id>/results/", views.results, name="results"),
    path("<int:question_id>/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/4.2/intro/tutorial04/), aby dowiedzieć się podstaw o przetwarzaniu formularzy i widokach generycznych.
