Розширте свою програму

Ми вже завершили усі кроки, необхідні для створення нашого сайту: знаємо як написати модель, url, відображення та шаблон. А також знаємо про те, як зробити наш сайт гарнішим.

Час попрактикуватись!

Перша потрібна для нашого блогу річ це, очевидно, сторінка для відображення одного посту, чи не так?

У нас вже є модель Post, отже? не треба нічого додавати до models.py.

Створюємо в шаблоні посилання на сторінку посту

Почнемо із додавання посилання в blog/templates/blog/post_list.html. Таким чином, матимемо:

{% extends 'blog/base.html' %}

{% block content %}
    {% for post in posts %}
        <div class="post">
            <div class="date">
                {{ post.published_date }}
            </div>
            <h1><a href="">{{ post.title }}</a></h1>
            <p>{{ post.text|linebreaksbr }}</p>
        </div>
    {% endfor %}
{% endblock %}

Ми хочемо, щоб в списку постів заголовок посилався на сторінку детальної інформації про пост. Давайте змінимо <h1><a href="">{{ post.title }}</a></h1> так, щоб вийшло посилання на пост:

<h1><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h1>

Саме час пояснити цей дивний запис {% url 'post_detail' pk=post.pk %}. Як можна було очікувати, {% %} означає, що ми використовуємо шаблонні теги Django. Цього разу ми використаєм один з них, який створить URL для нас!

blog.views.post_detail - це шлях до відображення post_detail, яке ми бажаємо створити. Зауважте, будь ласка, що: blog - це ім'я нашого додатку (папка blog), views взято з імені файлу views.py і остання частина - post_detail - це ім'я відображення.

Тепер, коли перейдемо на: http://127.0.0.1:8000/, отримаємо помилку (як і очікувалось, оскільки у нас немає URL або потрібного вигляду (в'ю) для post_detail). Він буде виглядати наступним чином:

NoReverseMatch error

Створюєм адресу URL для деталей запису

Давайте створимо URL в urls.py для нашого відображення post_detail!

Ми хочемо, щоб наш перший пост був доступний за такою URL-адресою: http://127.0.0.1:8000/post/1/

У файлі blog/urls.py вкажемо Django, де взяти відображення для запису блогу, яке називається post_detail. Додамо рядок url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),у файл blog/urls.py. Це має виглядати якось так:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.post_list, name='post_list'),
    url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
]

Ця частина ^post/(?P<pk>[0-9]+)/$ виглядає страшно, але не хвилюйтеся - зараз ми все пояснимо:

  • вона починається з ^ - цей символ означає "початок",
  • далі post/ означає, що після початку, URL-адреса має містити слова post та /. Все йде добре.
  • (?P<pk>[0-9]+) - ця частина хитріша. Вона означає, що Django візьме усе, що ви тут розмістите і передасть це до відображення як змінну із ім'ям pk. [0-9] також повідомляє нам про те, що це може бути лише цифрою, а не літерою (будь-яке значення між 0 та 9). + означає, що тут має бути один або більше символів. Таким чином, щось на зразок http://127.0.0.1:8000/post// є неприйнятним, однак http://127.0.0.1:8000/post/1234567890/ цілком!
  • / - далі нам потрібно знову /
  • $ - "кінець"!

Це означає, що якщо введете http://127.0.0.1:8000/post/5/, Django зрозуміє, що ви шукаєте відображення із назвою post_detail і передає цьому відображенню інформацію, що pk дорівнює 5.

pk - скорочення для первинного ключа - primary key. Це ім'я часто використовується в Django проектах. Однак, можете назвати вашу змінну як вам до вподоби (пам'ятайте: маленькі літери і _ замість пробілів!). Наприклад, замість (?P<pk>[0-9]+) можемо мати змінну post_id, і, таким чином, ця частина буде виглядати як: (?P<post_id>[0-9]+).

Добре, ми додали новий шаблон URL для blog/urls.py! Давайте перезавантажимо сторінку: http://127.0.0.1:8000/ Опаньки! Знову помилка! Як ми і очікували.

AttributeError

Пам'ятаєте наступний крок? Звісно: треба додати відображення!

Додамо деталі для відображення запису

Цього разу наше відображення отримує додатковий параметр - pk. Наше відображення має вилучити його, правда ж? Отже, визначимо нашу функцію як def post_detail(request, pk):. Зауважте, що треба використовувати точно таке ж ім'я, як ми визначили в urls (pk). Неправильно нехтувати цією змінною, це призведе до помилки!

А тепер, ми хотіли б додати один-єдиний пост. Щоб зробити, це можемо скористатися наступним запитом до бази даних:

Post.objects.get(pk=pk)

Однак, цей код містить проблеми. Якщо немає жодного поста із заданим первинним ключем (pk), ми отримаємо мегажахливу помилку!

DoesNotExist error

Ми цього не хочемо! Звичайно, Django надає деякі інструменти, що будуть обробляти це для нас: get_object_or_404. У випадку, якщо немає постів із заданим pk, виведеться більш приємна сторінка (так звана сторінка Page Not Found 404).

Page not found

Хороші новини полягають в тому, що можна створити свою власну сторінку Page not found і зробити її настільки гарною, наскільки ви захочете. Однак, це не є надто важливим на даний момент, тому пропустимо цей крок.

Добре, час додати відображення у наш файл views.py!

Нам треба відкрити blog/views.py і додати наступний код:

from django.shortcuts import render, get_object_or_404

Поряд із іншими рядками from. А в кінці файлу додамо наше відображення:

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

Так. Прийшла пора оновити сторінку: http://127.0.0.1:8000 /

Post list view

Спрацювало! Але що ж трапиться, коли ви натиснете на посилання в заголовку поста?

TemplateDoesNotExist error

О, ні! Інша помилка! Але ж ми вже знаємо, як із цим поводитись, чи не так? Потрібно додати шаблон!

Створюємо шаблон для деталей запису

Створимо файл в blog/templates/blog і назвемо його post_detail.html.

Це буде виглядати так:

{% extends 'blog/base.html' %}

{% block content %}
    <div class="post">
        {% if post.published_date %}
            <div class="date">
                {{ post.published_date }}
            </div>
        {% endif %}
        <h1>{{ post.title }}</h1>
        <p>{{ post.text|linebreaksbr }}</p>
    </div>
{% endblock %}

Знову розширюємо base.html. Всередині блоку content ми хотіли б відобразити такі параметри як: published_date (якщо існує), title і text. Але мусимо обговорити певні важливі речі, правда ж?

{% if ... %} ... {% endif %} - це шаблонний тег, який можна використовувати, коли ми бажаємо перевірити дещо (пам'ятаєте if ... else .. з розділу Вступ до Python?). У цьому випадку ми хочемо перевірити, чи дата запису published_date не порожня.

Окей, можемо перезавантажити нашу сторінку і побачити, чи повідомлення Page not found тепер зникло.

Post detail page

Йой! Працює!

Ще одне: розгортання!

Було б добре переконатись, що ваш сайт буде працювати на PythonAnywhere, вірно? Спробуймо зробити розгортання ще раз.

$ git status
$ git add --all .
$ git status
$ git commit -m "Added view and template for detailed blog post as well as CSS for the site."
$ git push
$ cd my-first-blog
$ source myvenv/bin/activate
(myvenv)$ git pull
[...]
(myvenv)$ python manage.py collectstatic
[...]
  • Нарешті, перейдіть на вкладку Web і натисніть Reload.

І це все! Вітання :)

results matching ""

    No results matching ""