🐍🚀 Django с нуля. Часть 3: создание профилей, сжатие изображений, CRUD и пагинация

В заключительной части туториала разберемся с автоматическим созданием профилей и уменьшением аватарок, реализуем CRUD, импортируем контент из json-файла и сделаем пагинацию.

Третий этап разработки

На этом этапе мы займемся профилями пользователей и предоставим авторам возможность добавлять, редактировать и удалять свои записи со стороны фронтенда. Код для всех файлов этой части проекта находится здесь.

Сохранение изображений профилей

На предыдущем этапе мы уже создали модель для профиля и зарегистрировали ее. Теперь нужно обеспечить сохранение аватарок в нужной папке. По умолчанию Джанго создает папку profile_pics (для хранения аватарок) на одном уровне с папками приложений, что не слишком удобно.

Чтобы изменить расположение папки, откройте my_site\settings.py и добавьте в начало файла import os, а в конец вставьте:

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

Запустите сервер, войдите в панель управления – там уже есть раздел Profiles, причем количество профилей равно 0, хотя мы создали нескольких пользователей. Чуть позже мы рассмотрим, как автоматически создавать профили одновременно с регистрацией аккаунтов, а пока что создадим вручную один профиль для админа с аватаркой, и один профиль для пользователя без аватарки – вернее, у него будет аватарка по умолчанию default.jpg, которую вам нужно будет создать и поместить в папку media (но не внутрь profile_pics, а рядом).

Внесите изменения в шаблон профиля users\profile.html:

{% extends "blog/base.html" %}
{% load crispy_forms_tags %}
{% block content %}
	<div class="content-section">
  	<div class="media">
    	<img class="rounded-circle account-img" src="{{ user.profile.image.url }}">
    	<div class="media-body">
      	<h2 class="account-heading">{{ user.username }}</h2>
  	    <p class="text-secondary">{{ user.email }}</p>
    	</div>
  	</div>
  	<!-- Здесь будет форма -->
	</div>
{% endblock content %}

Теперь профиль админа выглядит так:

В профиле админа появилась аватарка

Автоматическое создание профилей

Осталось решить задачу с автоматическим созданием профилей во время регистрации. В Джанго для реализации такой логики существуют сигналы. Создайте файл users\signals.py и сохраните в нем этот код. Эти сигналы нужно импортировать в users\apps.py.

Проверим, как работает автоматическое создание профилей – запустим сервер и создадим новый аккаунт. Все получилось:

Теперь профили пользователей создаются автоматически
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста»

Заполнение и обновление профилей

Пользователям нужна возможность самостоятельно вносить изменения в профиль – менять фото, ник и емейл, например. Для этого внесем дополнения в файл users\forms.py – добавим импорт from .models import Profile в начало и этот код в конец:

class UserUpdateForm(forms.ModelForm):
	email = forms.EmailField()
 
	class Meta:
    	model = User
    	fields = ['username', 'email']
 
 
class ProfileUpdateForm(forms.ModelForm):
	class Meta:
    	model = Profile
    	fields = ['image']

Перейдем к users\views.py – теперь он должен выглядеть так. В шаблон profile.html тоже нужно внести дополнения – вставьте этот код вместо комментария "здесь будет форма":

   	<form method="POST" enctype="multipart/form-data">
      	{% csrf_token %}
      	<fieldset class="form-group">
          	<legend class="border-bottom mb-4">Ваш профиль</legend>
          	{{ u_form|crispy }}
              {{ p_form|crispy }}
      	</fieldset>
      	<div class="form-group">
          	<button class="btn btn-outline-info" type="submit">Обновить</button>
      	</div>
  	</form>

Теперь пользователи могут изменять информацию в своих профилях:

Пользователи могут самостоятельно изменить ник, емейл и аватар

Автоматическое сжатие изображений

Если пользователи будут загружать слишком большие изображения, сервер скоро окажется перегруженным. Поэтому имеет смысл реализовать автоматическое сжатие изображений, используемых в качестве аватарок. Такую возможность предоставляет библиотека Pillow, которую мы уже использовали. Для сжатия фото с помощью Pillow в users\models.py нужно сохранить этот код. Теперь крупные изображения уменьшаются автоматически.

Отображение аватарок в постах

Пока что изображения пользователей видны только в их профилях. Чтобы фото авторов отображались в постах блога, внесем дополнения в шаблон blog\home.htmlсохраните в нем этот код. Аватарка пользователя теперь показывается в посте:

Аватарка автора отображается рядом с его записями

CRUD

