Нам нравится язык шаблонов Django. Он прост, имеет множество готовых функций, таких как i18n, а также встроенные теги и фильтры шаблонов. Тем не менее, использование HTML / CSS / JS только ограничивает ваши возможности по созданию модного и реактивного приложения, особенно если ваш проект поддерживается API.

  • Планируете ли вы создать красивое одностраничное приложение, но у вас жесткие сроки для первого прототипа?
  • У вас вообще есть сомнения по поводу создания одностраничного приложения?
  • Вы ориентируетесь на быстрые результаты и функциональность?
  • Вы просто хотите обогатить свое приложение Django?

Тогда у меня есть кое-что для вас.

tl; dr: Используйте виджеты Vue.js, чтобы улучшить свои шаблоны Django. Пример:

<image-list></image-list>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
  Vue.component('image-list', {
    data: function () {
      return {
        images: [],
      }
    },
    template: `
      <div>
        <h1>{% trans "Images" %}</h1>
        <ul v-cloak v-if="images.length">
          <li v-for="image in images">
            <img :src="image.src" :alt="image.alt" />
          </li>
        </ul>
      </div>
    `,
    beforeMount: function () {
      // Get images
      let el = this;
      axios('{% url "api-user-images" %}')
        .then(function(res) {
          el.images = res.data;
        });
    }
  });  
</script>

Хотя могут быть причины, по которым вы не хотите сразу начинать работу с одностраничным приложением («SPA). Особенно, если речь идет о быстром прототипировании. Создание SPA может потребовать больших усилий, особенно в отношении процессов развертывания, и вы можете пойти в неправильном направлении. В отличие от этого, Django позволяет создать надежный прототип, который по умолчанию имеет множество основных функций:

Если вы планируете использовать API, используйте django-rest-framework (REST) ​​или graphene (GraphQL), которые очень легко реализовать.

Подсказка: вы можете повторно использовать свои формы Django при использовании графена :)

Как вы знаете, добавление упомянутых выше функций с использованием интерфейсных фреймворков занимает некоторое время. Настройка прототипа Django с базовыми функциями занимает гораздо меньше времени и является очень гибкой. Django и его функции настолько хорошо организованы, что вашему прототипу обычно не требуется много кода.

Время - деньги, и быстрое создание прототипа приносит удовлетворение

Чтобы продемонстрировать эффективность Django, давайте спланируем задачи для небольшого приложения, которое позволяет загружать изображения, назначает их пользователю и показывает их в профиле пользователя.

  • Сначала настройте проект Django (django-admin startproject mysite)
  • Определите модель Django, которая хранит изображение и соединение пользователя
  • Включите аутентификацию, включите urls аутентификации и
  • Напишите CreateView, который отображает форму загрузки
  • Добавить шаблон для формы загрузки
  • Добавьте DetailView, который показывает отдельных пользователей

Вот и все. Не займет и часа. Красота в этом - гибкость. Если вам нужно больше полей, просто добавьте их в модель, и они автоматически появятся в форме (и будут автоматически проверены). Если вам нужны представления для удаления или обновления изображений, вы также можете добавить их с минимальными усилиями, используя представления на основе классов.

Я нашел это очень полезным во времена раннего прототипирования, когда требования и мнения часто меняются.

Прототип должен волновать

Создание прототипа с помощью Django эффективно, но результаты очень простые. Ваши клиенты / друзья / коллеги измеряют ваш прототип с помощью современных приложений. Итак, нам нужно добавить немного магии. Магия JavaScript. Мы не любим перенаправления, нам нужны вызовы AJAX. Мы хотим сохранить состояние текущих компонентов и упростить их переупорядочивание / изменение / добавление / удаление. Эти навороты покрываются несколькими JS-фреймворками.

Теперь мы по-прежнему хотим использовать причудливые встроенные функции Django, такие как аутентификация и перевод. Так почему бы не объединить традиционные сверхспособности Django с современным внешним видом JS?

Что это обозначает? Это означает использование представлений, форм и шаблонов Django и их дополнения виджетами JavaScript. Под виджетами я подразумеваю отдельные компоненты, которые можно вставлять в шаблоны html.

В Bitlab Studio мы обычно предпочитаем React. React мощный, но тяжелый. Настроить SPA легко, но нельзя просто вставить React в шаблоны Django. С Vue.js это возможно. Без какой-либо настройки.

Если вы хотите создать SPA после того, как ваш прототип был рассмотрен и одобрен, легко переместить уже созданные виджеты в новый SPA. Так что на самом деле вы не теряете время зря.

