Если вы попали на эту страницу урока, не читая часть первую, то вам сюда: Создание сайта на Django: Урок 45, система подписчиков, часть 1 (представление, оформление)
Обновленная версия системы подписчиков
Создание кнопок для подписки на пользователя
В шаблоне profile-detail.html добавим сами кнопки, а также подключим JavaScript, создадим сам js файл позже.
templates/modules/system/profiles/profile-detail.html
{% extends 'main.html' %}
{% load static %}
{% block content %}
<div class="card border-0 mb-2">
<div class="card-body">
<div class="row">
<div class="col-md-3">
<figure>
<img src="{{ profile.get_avatar }}" class="img-fluid rounded-0" alt="{{ profile }}">
</figure>
</div>
<div class="col-md-9">
<h5 class="card-title">
{{ profile }}
</h5>
<div class="card-text">
<ul>
<li>Никнейм: {{ profile.user.username }}</li>
<li>Заходил: {{ profile.user.last_login }}</li>
<li>Возраст: {{ profile.get_age }}</li>
<li>О себе: {{ profile.bio }}</li>
</ul>
{% if request.user != profile.user and request.user.is_authenticated %}
{% if request.user.profile in profile.followers.all %}
<button class="btn btn-sm btn-danger btn-following" data-slug="{{ profile.slug }}">
Отписаться от {{ profile }}
</button>
{% else %}
<button class="btn btn-sm btn-primary btn-following" data-slug="{{ profile.slug }}">
Подписаться на {{ profile }}
</button>
{% endif %}
{% endif %}
</div>
</div>
</div>
</div>
</div>
<div class="card border-0">
<div class="card-body">
<div class="row">
<div class="col-md-6">
<h6 class="card-title">
Подписки
</h6>
<div class="card-text">
<div class="row">
{% for following in profile.following.all %}
<div class="col-md-2">
<a href="{{ following.get_absolute_url }}">
<img src="{{ following.get_avatar }}" class="img-fluid rounded-1" alt="{{ following }}"/>
</a>
</div>
{% endfor %}
</div>
</div>
</div>
<div class="col-md-6">
<h6 class="card-title">
Подписчики
</h6>
<div class="card-text">
<div class="row" id="followersBox">
{% for follower in profile.followers.all %}
<div class="col-md-2" id="user-slug-{{ follower.slug }}">
<a href="{{ follower.get_absolute_url }}">
<img src="{{ follower.get_avatar }}" class="img-fluid rounded-1" alt="{{ follower }}"/>
</a>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block script %}
<script src="{% static 'custom/js/profile.js' %}"></script>
{% endblock %}
Пояснение:
- Добавил
{% block script %}<script src="{% static 'custom/js/profile.js' %}"></script>{% endblock %}
- Добавил
{% load static %}
для подгрузки скрипта. - Добавил следующий фрагмент кода:
{% if request.user != profile.user and request.user.is_authenticated %}
{% if request.user.profile in profile.followers.all %}
<button class="btn btn-sm btn-danger btn-following" data-slug="{{ profile.slug }}">
Отписаться от {{ profile }}
</button>
{% else %}
<button class="btn btn-sm btn-primary btn-following" data-slug="{{ profile.slug }}">
Подписаться на {{ profile }}
</button>
{% endif %}
{% endif %}
- Передаю в data-slug - ссылку пользователя.
- В зависимости от того, на странице своего профиля находится пользователь, или же на странице другого пользователя - кнопки показываются соответствующие, либо отсутствуют.
Теперь создадим в папке custom/js файл profile.js
templates/src/custom/js/profile.js
const subscribeBtn = document.querySelector('.btn-following')
const followerBox = document.querySelector('#followersBox')
subscribeBtn.addEventListener('click', subscribeUser)
function subscribeUser() {
const subscribe = this;
const subscribeProfileSlug = subscribe.getAttribute('data-slug');
fetch(`/s/user/${subscribeProfileSlug}/follow/`, {
method: 'POST',
headers: {
'X-CSRFToken': csrftoken,
"X-Requested-With": "XMLHttpRequest",
},
}).then((response) => response.json()).then((result) => {
if (subscribeBtn.classList.contains('btn-primary')) {
subscribeBtn.classList.remove('btn-primary')
subscribeBtn.classList.add('btn-danger')
} else {
subscribeBtn.classList.remove('btn-danger')
subscribeBtn.classList.add('btn-primary')
}
if (result['error']) {
subscribeBtn.innerText = `${result['error']}`
} else {
if (result['status']) {
followerBox.innerHTML += `
<div class="col-md-2" id="user-slug-${result['following_slug']}">
<a href="${result['following_get_absolute_url']}">
<img src="${result['following_avatar']}" class="img-fluid rounded-1" alt="${result['following_slug']}"/>
</a>
</div>
`
subscribeBtn.innerHTML = `${result['message']}`
}
else {
const currentSlugUser = document.querySelector(`#user-slug-${result['following_slug']}`)
currentSlugUser.remove()
subscribeBtn.innerHTML = `${result['message']}`
}
}
})
}
Пояснение:
subscribeBtn
- находим кнопку подписки по классу.btn-following
followerBox
- находим блок подписчики, для добавления/удаления пользователя без перезагрузки страницы.- Добавляем к
subscribeBtn
событие клика, передаем функциюsubscribeUser()
- Создаем функцию
subscribeUser()
, получаем слаг профиля, а также создаем метод отправки POST запроса с помощью fetch - Преобразуем получаемый json в результат, разворачиваем в условиях, добавляем классы кнопкам, добавляем пользователя к подписчикам.
Примечание: я не очень хорошо разбираюсь в JavaScript, поэтому знатоки, можете его оптимизировать так, как вам нужно. Я ещё с JS много не практиковался.
Тестируем на сайте:
Кликаем по кнопке отписаться

Результат:

Снова нажимаем подписаться:

Отлично. Все работает так, как надо. Вы же можете оформить все это так, как хотите. Принцип знаете.