Архив проекта:
Убедитесь, что в ходе спринта вы полностью выполнили все задания в уроках: они будут проверяться вместе с домашним заданием.
1. В проект добавлены кастомные страницы ошибок:
- 404 page_not_found
- 500 server_error
- 403 permission_denied_view
Написан тест, проверяющий, что страница 404 отдает кастомный шаблон.
2. С помощью sorl-thumbnail выведены иллюстрации к постам:
- в шаблон главной страницы,
- в шаблон профайла автора,
- в шаблон страницы группы,
- на отдельную страницу поста.
Написаны тесты, которые проверяют:
- при выводе поста с картинкой изображение передаётся в словаре
context
- на главную страницу,
- на страницу профайла,
- на страницу группы,
- на отдельную страницу поста;
- при отправке поста с картинкой через форму PostForm создаётся запись в базе данных;
3. Создана система комментариев
Написана система комментирования записей. На странице поста под текстом записи выводится форма для отправки комментария, а ниже — список комментариев. Комментировать могут только авторизованные пользователи. Работоспособность модуля протестирована.
4. Кеширование главной страницы
Список постов на главной странице сайта хранится в кэше и обновляется раз в 20 секунд.
5. Тестирование кэша
Написан тест для проверки кеширования главной страницы. Логика теста: при удалении записи из базы, она остаётся в response.content
главной страницы до тех пор, пока кэш не будет очищен принудительно.
Финальное задание спринта
Осталось добавить в проект систему подписки на авторов и создать ленту их постов.Задача вам знакома: создайте модель, напишите view-функцию, добавьте в urls.py новые пути, подготовьте шаблоны.
Модель Follow должна иметь такие поля:
- user — ссылка на объект пользователя, который подписывается. Укажите имя связи:
related_name='follower'
- author — ссылка на объект пользователя, на которого подписываются, имя связи пусть будет
related_name='following'
Напишите view-функцию страницы, куда будут выведены посты авторов, на которых подписан текущий пользователь.Ещё две view-функции нужны для подписки на интересного автора и для того, чтобы отписаться от надоевшего графомана:
# posts/views.py
@login_required
def follow_index(request):
# информация о текущем пользователе доступна в переменной request.user
# ...
context = {}
return render(request, 'posts/follow.html', context)
@login_required
def profile_follow(request, username):
# Подписаться на автора
...
@login_required
def profile_unfollow(request, username):
# Дизлайк, отписка
...
Добавьте необходимые адреса в posts/urls.py:
# posts/urls.py
urlpatterns = [
# ...
path('follow/', views.follow_index, name='follow_index'),
path(
'profile/<str:username>/follow/',
views.profile_follow,
name='profile_follow'
),
path(
'profile/<str:username>/unfollow/',
views.profile_unfollow,
name="profile_unfollow"
),
]
Теперь шаблоны.
Создайте шаблон posts/follow.html, куда будут выводиться посты авторов, на которых подписан текущий пользователь. За образец можно взять шаблон posts/index.html, только замените заголовок.
Добавьте в шаблоны index.html и follow.html виджет переключения лент switcher.html:
<!-- templates/posts/includes/switcher.html -->
{% if user.is_authenticated %}
<div class="row my-3">
<ul class="nav nav-tabs">
<li class="nav-item">
<a
class="nav-link {% if index %}active{% endif %}"
href="{% url 'posts:index' %}"
>
Все авторы
</a>
</li>
<li class="nav-item">
<a
class="nav-link {% if follow %}active{% endif %}"
href="{% url 'posts:follow_index' %}"
>
Избранные авторы
</a>
</li>
</ul>
</div>
{% endif %}
Шаблон index.html:
<!-- templates/posts/index.html -->
{% extends 'base.html' %}
{% block title %}Последние обновления на сайте{% endblock %}
{% block content %}
{% include 'posts/includes/switcher.html' %}
{% for post in page_obj %}
{% if post.group %}
<a href="{% url 'posts:group_list' post.group.slug %}">
все записи группы
</a>
{% endif %}
{% if not forloop.last %}<hr>{% endif %}
{% endfor %}
{% include 'posts/includes/paginator.html' %}
{% endblock %}
На странице профайла в шапку профиля добавьте ссылку «Подписаться»:
<!-- templates/posts/profile.html -->
<div class="mb-5">
<h1>Все посты пользователя {{ author.get_full_name }}</h1>
<h3>Всего постов: {{ posts_count }}</h3>
{% if following %}
<a
class="btn btn-lg btn-light"
href="{% url 'posts:profile_unfollow' author.username %}" role="button"
>
Отписаться
</a>
{% else %}
<a
class="btn btn-lg btn-primary"
href="{% url 'posts:profile_follow' author.username %}" role="button"
>
Подписаться
</a>
{% endif %}
</div>
Обратите внимание, добавлен <div class="mb-5">
который сделаем внешний отступ снизу от шапки профиля. В шаблоне используется булева переменная following
. Во view-функцию добавьте проверку: подписан ли текущий пользователь на автора, страницу которого он просматривает; присвойте результат проверки переменной following
и передайте её в в словаре контекста view-функции profile()
.
Тестирование
Напишите тесты, проверяющие работу нового сервиса:
- Авторизованный пользователь может подписываться на других пользователей и удалять их из подписок.
- Новая запись пользователя появляется в ленте тех, кто на него подписан и не появляется в ленте тех, кто не подписан.