Итак, теперь я покажу вам, как создавать виджеты Vue.js и обогащать их всеми прекрасными функциями Django и наоборот.

Примеры синергии

Давайте создадим панель инструментов, на которой будут отображаться изображения текущего пользователя.

from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.generic.views import DetailView

@method_decorator(login_required, name='dispatch')
class UserImagesView(DetailView):
    model = User
    def get_object(self, *args, **kwargs):
        return self.request.user

Используя декоратор аутентификации, вам больше не придется беспокоиться обо всем рабочем процессе аутентификации.

Добавьте представление к своим URL-адресам.

from django.conf import settings
from django.contrib import admin
from django.contrib.auth.views import LoginView, LogoutView
from django.conf.urls.static import static
from django.urls import path

from . import views

urlpatterns = [
    path('login/', LoginView.as_view(), name='login'),
    path('logout/', LogoutView.as_view(), name='logout'),
    path('admin/', admin.site.urls),
    path('', views.DashboardView.as_view(), name='dashboard'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Теперь создайте базовый шаблон.

{% load i18n %}
<html>
<head>
  <title>{% trans "Dashboard" %}</title>
</head>
<body>
  <h1>{% trans "Dashboard" %}</h1>
</body>
</html>

Конечно, теперь мы могли использовать язык шаблонов Django для отображения изображений. Но поскольку мы хотим делать необычные вещи и манипулировать DOM, мы можем обслуживать контент через Vue.js. После перехода на SPA мы можем скопировать компоненты, которые мы уже создали.

{% load i18n %}
<html>
<head>
  <title>{% trans "Dashboard" %}</title>
</head>
<body>
  <div id="app">
    <image-list></image-list>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app'
    });
    Vue.component('image-list', {
      data: function () {
        return {
          images: [
            {% for image in object.images.all %}
            { src: '{{ image.src }}', alt: '{{ image.alt }}' }{% if not forloop.last %},{% endif %}
            {% endfor %}
          ]
        }
      },
      template: `
        <div>
        <h1>{% trans "Dashboard" %}</h1>
        <ul v-cloak v-if="images.length">
          <li v-for="image in images">
            <img :src="image.src" :alt="image.alt" />
          </li>
        </ul>
      </div>
      `
    });  
  </script>
</body>
</html>

Ты видишь это? Вы можете легко использовать теги шаблонов Django в своем JS-коде.
Вы, конечно, уже можете добавить некоторые вызовы API, что упрощает перенос компонентов Vue.js в SPA.

{% load i18n %}
<html>
<head>
  <title>{% trans "Dashboard" %}</title>
</head>
<body>
  <div id="app">
    <image-list></image-list>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <script>
    const app = new Vue({
      el: '#app'
    });
    Vue.component('image-list', {
      data: function () {
        return {
          images: []
        }
      },
      template: `
        <div>
        <h1>{% trans "Dashboard" %}</h1>
        <ul v-cloak v-if="images.length">
          <li v-for="image in images">
            <img :src="image.src" :alt="image.alt" />
          </li>
        </ul>
      </div>
      `,
      beforeMount: function () {
        // Get images
        let el = this;
        axios('{% url "api-user-images" %}')
          .then(function(res) {
            el.images = res.data;
          });
      }
    });  
  </script>
</body>
</html>

Иногда синтаксис Vue.js и Django противоречит друг другу. В этом случае используйте тег verbatim, чтобы Django игнорировал содержащийся в нем код.

{% verbatim %}
<div v-if="image">{{ image.src }}</div>
{% verbatim %}

Вы также можете использовать настройку разделители. Спасибо Раффаэле за подсказку.

new Vue({
  delimiters: ['${', '}']
})

Для форм вы можете использовать тег csrf_token в Django.

<form id="form" v-on:submit.prevent="submitForm">
  {% csrf_token %}
  ...
</form>
<script>
  function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
  }
  const form = new Vue({
    el: '#form',
    methods: {
      submitForm: function() {
        ...
        axios({
          url: '/',
          method: 'post',
          headers: {'X-CSRFToken': getCookie('csrftoken')},
          data: {what: 'ever'}
        });
        ...
      }
    }
  });  
</script>

Но почему?

У каждого решения есть свои достоинства и недостатки. Причина, по которой мне лично нравится такой подход, - это скорость, гибкость и прагматизм. Мне также нравится удобство, обеспечиваемое фреймворками, поэтому я не хочу пропустить ни один из них. Вместо этого я предпочитаю так или иначе объединять их силы.

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

Ваше здоровье!