Дисклеймер!

Статья предназначена для людей, которые достаточно хорошо разбираются в веб разработке на python. Это моя первая статья, поэтому прошу сильно не ругаться :)

Привет, Хабр!

Создавая небольшой сайтик на Django появилась мысль сделать из него web приложение(Опыт в создании веб приложение был, правда только на Flask). И в итоге начались поиски, которые так и не привели к наиболее приятному способы создания PWA приложения на Django, к моему удивлению даже на хабре не нашлось статьи на это тему (. Спустя 3 дня упорных поисков , я совершенно случайно наткнулся на gitlab, где задача была реализована достаточно понятно, и без старонних библиотек. Если вы достаточно хорошо понимаете django и сам принцип создание веб сайтов, данный gitlab можно посмотреть и скачать здесь.

Если хотите разобраться вместе со мной, тогда вперёд!

Установка Django и создание проекта

Ну сперва-наперво нужно установить сам Django.

pip install django

Ну или, если у вас линукс или что-то такое:

sudo pip install django

На всякий случай оставлю ссылку на pip библиотеку здесь.

Теперь пора создавать сам проект

Переходим в папку, где будет размещаться проект, и пишем:

django-admin startproject имя вышего проекта

У меня проект будет называться django-pwa-test

Заходим в папку проекта. Там должны быть: папка с именем вашего проекта, файл manage.py и файл db.sqlite3.

Переходим в папку с именем вашего проекта, и создаем там папки: static(здесь будут храниться некоторые статические файлы) и templates(здесь будут храниться frontend файлы). По желанию так-же стоит создать папку apps, в ней будут храниться приложения(я создам, а вы - как хотите).

Дальше. Переходим в папку apps и создаём приложение(у меня оно будет называться 'Pwa')

django-admin startapp Pwa

Создание манифеста и сервис воркера

И так. Для тех, кто не знает: манифест и сервис воркер - это основные файлы, которые и буду отвечать за работу PWA.

Service worker обеспечивают возможность работы offline, также он — посредник между клиентом и сервером, пропускающий через себя все запросы к серверу.

В манифесте будет храниться информация: о названии приложения, его описание, стартовый url, его иконки и тд.

Для создание манифеста:переходим в папку static и создаём файл manifest.json. В файле пишем:

{
    "name": "Django PWA",
    "short_name": "djangopwa",
    "start_url": "/",
    "scope": ".",
    "display": "standalone",
    "background_color": "#FFF",
    "theme_color": "#493174",
    "description": "Test app for Django and PWA",
    "dir": "ltr",
    "lang": "en-US",
    "orientation": "portrait-primary",
    "icons": [{
        "src": "/static/icons/aurss.96x96.png",
        "type": "image/png",
        "sizes": "96x96"
    }, {
        "src": "/static/icons/aurss.512x512.png",
        "type": "image/png",
        "sizes": "512x512"
    }]
}

Где: name и shortname - имена приложения, starturl - ulr, который будет открываться при запуске PWA приложения, scope - уровни, на которых может работать сервис воркер, icons - путь к иконкам для приложения(мы создадим их немного позже). Подробнее можно почитать здесь.

Создание сервис воркера

Переходим в папку templates и создаём файл sw.js. Пишем в нём:

console.log('Hello from sw.js');

importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.2.0/workbox-sw.js');

if (workbox) {
  console.log(`Yay! Workbox is loaded ?`);

  workbox.precaching.precacheAndRoute([
    {
      "url": "/",
      "revision": "1"
    }
  ]);

  workbox.routing.registerRoute(
    /\.(?:js|css)$/,
    workbox.strategies.staleWhileRevalidate({
      cacheName: 'static-resources',
    }),
  );

  workbox.routing.registerRoute(
    /\.(?:png|gif|jpg|jpeg|svg)$/,
    workbox.strategies.cacheFirst({
      cacheName: 'images',
      plugins: [
        new workbox.expiration.Plugin({
          maxEntries: 60,
          maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
        }),
      ],
    }),
  );

  workbox.routing.registerRoute(
    new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
    workbox.strategies.cacheFirst({
      cacheName: 'googleapis',
      plugins: [
        new workbox.expiration.Plugin({
          maxEntries: 30,
        }),
      ],
    }),
  );
} else {
  console.log(`Boo! Workbox didn't load ?`);
}

Если хотите больше узнать о том, как работает сервис воркер, то смотрите здесь.

Подключение PWA к html файлу

Переходим в папку templates и создаем html файл с любым именем (у меня будет home.html). В html файле прописываем:

<!DOCTYPE html>
<html>
<head>
	{% load static %}

	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="manifest" href="{% static 'manifest.json' %}">

	<title>hello world</title>
</head>
<body>

	 <script>
       if ('serviceWorker' in navigator) {
           navigator.serviceWorker.register('{% url "sw.js" %}', { scope: '/' }).then(function(reg) {
               // registration worked
               console.log('Registration succeeded. Scope is ' + reg.scope);
           }).catch(function(error) {
               // registration failed
               console.log('Registration failed with ' + error);
           });
       }
   </script>
	
</body>
</html>

Пробежимся по основному

  • {% load static %} дает нам доступ к папке static

  • Через тег link в 8 строке мы подключаем файл манифеста.

  • С помощью небольшого js скрипта, мы подключаем сервис воркер.

Иконки для манифеста

Если вспомнить код манифеста, а точнее часть с параметрами иконок:

"icons": [{
        "src": "/static/icons/aurss.96x96.png",
        "type": "image/png",
        "sizes": "96x96"
    }, {
        "src": "/static/icons/aurss.512x512.png",
        "type": "image/png",
        "sizes": "512x512"
    }]

Можно заметить, что иконки берутся из /static/icons, поэтому мы переходим в папку static и создаём там папку с именем icons. В этой папке будут храниться иконки разного размера, для вашего приложения. В данном случае, в папку icons нужно сохранить изображения с размерами: 96x96 512x512. С именем, которое указано в манифесте(При желании его можно изменить)

На этом создание дополнительных файлов подходит к концу)

