Как стать автором
Обновить

Как подружить django и vue.js

Время на прочтение4 мин
Количество просмотров21K

Введение

Мне часто по жизни доводится работать с проектами, где есть 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
Как это сделать, можно почитать туть:
https://whitenoise.evans.io/en/stable/django.html

Напрямую сервить статику django через staticfiles_urlpatterns() не желательно

Теперь займёмся настройкой маршрутизации. По пути 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.py

from 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
Теги:
Хабы:
Всего голосов 5: ↑3 и ↓2+1
Комментарии7

Публикации

Истории

Работа

Python разработчик
136 вакансий
Data Scientist
60 вакансий

Ближайшие события