Прелоадер или загрузка другой страницы в ожидании ответа api (Django)

Vladimirych

Новичок
Пользователь
Авг 7, 2020
12
1
3
Первый раз загрузка страницы происходит секунд 10 или дольше, потому что сайт вытаскивает данные из api, поэтому я хочу или повесить прелоадер или показывать какую-то заглушку, которая поменяется на реальную страницу после получения всех данных. Проблема в том, что вообще любые данные, в том числе и прелоадер если его пытаться добавить, появляются только после того, как все данные получены.

У меня получилось решить эту проблему с помощью класса во views.py, в котором первая функция была GET и она сразу рендерила страницу с каким-то сообщением, а вторая POST и она вызывалась при нажатии на кнопку. Но я бы не хотел никаких кнопок и дополнительных действий для пользователя. Просто бы вывести какое-то сообщение, что нужно подождать пока сайт получит все данные.

Мой файл view.py сейчас выглядит вот так. Функция get_info в файле getinfo.py делает запрос к api и возвращает словарь с данными.
Код:
def index(request):
    ctx = getinfo.get_info(request)
    return render(request, 'app/index.html', ctx)
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
По сути, мне нужно, чтобы кнопка как бы нажималась сама собой по факту загрузки страницы и вообще была невидимой.
Можно, например, после загрузки страницы (шапки) нажимать кнопку с помощью js.
Или в одной вьюхе загружать заглушку (шапку, прелоадер), в шаблоне как загрузится страница через ajax вызывать другую вьюху, в которой получать данные из api и возвращать результат в виде json`a.
 

stud_55

Модератор
Команда форума
Модератор
Апр 3, 2020
1 522
672
113
Второй вариант видится более правильным, но так вот с нуля в нем разобраться, видимо, не выйдет. И еще почему-то почти не находятся примеры вызова функцией через ajax, буквально два-три примера на весь интернет.
Вот пример (попытался максимально его упростить):
Python:
# urls.py
from django.urls import path

from . import views

urlpatterns = [
    path('start/', views.start, name='start'),
    path('heavy/', views.heavy, name='heavy'),
]
Python:
# views.py
from django.shortcuts import render
from django.http import JsonResponse
import time


def start(request):
    # выводим шаблон с прелоадером
    return render(request, 'start.html', {'message': 'Task Started'})


def heavy(request):
    # для имитации работы с апи
    time.sleep(10)
    # возвращаем json
    return JsonResponse({'task': 'Task Completed'})
HTML:
<!-- start.html в папке с шаблонами -->
{% load static %}
<!DOCTYPE html>
<html>
<head>
    <title>Heavy Task</title>
</head>
<body>
    <h1 id='status'>{{message}}</h1>
    <!-- прелоадер -->
    <img src="{% static 'images/spinner.gif' %}" id='img' />
    <!-- axios для ajax (легче чем jquery и проще чем нативный fetch) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.20.0/axios.min.js" type="text/javascript"></script>
<script type="text/javascript">
    // ждем загрузки страницы
    document.addEventListener('DOMContentLoaded', function(){
      // делаем запрос
      getData()
    });

    function getData() {
      // показываем прелодер
      preloader(true)
      // делаем запрос
      axios.get('http://127.0.0.1:8000/heavy/')
        .then(res => renderData(res))
        .catch(err => console.error(err));
    }

    function renderData(res) {
        // убираем прелодер
        preloader(false)
        // выводим данные в шаблон
        el = document.querySelector('#status')
        el.innerHTML = res.data['task']
    }

    function preloader(flag) {
        img = document.querySelector('#img')
        if (flag){
            img.style.display = 'block'
        }
        else {
            img.style.display = 'none'
        }  

    }
</script>
</body>
</html>
 

Вложения

  • spinner.gif
    spinner.gif
    8,7 КБ · Просмотры: 1

Vladimirych

Новичок
Пользователь
Авг 7, 2020
12
1
3
С кнопкой это реализовано вот так:

Код:
class View(View) :

    def get(self, request):
        return render(request, 'app/index.html')

    def post(self, request):
        request.POST.get('button')
        ctx = getinfo.get_info(request) # Запрашивает данные через api
        return render(request, 'app/index.html', ctx)

То есть сначала загружается только шапка сайта и кнопка "Получить данные". После нажатия кнопки запускается вторая функция, получает данные через api и на сайте открывается ранее скрытая часть страницы.

По сути, мне нужно, чтобы кнопка как бы нажималась сама собой по факту загрузки страницы и вообще была невидимой.
 

Vladimirych

Новичок
Пользователь
Авг 7, 2020
12
1
3
Сработало, сделал первый вариант. Была проблема, что после нажатия кнопки все данные приходят с перезагрузкой страницы и поэтому кнопка нажимается опять и опять. Решил это спрятав ее в {% if not lst %} тут кнопка со скриптом {% endif %}, где lst это один из списков, которые возвращаются при нажатии кнопки.

Код:
<form method="post">
    {% csrf_token %}
    <input type="submit" id="btn1" onclick="clickButton()" style="display:none;" name="butt_1" value="Show Stats">
</form>

<script type="text/javascript">

    // Simulate click function
    function clickButton() {
        document.querySelector('#btn1').click();
    }

    // Timeout
    setTimeout(clickButton, 1000);
</script>

Второй вариант видится более правильным, но так вот с нуля в нем разобраться, видимо, не выйдет. И еще почему-то почти не находятся примеры вызова функцией через ajax, буквально два-три примера на весь интернет.
 

Vladimirych

Новичок
Пользователь
Авг 7, 2020
12
1
3
Спасибо огромное! Пример запустил, буду прикручивать к сайту.
 

Форум IT Специалистов