Django — это огромная экосистема из всевозможных модулей, расширяющих возможности базового фреймворка. На сайте PyPI.org размещены десятки тысяч расширений, в названии которых есть слово django, а неопубликованных модулей или тех, что названы как-то иначе — ещё больше.
Пустим в дело богатства экосистемы: подключим к проекту Yatube управление изображениями.
Приложение для работы с картинками: sorl-thumbnail
В стандартную установку Django встроен инструмент для работы с картинками, но задачи вроде изменения размера изображений ему не по силам. Django умеет только загружать файлы и отдавать их как есть.
Для настоящей соцсети этого мало. Пользователи могут залить RAW-картинку размером 5950×3968 пикселей и весом в 50 Мб, или выложить картинку-мем размером в 120х80. Если опубликовать эти картинки в исходном виде — сайт будет выглядеть неопрятно или долго загружаться.
Дадим пользователям возможность иллюстрировать посты и сделаем так, чтобы загруженные изображения выглядели более-менее одинаково.Одно из первых по популярности и удобству приложений для работы с графикой — библиотека sorl-thumbnail. Для его работы нужна графическая библиотека. Для sorl-thumbnail годятся многие библиотеки, мы возьмём Pillow.
Когда Python ещё набирал популярность, в компании Secret Labs AB написали библиотеку PIL (от Python Imaging Library). Это была одна из первых графических библиотек для Python. Она быстро стала стандартом в сообществе. Компания Secret Labs AB перестала существовать, но потребность в обработке изображений никуда не пропала, и Alex Clark сделал форк (ответвление проекта) под новым названием Pillow (англ. «подушка»); буквы pil включены в название в честь старого проекта, а не потому, что Кларк любит поспать. Новая библиотека поддерживает совместимость и со старыми проектами.
Для установки Pillow выполните команду в виртуальном окружении проекта:
(venv) $ pip install pillow
Возможно, вам вам понадобится установить дополнительные библиотеки для вашей операционной системы.
Теперь установите приложение sorl-thumbnail
:
(venv) $ pip install sorl-thumbnail
Добавьте приложение в список INSTALLED_APPS
, в конец списка:
PYTHONINSTALLED_APPS = [
# ...
'sorl.thumbnail',
]
Выполните миграцию, после этого приложение будет готово к работе.
Теперь вам станут доступны специальные теги в шаблонах:
<!-- Загрузка тегов библиотеки в шаблон -->
{% load thumbnail %}
<!-- Пример использования тега для пропорционального уменьшения и обрезки -->
<!-- картинки до размера 100x100px с центрированием -->
{% thumbnail item.image "100x100" crop="center" as im %}
<img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
{% endthumbnail %}
Даже если у вас всё хорошо получается — документация к приложению не будет лишней.
Настройки проекта
Добавим в модель Post новое поле, чтобы к посту можно было добавить заглавную картинку:
PYTHON
class Post(models.Model):
text = models.TextField(
'Текст поста',
help_text='Введите текст поста'
)
pub_date = models.DateTimeField(
'Дата публикации',
auto_now_add=True
)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
verbose_name='Автор'
)
group = models.ForeignKey(
Group,
on_delete=models.SET_NULL,
related_name='posts',
blank=True,
null=True,
verbose_name='Группа',
help_text='Выберите группу'
)
# Поле для картинки (необязательное)
image = models.ImageField(
'Картинка',
upload_to='posts/',
blank=True
)
# Аргумент upload_to указывает директорию,
# в которую будут загружаться пользовательские файлы.
class Meta:
ordering = ('-pub_date',)
verbose_name = 'Пост'
verbose_name_plural = 'Посты'
def __str__(self):
return self.text[:15]
Путь в параметре upload_to
указывается относительно адреса, указанного в settings.py в MEDIA_ROOT
: в нём устанавливают полный путь к директории, куда будут загружаться файлы пользователей: обычно её называют media/.
В этой директории может быть несколько папок: сейчас мы работаем с картинками, но как знать — возможно, завтра мы разрешим пользователям загружать архивы, текстовые файлы или видео. Загружаемые файлы лучше хранить в разных папках, в соответствии с их назначением.
Добавьте следующие строки в файл settings.py:
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.2/howto/static-files/
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Для загрузки картинок установлен параметр upload_to='posts/'
, таким образом картинки, прикреплённые к постам, будут сохраняться в директории media/posts.
Как всегда, после изменения модели сделайте миграции.
Теперь добавьте новое поле в форму, связанную с моделью:
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
# Добавили поле image в форму
fields = ('group', 'text', 'image')
При дефолтных настройках проекта в режиме разработчика Django не будет раздавать картинки, загруженные пользователями: обычно раздачей картинок занимается специальный сервер. Чтобы настроить отображение картинок — в urls.py нужно переопределить поведение Django — указать, что в режиме DEBUG=True
он должен брать картинки из директории, указанной в MEDIA_ROOT
.
Добавьте в файл yatube/urls.py
следующий код:
# Эти строки — в начало файла, после импорта других модулей
from django.conf import settings
from django.conf.urls.static import static
...
# Эти строки — в самый конец файла:
if settings.DEBUG:
urlpatterns += static(
settings.MEDIA_URL, document_root=settings.MEDIA_ROOT
)
Эта колдограмма будет работать, когда ваш сайт в режиме отладки. Он позволяет обращаться к файлам в директории, указанной в MEDIA_ROOT
по имени, через префикс MEDIA_URL
.
Создайте директорию media/ вручную и добавьте её в .gitignore.
Обновление шаблона
Чтобы изображение показывалось на странице сайта, измените шаблон страницы записи. Добавьте вывод картинок в posts/post_detail.html
:
{% load thumbnail %}
...
<article>
<ul>
<li>
Автор: {{ post.author.get_full_name }}
<a href="{% url 'posts:profile' post.author %}">все посты пользователя</a>
</li>
<li>
Дата публикации: {{ post.pub_date|date:"d E Y" }}
</li>
</ul>
{% thumbnail post.image "960x339" crop="center" upscale=True as im %}
<img class="card-img my-2" src="{{ im.url }}">
{% endthumbnail %}
<p>{{ post.text }}</p>
<a href="{% url 'posts:post_detail' post.pk %}">подробная информация</a>
</article>
...
Если в посте нет картинки, то содержимое тега thumbnail
будет проигнорировано; проверку {% if post.image %}...{% endif %}
делать не надо.
Шаблон формы создания и редактирования поста
В HTML-форме создания и редактирования поста появится поле для загрузки изображения. Форма должна понимать, что из неё на сервер будут передаваться файлы. Обновите шаблон с формой — в HTML-тег <form>
добавьте атрибут enctype
:
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
...
{% endfor %}
Обновление view-функции
Осталось подправить view-функцию редактирования записи. Django-формы умеют работать с файлами. Нужно лишь передать дополнительный параметр files=request.FILES or None
, и больше ничего! Вам не надо отдельно сохранять файлы, не надо проверять их тип или беспокоиться, что в директории загрузки окажется файл с таким же именем — Django сам переименует файл при необходимости:
def post_edit(request, post_id):
post = get_object_or_404(Post, pk=post_id)
if post.author != request.user:
return redirect('posts:post_detail', post_id=post_id)
form = PostForm(
request.POST or None,
files=request.FILES or None,
instance=post
)
if form.is_valid():
form.save()
return redirect('posts:post_detail', post_id=post_id)
context = {
'post': post,
'form': form,
'is_edit': True,
}
return render(request, 'posts/create_post.html', context)