Предисловие
Веб-разработчики часто сталкиваются с необходимостью динамически обновлять страницы без полной перезагрузки. С этим хорошо справляется технология ассинхронного обмена данными AJAX, однако я не нашел на просторах интернета простого мануала использования AJAX и решил создать его сам. В этой статье я собираюсь подробно показать взаимодействие фронтенда с AJAX и бекенда с Django, ограничившись минимумом кода. Статья больше рассчитана на новичков и станет отличной базой для дальнейшего развития в теме.
Часть 1. Подготовка проекта
Для демонстрации я создам небольшой Django проект, который имеет всего лишь одно приложение, обрабатывающее сообщение от пользователя. Вы можете скачать проект с GitHub отсюда или создать что-то подобное самостоятельно. Познакомимся с структурой приложения поближе.
Структура приложения
app/ │ │ ├── app/ │ └── #Конфигурация проекта │ ├── modules/ #Здесь хранятся приложения │ └── messages_app/ │ ├── models.py #Хранит модель Message (Имя отправителя, Текст, Время отправки) │ ├── forms.py #Хранит форму модели Message (Имя отправителя, Текст сообщения) │ ├── urls.py #Два адреса, обрабатывают views │ ├── views.py #Может отправить на шаблон отображения сообщений (messages.html) или на шаблон отправки сообщения (send_message.html) │ └── # Другие настройки по умолчанию │ ├── templates/ #Здесь хранится весь фронт │ ├── messages.html # Обрабатывает все сообщения │ ├── send_message.html # Отправка сообщения для сохранение его в модель Message │ └── src/ │ └── js/ │ └── ajax.js/ #Здесь будет хранится код JS, пока файл пуст
Все django-приложения будут храниться в modules, а html-шаблоны в templates в папке проекта, код JS будет хранится в templates/src/js.
Дальше я подробно разберу файлы внутри структуры проекта: приложения и шаблоны. Если вы в состоянии разобраться самостоятельно, то можете смело пропустить этот шаг и перейти ко второй части.
Рассмотрим единственную модель приложения:
#/modules/models.py from django.db import models class Message(models.Model): sender_name = models.CharField(max_length=100) # Имя отправителя message = models.TextField() # Текст сообщения sent_at = models.DateTimeField(auto_now_add=True) # Время отправки
Я уже создал два тестовых сообщения для отображения. Эта модель используется во views.py, для отображения всех элементов и для создания нового элемента:
#/modules/views.py from django.shortcuts import render from .models import Message from .forms import MessageForm # Create your views here. def get_all_mesages(request): messages = Message.objects.all() return render(request, 'messages_app/messages.html', {'messages': messages} ) def send_message(request): if request.method == 'POST': form = MessageForm(request.POST) if form.is_valid(): form.save() # Сохраняем форму в базе данных return render(request, 'messages_app/send_message.html', {'form': form, 'repeat': True}) else: form = MessageForm() return render(request, 'messages_app/send_message.html', {'form': form})
Во views используется форма из forms.py:
#/modules/forms.py from django import forms from .models import Message class MessageForm(forms.ModelForm): class Meta: model = Message fields = ['sender_name', 'message']
HTML-шаблоны
Используемые шаблоны — message.html для отображения всех элементов:
<!-- /templates/message.html --> {% load static %} <div id="messages-container"> {% for message in messages %} <hr> <p>Отправитель: {{ message.sender_name }}</p> <p>Сообщение: {{ message.message }}</p> <p>Отправлено: {{ message.sent_at }}</p> <hr> {% endfor %} </div> <script src="{% static 'messages_app/src/js/ajax.js' %}"></script>
И send_message.html:
<!-- /templates/send_message.html --> {% if repeat %} <div> Вы уже отправляли форму, хотите отправить повторно?</div> {% endif %} <h1>Отправить сообщение</h1> <form method="post"> {% csrf_token %} {{ form.as_p }} <button type="submit">Отправить</button> </form>
По пути templates/src/js/ находится ajax.js, который сейчас пуст. В дальнейшем мы заполним его кодом.
Часть 2. Внедрение AJAX
Внутри AJAX-запроса используется стандартный HTTP-запрос, такой же, как и обычный GET или POST, однако нам, для эффективного использования AJAX, данные нужно завернуть в JSON-формат. Для этого мы будем использовать JsonResponse на бекенде — перейдем во views.py и создадим еще один метод, который будет заворачивать экземпляры модели в JSON.
#/modules/views.py #...Ранее добавленные импорты и методы from django.http import JsonResponse def ajax_messages(request): messages = Message.objects.all() #Получим все сообщения из модели #Обработаем модель messages_data = [] for message in messages: messages_data.append({ 'sender_name': message.sender_name, 'message': message.message, 'sent_at': message.sent_at.strftime('%Y-%m-%d %H:%M:%S'), # Преобразуем дату в строку }) return JsonResponse({'messages': messages_data})
Добавим отображение метода в urls.py
#/modules/urls.py from django.urls import path from . import views urlpatterns = [ path('', views.get_all_mesages, name='get_all_messages'), path('send/', views.send_message, name='send_message'), #ajax path('get_data/', views.ajax_messages, name='get_data') ]
Попробуем перейти по ссылке https:localhost/get_data/. Нас ждет такой результат:
Теперь мы можем получать по этому адресу данные из модели в JSON-форматe. Далее создадим AJAX-запрос — для этого на странице отображения напишем следующий JS код и поместим его в ajax.js
// templates/src/js/ajax.js let get_data_url = 'get_data/' // Переход на ссылку с ajax запросом function draw_messages(messages) { // То что мы будем делать с нашими данными console.log(messages) // Сейчас мы просто хотим вывести их в консоль } function ajax_get(){ return fetch(get_data_url, { method: 'GET', }).then(response => response.json()) // Преобразуем полученный ответ в JSON .then(data => draw_messages(data)) // Обрабатываем данные, полученные в ответе с помощью функции draw_message [3 строка] .catch(error => console.error('Ошибка:', error)); // Если возникли ошибки, выводим их в консоль }
Мы создали асинхронный GET-запрос который обращается к адресу /get_data/. Уже сейчас, если в консоли браузера на странице отображения сообщений мы введем ajax_get() — получим тот самый ответ в json — элементы модели Message.
Нам нужно, чтобы метод обновлял все содержимое блока #messages-container, для этого изменим метод draw_messages внутри ajax.js
// templates/src/js/ajax.js let get_data_url = 'get_data/' // Переход на ссылку с ajax запросом const messagesContainer = document.querySelector('#messages-container'); // Сюда помещаются наши статьи function draw_messages(messages) { // Очистим контейнер перед добавлением новых сообщений messagesContainer.innerHTML = ''; // Для каждого сообщения в массиве messages создаем HTML messages.forEach(message => { const messageElement = document.createElement('div'); // Создаем элементы для отображения данных сообщения const senderName = document.createElement('p'); senderName.textContent = `Отправитель: ${message.sender_name}`; const messageText = document.createElement('p'); messageText.textContent = `Сообщение: ${message.message}`; const sentAt = document.createElement('p'); sentAt.textContent = `Отправлено: ${message.sent_at}`; // Создаем разделитель const hr = document.createElement('hr'); // Добавляем все элементы в messageElement messageElement.appendChild(senderName); messageElement.appendChild(messageText); messageElement.appendChild(sentAt); messageElement.appendChild(hr); // Вставляем messageElement в контейнер messagesContainer.appendChild(messageElement); }); } function ajax_get() { fetch(get_data_url, { method: 'GET', // Используем метод 'GET' }) .then(response => response.json()) // Преобразуем ответ в JSON .then(data => { draw_messages(data.messages); // Передаем полученные сообщения в draw_messages }) .catch(error => console.error('Ошибка:', error)); // Обрабатываем ошибки }
При AJAX-запросе мы полностью очищаем #messages-container и обновляем содержимым из GET-запроса.
Эта простая и местами примитивная реализация поможет понять всю суть процесса, однако сейчас все равно чего-то не хватает — добавим интервал в 1 секунду для ajax_get(), чтобы данные обновлялись автоматически, и нам не пришлось перезагружать страницу. Для этого добавим в конец ajax.js:
// templates/src/js/ajax.js // ...Переменные и методы setInterval(ajax_get, 1000);
Проверить результат можно просто: откройте страницу с отображением сообщений и страницу с отправкой. Заполните форму отправки и вернитесь на страницу с сообщениями, она автоматически обновится.
В этой статье мы рассмотрели простой GET-запрос. Однако такой подход не подойдет, если объем данных в модели будет слишком большим. В таком случае нужно реализовать POST-запрос с сохранением текущих данных на клиенте. Об этом могу написать позже, если статья вам понравиться, и вы захотите продолжения!
ссылка на оригинал статьи https://habr.com/ru/articles/862780/
Добавить комментарий