Skip to content

Latest commit

 

History

History
 
 

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 

README.md

Расширяем свое приложение

Мы уже выполнили часть необходимых шагов для создания веб-сайта: мы знаем как создать модель, URL, представление и шаблон. Мы также знаем как улучшить визуальный дизайн с помощью CSS.

Время практики!

Первое, что нам потребуется в блоге - страница для отображения конкретной записи, верно?

У нас уже есть модель 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|linebreaks }}</p>
            </div>
        {% endfor %}
    {% endblock content %}

{% raw %}Нам хотелось бы иметь ссылку с заголовка поста в списке на страницу подробной информации о посте. Давай изменим <h1><a href="">{{ post.title }}</a></h1> чтобы получилась ссылка на пост:{% endraw %}

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

{% raw %}Самое время разобраться с загадочным {% url 'post_detail' pk=post.pk %}. Как можешь предположить, синтаксис {% %} означает использование тегов шаблонов Django. На этот раз мы используем тот, что создаст для нас URL!{% endraw %}

blog.views.post_detail это путь к представлению post_detail, которое нам нужно создать. Пожалуйста, обрати внимание: blog - это имя нашего приложения (директория blog), views - имя файла views.py без расширения и последнее - post_detail - имя представления.

Теперь, когда мы перейдем по адресу http://127.0.0.1:8000/ мы получим ошибку (как и ожидается, поскольку у нас нет прописанного URL и представления для post_detail). Она будет выглядеть следующим образом:

Ошибка NoReverseMatch

Создадим URL для страницы поста

Давай создадим URL в urls.py для представления post_detail!

Мы хотим, чтобы адрес страницы нашего первого поста был таким: URL: http://127.0.0.1:8000/post/1/

Давай создадим URL в файле 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 include, 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):. Обрати внимание, что мы должны использовать тоже имя переменной, что мы выбрали для обработки URL (pk). Пропуск переменной будет неправилен и приведет к ошибке!

Теперь мы хотим получить одну конкретную запись из блога. Для этого потребуется использовать QuerySet:

    Post.objects.get(pk=pk)

Однако в этом коде есть проблема. Если не существует экземпляра объекта Post с заданным primary key (pk) мы получим страшную ошибку!

Ошибка DoesNotExist

Мы этого не хотим! Однако, Django, конечно, имеет средство, которое позволит нам её обойти: get_object_or_404. В случае, если не существует экземпляра объекта Post с заданным pk, мы получим намного более приятную страницу (которая называется Page Not Found 404).

Страница не найдена

Хорошая новость в том, что ты можешь сделать свою страницу 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/

Представление списка записей

Заработало! Только что произойдет, если ты попробуешь перейти по ссылке из заголовка записи?

Ошибка TemplateDoesNotExist

Ой, нет! Другая ошибка! Но мы уже знаем как иметь с ней дело, верно? Нам нужно добавить шаблон!

Создадим шаблон для страницы поста

Мы создадим файл post_detail.html в директории blog/templates/blog.

Он должен содержать следующее:

    {% 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|linebreaks }}</p>
        </div>
    {% endblock %}

И снова мы расширяем base.html. В блоке content мы отображаем дату публикации (published_date, если она существует), заголовок и текст. Нам также нужно обсудить пару важных вещей, хорошо?

{% raw %}{% if ... %} ... {% endif %} это тег шаблона, который мы можем использовать, если нам нужно что-то проверить (помнишь конструкцию if ... else .. из главы Введение в Python?). В данном случае мы хотим проверить, не пуста ли дата публикации published_date поста.{% endraw %}

Отлично, можешь перезагрузить страницу и проверить пропала ли ошибка Page not found.

Отдельная страницы записи

Ура! Все работает!

Еще одна вещь: развертывание!

Было бы неплохо проверить, что веб-сайт все еще будет работать на PythonAnywhere, верно? Давай еще раз проведем развертывание.

    $ git status
    $ git add -A .
    $ 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
    [...]
  • И нажми Reload на вкладке Web tab.

Вот и все! Поздравляем :)