Введение
Мне часто по жизни доводится работать с проектами, где есть SPA на Vue и какой-то бэк на Django + DRF. Раскидывать их по разных контейнерам в докере и рулить маршрутами на стороне nginx, конечно, круто, но а что если нужно передать какой-то параметр (например, токен) в Vue и мы не можем авторизовать пользователя просто так?Кейс
Есть такая штука, как битрикс (да, я знаю, питону не место там, но всё же он там может быть). У него есть возможность установки внешних приложений из маркетплейса. И работает оно просто - открывается iframe и посылается POST запрос на URI обработчика приложения. В этом запросе битрикс передаёт токены для доступа, id пользователя, домен портала и прочую полезную инфу (место вызова приложения, тариф и прочее). Кстати, в битриксе это называют приложением второго типа (Первый тип без бэка вообще. А третий без фронта xD).Подкручиваем бэк
Для начала стоит создать приложение, которое будет сёрвить фронт (можно и не создавать, но мне кажется, что пилить проект по кускам, когда одно приложение отвечает за пользователей, другое за фронт, третье за посты/товары/корзины и многое другое и так далее). Сделаем с нуля проект django, вкинем туда venv и приступимdjango-admin startproject vue_django_test_app
cd vue_django_test_app
python3 -m venv venv
source venv/bin/activate
pip install django
pip freeze > requirements.txt
python3 ./manage.py startapp app
Вот проект и создан, мы в виртуальном окружении. Побалуемся
Во-первых, нам нужно подредачить settings.py и добавить приложение app в INSTALLED_APPS, прописать STATIC_ROOT и указать путь к шаблонам
INSTALLED_APPS = [
...
'app'
]
...
TEMPLATES = [
{
...
'DIRS': [BASE_DIR / 'templates'],
...
}
]
...
STATIC_ROOT = BASE_DIR / 'static/'
Для любителей Heroku
Если вы хотите дружить и с Heroku, то вам желательно установить и настроить пакет whitenoise
Как это сделать, можно почитать туть:
Using WhiteNoise with Django - WhiteNoise 6.7.0 documentation
whitenoise.evans.io
Теперь займёмся настройкой маршрутизации. По пути vue_django_test_app/urls.py нужно подключить вьюху, которая отправит шаблон (чуть позже напишем). Также на деве будем обслуживать статику через встроенный механизм django
from django.urls import path
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from app.views import FrontendTemplateView
urlpatterns = [
path('', FrontendTemplateView.as_view())
]
urlpatterns += staticfiles_urlpatterns
Пишем представление Django
Как мы помним, нам нужно передать токены и GET параметры на фронт. Для этого нужно написать своё представление. Напишем его в app/views.pyfrom django.shortcuts import render
from django.views import View
import json
class FrontendTemaplteView(View):
def post(self, request):
# Собираем все параметры запроса в контекст
context = {
'post_data': request.body,
'get_data': json.dumps(request.GET) # Сериализуем в JSON
}
# Отправляем клиенту отрендеренный с контекстом шаблон
return render(request, 'index.html', context)
Абсолютно простая вьюшка. Думаю, легко понять, что осталось сделать, чтобы пробросить данные)
Создание и настройка сборки vue приложения
Допустим, какой-то бэк на django у нас уже есть. Заходим в корень проекта и создаём проект vue.js (пусть будет frontend)vue create frontend
Там vue поспрашивает за конфигурацию приложения. Выбирать можно что угодно, но нужно, чтобы конфиг хранился в раздельных .js файлах.
Про vue router
Vue router желательно не использовать в history mode, так как на каждый url фронта, нужно будет докидывать маршрут и в django
Затем нам нужно подредачить vue.config.js, чтобы webpack автоматом клал шаблон и статику в директории django
// Путь к приложению в котором храниться статика django
const static_dir = '../app/static'
// Путь, относительно static_dir
// В него webpack положит шаблон Vue приложения
const template_path = '../../templates/index.html'
module.exports = {
// Paths
// Рабочая директория сборки
// Я обычно указываю директорию приложения django, которое отвеает за фронт
outputDir: process.env.NODE_ENV === 'production' ? static_dir : 'dist/',
// Куда пойдёт шаблон проекта
indexPath: process.env.NODE_ENV === 'production' ? template_path : 'index.html',
// Куда пойдут ассеты (относительно outputDir)
assetsDir: '', // ассеты храним там же, где и JS/CSS
// Путь по которому можно достать статику
// Нужно указать тот, который прописан в STATIC_URL настроек django
publicPath: process.env.NODE_ENV === 'production' ? 'static' : '/',
}
Проверка на NODE_ENV нужна для того, что дев сервер webpack мог нормально отработать при запуске npm/yarn run serve (ну мало ли нужно будет)
Модификация шаблона webpack
Осталось лишь дать понять django куда пихать контекст. И нам в этом поможет файл public/index.html - из него webpack соберёт окончательный html файл и положит его в папку templates. Добавим в этот файл маленький скрипт в котором создадим переменную глобального скоупа и положим туда наши JSON-чики<head>
...
<script>
window.data = {
post: {{post_data | safe}},
get: {{get_data | safe}},
}
</script>
...
</head>
Фильтр safe отключает экранирование символов, чтобы JSON остался валидным.
Финиш
Вот и всё готово! Осталось лишь собрать проект!Из корня проекта:
cd frontend; npm run build; cd ../
python3 ./manage.py collectstatic --noinput
python3 ./manage.py makemigrations; python3 ./manage.py migrate
pip install gunicorn
gunicorn vue_django_test_app.wsgi
Источник статьи: https://habr.com/ru/post/568666/