Django template slow to render: кэширование помогает последующим загрузкам, но можно ли помочь первой?
У меня есть приложение django, размещенное на heroku, и у меня есть страница "семейный альбом", которая загружает кучу миниатюр изображений, которые ссылаются на большую страницу с подробными изображениями. (Причем набор изображений может быть разным для каждого пользователя).
Каждая из этих миниатюр использует шаблон image_link.html. Максимум на странице семейного альбома может быть до ~1100 таких миниатюр, и они отлично загружаются в продакшене.
Проблема: я хотел добавить возможность небольшого наведения курсора, чтобы при наведении курсора на миниатюру можно было увидеть наложение того, кто изображен на картинке. (Это возвращается функцией класса Image). Я начал с кода наложения изображения из w3schools здесь , и обновил его, чтобы показать список людей на каждой фотографии (вместо статичного текста).
Это работает отлично, но локально загрузка страницы занимает около 4-5 секунд, а когда я развертываю ее на продакшене (на heroku), это занимает вечность: в среднем ~22 секунды, иногда превышая 30-секундный таймаут. (Я использую один Hobby Dyno).
Так что я сделал несколько вещей:
- кэшировал код в views.py, который захватывает все изображения, которые будут отображаться (незначительная помощь, я думаю, что медлительность происходит во время рендеринга шаблона)
- затем я добавил кэширование фрагментов шаблона на странице семейного альбома
Это делает последующие загрузки быстрыми, но первая - просто убийца. Я относительно новичок в кэшировании в django- есть ли другие вещи, которые я могу сделать, чтобы ускорить это? Например, могу ли я как-то отрисовать шаблон в фоновом режиме до того, как пользователь запросит его?
Вот код: image_index.html (он же "семейный альбом"):
{% extends 'familytree/base.html' %}
{% block title %} - family album{% endblock title %}
{% block content %}
{% load cache %}
{% cache 1800 sidebar user %}
<h1>Family Album</h1>
{% if image_list %}
{% for image in image_list %}
{% include "familytree/image_link.html" with image=image height=150 show_hover=True %}
{% endfor %}
{% else %}
<p>No images are available.</p>
{% endif %}
{% endcache %}
{% endblock content %}
image_link.html (новый бит - это наложение span в блоке 'if show_hover'):
<div style="display: inline-block; margin-bottom:10px"; class="image_container">
<a href="{% url 'image_detail' image.id %}">
{% if image.little_name %}
<img src="{{ media_server }}/image/upload/h_{{ height }},r_20/{{ image.little_name }}" class="image"/>
{% else %}
<img src="{{ media_server }}/image/upload/h_{{ height }},r_20/{{ image.big_name }}" class="image"/>
{% endif %}
{% if show_hover %}
<span class="overlay">
<span class="text">Pictured: {{image.pictured_list}}</span>
</span>
{% endif %}
<div style="padding-left: 8px">
{% if image.year %}
({{ image.year }})
{% endif %}
</div>
</a>
</div>
И заранее я вызываю эту функцию в views.py, когда пользователь только приходит, так что я могу просто передать ее в image_index, когда он туда зайдет:
def get_image_index_stuff(accessible_branches, profile):
image_list = Image.objects.none()
for branch in accessible_branches:
name = branch.display_name
image_list = image_list.union(Image.objects.filter(branches__display_name__contains=name).order_by('year'))
sorted_list = image_list.order_by('year')
image_cache_name = 'images_' + str(profile.user)
cache.set(image_cache_name, sorted_list, 60 * 30) # save this for 30 minutes
return sorted_list
Вот стили для наложения и изображения:
/*Stuff for image gallery hover text:*/
.image_container {
position: relative;
}
.image {
display: block;
width: 100%;
height: auto;
}
.overlay {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
height: 100%;
width: 100%;
opacity: 0;
transition: .5s ease;
background-color: var(--link-color);
border-radius: 20px;
}
.image_container:hover .overlay {
opacity: 1;
}
.text {
color: white;
font-size: 12px;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
text-align: center;
}
Некоторые предложения:
- Делегируйте создание кэша на обработчик фонового процесса, например
celery
.
- Если вы хотите отобразить длинную страницу, попробуйте сделать бесконечную прокрутку страниц, подобную facebook, чтобы создать иллюзию, что у вас есть длинная страница, но при этом страницы отображаются в фоновом режиме.