Чтобы дать возможность пользователям управлять постами, нужно реализовать CRUD – набор операций по созданию, редактированию и удалению контента. Создать такую функциональность будет проще, если перейти от функций представления к классам. Для этого нынешнее содержимое файла blog\views.py нужно изменить на это, а код blog\urls.py должен выглядеть так. Обратите внимание на классы PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView) и PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView) – они обеспечивают создание, редактирование и удаление записей только зарегистрированными пользователями; при этом редактировать и удалять посты могут лишь их авторы.

Для просмотра отдельных постов создадим шаблон post_detail.html вот с таким кодом. Теперь каждый пост можно открыть отдельно: http://localhost:8000/post/1/. Добавим эту возможность в шаблон home.html:

<h2><a class="article-title" href="{% url 'post-detail' post.id %}">{{ post.title }}</a></h2>

Перейдем к шаблону создания новых постов. Создайте файл post_form.html с таким кодом. Форма будет отображаться по адресу http://localhost:8000/post/new/:

Пользователи могут создавать новые записи

После создания записи следует перенаправить пользователя на отдельную страницу поста. Для этого измените существующий код blog\models.py на этот, и все заработает:

Отдельная страница для каждой записи

Записи уже можно обновлять, но пока что нельзя удалять. Создадим нужный шаблон – файл blog\post_confirm_delete.html. Код для него есть здесь. Теперь удаление работает, после подтверждения удаления запись исчезает, а пользователь перенаправляется на главную страницу блога:

Подтверждение удаления

Осталось добавить ссылку на создание новой записи на панель навигации – мы сделаем это в шаблоне base.html, добавив всего одну строку <a class="nav-item nav-link" href="{% url 'post-create' %}">Новая запись</a>. Все готово! Если что-то не работает, сверьтесь с готовым кодом к третьему этапу.

Четвертый этап разработки

На заключительном этапе работы над проектом мы загрузим контент из json файла (с помощью интерактивной консоли Django), сделаем пагинацию и обеспечим вывод всех постов автора на отдельной странице.

Импорт контента из файла json

Создавать посты от имени нескольких авторов утомительно, поэтому мы воспользуемся загрузкой контента из готового файла posts.json. Запустим интерактивную консоль Джанго python manage.py shell и проведем импорт. Отступы в консоли – 2 вместо обычных 4:

>>> import json
>>> from blog.models import Post
>>> with open('posts.json', encoding="utf8") as f:
...   posts_json = json.load(f)
...
>>> for post in posts_json:
...   post = Post(title=post['title']), content=post['content'], author_id=post['user_id']
...   post.save()
...
>>> exit()

Теперь на нашей главной странице отображается множество записей.

Пагинация

Пора реализовать пагинацию – разбиение постов на страницы. Для разделения постов на страницы внесем изменения в класс PostListView(ListView) в файле blog\views.py – добавим строку paginate_by = 5. Отредактируем шаблон home.html – разместим логику пагинатора между {% end for %} и {% end block content%} в конце файла. Записи теперь разделены на страницы:

Пагинатор разделяет записи по 5 постов на странице

Еще было бы здорово показывать на странице пользователя все записи, которые он создал – с пагинацией, если записей много. Для этого мы добавим в blog\views.py импорт get_object_or_404 и новый класс:

class UserPostListView(ListView):
	model = Post
	template_name = 'blog/user_posts.html'  # <app>/<model>_<viewtype>.html
	context_object_name = 'posts'
	paginate_by = 5
 
	def get_queryset(self):
    	user = get_object_or_404(User, username=self.kwargs.get('username'))
    	return Post.objects.filter(author=user).order_by('-date_posted')

Сделаем шаблон user_posts.html и добавим новый путь в файле blog\urls.py:

path('user/<str:username>', UserPostListView.as_view(), name='user-posts').

Осталось внести поправку в данные автора в шаблон home.html:

<a class="mr-2" href="{% url 'user-posts' post.author.username %}">{{ post.author }}</a>

и в post_detail.html:

<a class="mr-2" href="{% url 'user-posts' object.author.username %}">{{ object.author }}</a>.

И все заработало:

Записи пользователя выводятся на его личной странице

Весь код для четвертого этапа можно взять здесь.

Заключение

Поэтапное создание простого веб-приложения дает возможность быстро освоить основные принципы разработки в Django. Фреймворк позволяет достаточно просто реализовать сложную функциональность – например, CRUD, а соответствующие библиотеки помогают разрабатывать формы и автоматически сжимать изображения. Напоминаем, что код для всех этапов проекта доступен здесь.

***

Материалы по теме


ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

admin
11 декабря 2018

ООП на Python: концепции, принципы и примеры реализации

Программирование на Python допускает различные методологии, но в его основе...
admin
28 июня 2018

3 самых важных сферы применения Python: возможности языка

Существует множество областей применения Python, но в некоторых он особенно...
admin
13 февраля 2017

Программирование на Python: от новичка до профессионала

Пошаговая инструкция для всех, кто хочет изучить программирование на Python...