И так, если вы всё сделали правильно, то ваш проект будет выглядеть как-то так :

django-pwa-test
	manage.py
  db.sqlite3
	django-pwa-test
  	apps
    	Pwa
      	python файлы
		static
    	manifest.json
      icons
      	ваши иконки для приложения
    templates
    	home.html
      sw.js
      	

Настройка параметров в settings.py

Теперь пора немного изменить настройки приложения)

Переходим в основную папку проекта, находим settings.py и дополняем.

Для начала нужно импортировать модуль os:

import os

Теперь ищем переменную TEMPLATES, в ней ищем массив с именем DIRS, и добавляем в него:

os.path.join(BASE_DIR, 'имя вашего приложения/templates')

Должно получиться что-то такое:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            os.path.join(BASE_DIR, 'имя вашего приложения/templates'),

        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Далее ищем переменную BASE_DIR(она будет в самом начале), и после неё пишем:

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'имя вышего приложения/static/'),
]

STATIC_ROOT = BASE_DIR / 'static'

На этом изменения в настройках закончены.

Рендер страницы и доступ к sw.js

Для того, чтобы наша страница могла получить доступ к файлу sw.js на нужно написать класс, который будет в этом участвовать.

Идём в папку с приложением(именно приложением, не проектом. Если не забыли, у меня приложение называется Pwa) и записываем в файл views.py:

from django.shortcuts import render
from django.views.generic import TemplateView


# Create your views here.


def home(request):
	return render(request, 'home.html')


class ServiceWorkerView(TemplateView):
    template_name = 'sw.js'
    content_type = 'application/javascript'
    name = 'sw.js'

Быстрый разбор:

  • Если вы хотя бы немного знаете Django, то функция home должна быть вам понятна(Если вы не знаете, как она работает, то советую сначала поучить Django, и потом уже приходить сюда. Без обид)

  • через urls.py методом .as_view() мы получим доступ к классу ServiceWorkerView (а также и его значениям), и достанем из него значение переменно name(она будет использована для получения доступа к файлу).

Добавление адресов в urls.py

Здесь мы пропишем адреса для отображения основной страницы и sw.js

Идем в основную папку проекта, открываем файл urls.py и пишем.

Для начала из созданного приложения (У меня это Pwa) нужно импортировать файл

В случае, если вы, как и я сохранили приложение в папке apps:

from .apps.Pwa import views

Если же вы самостоятельная личность, и сохранили без папки apps, то:

from .Pwa import views

Напоминаю: я импортирую из папки Pwa потому, что так называется моё приложение(у вас оно может быть другим, но тогда вам надо проверить все файлы и сменить их путь на свой)!!!

Теперь в массив urlpatterns нужно добавить следующие значения: path("", views.home), path('sw.js',views.ServiceWorkerView.as_view(), name=views.ServiceWorkerView.name,)

Теперь ваш urls.py должен выглядеть как-то так:

from django.contrib import admin
from django.urls import path
from .apps.Pwa import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path("", views.home),
    path('sw.js',
        views.ServiceWorkerView.as_view(),
        name=views.ServiceWorkerView.name,
    ),
]

Разбор:

  • path('', views.home) прорисует основную страницу вызвав функцию home() из файла view.py в нашем приложении

  • path('sw.js',views.ServiceWorkerView.as_view(),name=views.ServiceWorkerView.name) позволяет получить доступ к файлу sw.js

На этом пока всё. Если хотите протестировать, то переходите в папку с файлом manage.py, и выполняйте команду python3 manage.py runserver

Открывайте браузер по указанной ссылке(она в терминале), и если ваш браузер поддерживает pwa, то на панели поиска(справа, вверху) появится предложение установить приложение. Если у вас FireFox, то скорее всего не появится.

Ели вы в поддерживающем pwa браузере, но предложение установить приложение, или иконка установки так и не появились, то нажимайте F12, и посмотрите в консоли ошибки, если ошибок нет, то нажимайте F12 переходите на вкладку 'Приложения', и проверьте манифест и сервис воркер. Если ничего не помогло, тогда гугл в помощь!

P.S. Открыт для критики, буду рад, если укажите на ошибки и недочёты :)