Размер
Мобильная версия для Django-проекта
Play

Мобильная версия для Django-проекта

С каждым днем пользователи смартфонов занимают все большую долю интернета. По данным LiveInternet доля российских пользователей OS Android уже превысила долю Windows7. В выходные дни пользователи мобильных платформ пользуются интернетом значительно чаще. Та же тенденция наблюдается и в мире. Все это еще раз доказывает необходимость адаптации сайта для смартфонов и планшетов.

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

1. Варианты мобильной версии сайта

1.1 Адаптивная верстка

В этом случае мы отдаем одинаковое количество данных для большой и мобильной версии сайта. Этот подход самый простой для backend разработки, все решается версткой.

  • не требует редиректов;
  • не нужно отдельно сообщать поисковым роботам о наличии мобильной версии (мета теги alternate, сайтмапы и прочее).
  • поскольку на мобильной версии приходится отдавать все и скрывать лишнее, создается лишний трафик и нагрузка на сервер;
  • версия для мобильных устройств всегда должна создаваться с большой версией сайта;
  • так как данные на обоих версиях одинаковы, может быть сложно удобно организовать обе версии, скорее всего мобильной версией придется пожертвовать; к примеру, я не представляю, как можно сделать удобный форум при таком подходе.
1.2 Мобильная версия на поддомене

По сути, это два отдельных сайта. Такой подход решает проблемы лишнего трафика, дает больше гибкости и возможностей в разработке версии для мобильных устройств. Однако при этом вопрос, какую версию показывать пользователю, решается сервером, а не браузером. Также нужно дать возможность пользователю выбрать, какая версия сайта ему нужна, и «подружить» обе версии сайта редиректами и альтернейтами.

Разные URL одной страницы приводят к недостатку этого способа: относительные ссылки в материалах сайта могут вести на страницы, отсутствующие в мобильной версии. Поэтому приходится указывать абсолютные ссылки на основной домен и потом редиректить пользователя на нужную версию. Решением этого недостатка будет полностью соответствующие большая и мобильная версии, но в этом случае правильнее идти третьим способом.

1.3 Мобильная версия на том же домене

Это доработка первого подхода и решение его минуса с трафиком и лишней нагрузкой. Реализуется он так же как с поддоменом: вы определяете, какая версия нужна клиенту, и отдаете нужное количество данных в нужный шаблон. Одинаковый URL для обоих версий сайта — безусловно плюс. Хотя проблема организации контента для обоих версий еще остается, но решать ее уже проще, так как ограничения на одинаковые данные уже нет.

1.4 Наш опыт

В отделе контентных проектов Mail.Ru Group мы используем второй подход, хотя и плавно движемся в сторону третьего. Проекты Дети Mail.Ru и Здоровье Mail.Ru написаны на Django, оба имеют мобильные и/или тач версии. Несмотря на то, что проекты под капотом немного отличаются, механизм создания мобильных версий у них одинаков. Об этом я хочу с вами поделиться.

2. Исходные соглашения

2.1 Все роуты мы именуем

И обращаемся к ним всегда по этому имени.

Мы никогда не собираем URL'ы сами в контроллерах или шаблонах, они указаны только в urls.py. DRY.

2.2 Используем django-hosts

Об этой библиотеке уже упоминали на Хабре. Изначально мы ее использовали на «детях» для форума на поддомене, сейчас форум переехал у нас на основной хост, и эта библиотека используется только для мобильный версий.

Вкратце, как она работает: вы подключаете middleware, которая в зависимости от Host заголовка подменяет схему URL'ов. Помимо джанговской функции reverse , вы можете использовать из этой библиотеки reverse_full , которая строит абсолютный URL. Подобный тег host_url можно использовать в шаблонах. Используемые функции reverse_host , get_host также взяты из этого приложения.

2.3 Отдельные контроллеры для большой и мобильной версии

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

3. Разработка мобильной версии

Мобильная версия должна решать следующие задачи:

  1. Определение версии сайта и редирект для соответствующих устройств.
  2. Возможность пользователя отказаться от мобильной версии и использовать основную.
  3. Редиректы должны перенаправлять на соответствующую мобильную версию и наоборот. Нехорошо кидать пользователя на главную и заставлять искать с начала.
  4. Если пользователь попал на отсутствующую страницу в мобильной версии, для которой есть аналог в большой версии, ему нужно явно сообщать об этом. Этой задачи не было, если бы обе версии соответствовали друг другу.
  5. Необходимо указывать мета теги alternate и canonical, если для страницы доступен мобильный аналог.
3.1 Определение версии сайта

С какого устройства пользователь зашел на наш проект мы определяем с помощью нашего модуля nginx. Выглядит это примерно вот так:

Модуль опредеяет тип версии, которую нужно показать (m или touch), но если у пользователя стоит кука mobile, мы игнорируем это. Результат передается в виде http заголовка на бэкенд.

Дальнейшая обработка запроса происходит в middleware.

  • пришел GET запрос;
  • запрос пришел на основную версию сайта (если пользователь явно набрал адрес мобильной версии — оставим его на ней);
  • проверим, есть ли такая страница в мобильной версии (не редиректить же его на 404).
3.2 Переход на большую версию сайта

На мобильную версию мы отправили пользователя, дадим ему также возможность перейти обратно на большую версию. В подвалах наших проектов содержится ссылка вида /go-health/ , по которой и осуществляется переход.

К сожалению, иногда страницы мобильной версии отличаются от основной. Та информация, которая легко помещается на большой версии, в мобильной разделяется на 3 страницы. Поэтому отбрасывать поддомен и редиректить на тот же URL, было бы неправильно. Мы выбрали следующий алгоритм:

  1. Определяем имя роута той страницы, на которой мы находимся.
  2. Функция контроллера может содержать специальный атрибут go_view_name . В этом случае мы редиректим на страницу с этим (другим) именем роута. Это нужно как раз для того случая, когда несколько страниц одной версии соответствуют одной странице большой версии.
  3. В остальных случаях редиректим на роут большой версии с тем же именем.

Атрибут go_url_name назначается через декоратор

А декоратор never_use_mobile ставит куку mobile для отмены автоматического редиректа

К сожалению, тач версии развиваются после основных разделов и не всегда соответствуют страницам на большой версии, поэтому такой код приходится держать. Атрибут go_view_name просто подменяет имя роута для страницы-аналога. Это довольно ограниченное решение, но его пока хватает.

3.3 404 для мобильной версии

Вы можете не просто сообщать пользователю о том, что страница не найдена, но и указать, что такая страница есть в полной версии сайта. При этом проверить URL по схеме URL'ов недостаточно: запрос /news/foo/ соответствует схеме URL'ов, а новости такой нет. Поэтому надо попытаться выполнить функцию контроллера в основной схеме урлов. Есть еще одна тонкость: надо подменять текущую схему URL'ов для большой версии, так как она нужна функциям reverse и тегу url. Иначе вы будете рендерить страницу большой версии в схеме URL'ов мобильной.

3.4 Мета теги alternate и canonical

Эти URL'ы строятся с помощью функций или шаблонных тегов приложения django-host.

📎📎📎📎📎📎📎📎📎📎