Skip to content

Th0rn-dev/kiteupru

Repository files navigation

Дипломная работа

Курс: Разработчик на Python 2018 Тема: Миграция сайта kiteup.ru платформы ModX + MySql на платформу Django 2 + PostgreSql. Задание:

  1. Установить и настроить веб фреймворк на Python - Django 2. В качестве БД использовать PostgreSQL стабильной версии, макет сайта сверстать на Bootstrap 4
  2. Осуществить миграцию всех существующих разделов: “Главная”, “Кайт школа”, “ЧаВо”, “Новости”, “Статьи”, “Фото – Видео”, “Контакты”, “Мероприятия”
  3. Разработать личный кабинет пользователя (стена записей, контакты)

Введение.

Внимание, будет много буковок перед основной частью. Сайт kiteup.ru сделал самостоятельно несколько лет тому назад. Сайт делал под проект определенной тематики и целевой аудитории: активные виды парусного спорта – кайтсерфинг, сноукайтинг, лэндкайтинг.

Выбрал и приобретел шаблон с подходящим этому направлению цветом и стилем, и веб фреймворк Mod с готовыми плагинами, на котором реализовал определенный функционал. Дальнейшие доработки: личный кабинет пользователя, расширенный календарь событий, комментарии под постами, подсчет посещений, лайки и прочие ништяки требовали либо привлечения разработчика, либо углубленного изучения PHP.

При этом я штудировал и посещал курсы по программированию на PHP и верстке HTML, но самостоятельно дорабатывать не получалось – все казалось слишком трудным и запутанным. В общем, программирование – мой личный «камень преткновения», хотя в ИТ я не новичок.

И совсем недавно я открыл для себя язык программирования Python. К этому подтолкнул случай: знакомому понадобилось сделать коллектор с датчиков температур. А мой любимый мини ПК Raspberry Pi 3 (RPi3) идеально подходил для реализации «хотелки». На примере домашней метеостанции на RPi 3 написанной на Python мне удалось сделать проект.

Не помню, чем именно понравился мне Python, но позже, посмотрев востребованность разработчиков на нем и растущий активный спрос – принял важное на тот момент решение – стать разработчиком на Python и устроиться на работу. Это желание привело меня в учебный цент otus.ru на курс “Разработчик на Python” – пишу диплом и одновременно воплощаю свои мечты.

Подготовка среды разработки.

На ПК с Windows 10 установил:

  1. Python версии 3.7.1
  2. Python IDE PyCharm

В PyCharm создал новый проект dilpom, настроил виртуальное окружение.

Далее внутри виртуального окружения:

./pip install django=2.1.9 

Скачиваем geckodriver и его поддержку в Python:

./pip install selenium

Создаем новое приложение Django:

./python manage.py startproject kiteup

Создалась структура каталогов:

diplom
├───manage.py
├───kiteup
│        settings.py
│        urls.py
│        wsgi.py
│        __init__.py

Разработка приложения.

Прежде чем приступить к миграции сайта на Django, испробовал несколько подходов, но в качестве основного выбрал методологию Test Driven Development – Разработка через тестирование wiki.

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

Да, TDD медленный и нудный: сначала пишется тест, покрывающий желаемый функционал, затем пишется код, заставляющий пройти тест и, в заключении, производится рефакторинг кода к соответствующему стандарту.

Очень короткими циклами, маленькими, но уверенными шагами движемся к завершению поставленной задачи – объявленной в теме дипломного проекта. И спим спокойно, ведь каждая строка кода обложена тестами (функциональными, интеграционными и модульными) , сам код получается чище и короче.

Создаем в Django первое приложение, в моем случае это News (раздел сайта с новостями):

./python manage.py startapp news

В структуре каталога появилась новая папка News:

diplom
├───manage.py
├───kiteup
│        settings.py
│        urls.py
│        wsgi.py
│        __init__.py
├───news
│        __init__.py
│        admin.py
│        apps.py
│        test.py
│        models.py
│        views.py

И, правильно, прежде чем начать разрабатывать приложение News, пишу тест в test.py:

from selenium import webdriver
browser = webdriver.Firefox()
browser.get(‘http://127.0.0.0:8000’)
assert ‘Новости’ in browser.title

Пробуем выполнить:

./python manage.py test

Что происходит?

Запускается окно реального браузера Firefox, открывается веб страница по адресу: http://127.0.0.0:8000 и проверятся тестовое утверждение, что в заголовке страницы есть слово “Новости”.

И, в консоль получаем кучу ошибок (исключения, отсутствие ответа и т.д.)

Анализируем трейсбэк и понимаем, что не запущен тестовый сервер.

Запускаем его:

./python manage.py runserver 127.0.0.0:8000

В другом окне терминала в рабочей директории diplom далее по тексту весь код будет запускаться из-под этой директории:

./python manage.py test

Снова запустился Firefox, и в окне появилась стартовая страница Django с приветствием, но assertionError сообщил, что нет слова “Новости” в заголовке страницы.

Использую небольшой код: в test.py мы управляем браузером и со стороны пользователя мы видим как функционирует приложение – с этого момента, тесты с использованием Selenium будут называться функциональными тестами (ФТ).

В структуре директории diplom создадим отдельную папку functional_tests и перенесем код теста в файл test_news_creation.py. Не забыв при этом создать файл init.py, что позволяет питону интерпретировать директорию как package.

Получилась такая структура каталогов:

diplom
├───manage.py
├───functional_tests
│        __init__.py
│        test_news_creation.py
├───kiteup
│        settings.py
│        urls.py
│        wsgi.py
│        __init__.py
├───news
│        __init__.py
│        admin.py
│        apps.py
│        test.py
│        models.py
│        views.py

И еще очень важный момент: после отработки теста окно браузера Firefox осталось открытым и assertionError дает не информативный трейсбэк, по которому сложно отследить - где и в каком модуле произошла ошибка.

Значительно расширить ФТ поможет модуль unittest стандартной библиотеки Python. Теперь test_news_creation.py содержит в себе следующий код:

import unittest
from selenium import webdriver
class NewVisitorTest(unittest.TestCase):
	‘’’тест посетителя’’’
	def setUp(self):
		‘’’установка’’’
		self.browser = webdriver.Firefox()
	def teardown(self):
		‘’’демонтаж’’’
		self.browser.quit()
	def test_can_start_news_page(self):
		self.browser.get(‘http://127.0.0.0:8000’)
		self.assertIn(‘Новости’, self.browser.title)
if __name__ == “__main__”:
	unittets.main()

Запускаем ./python functional_tests.test_news_creation.py снова получаем не работающий ФТ.

Т.к. Django проект может иметь много приложений, а ФТ оценивают весь проект таким, как видит его пользователь, настал момент перейти к модульным тестам, которые будут оценивать одно приложение, его внутреннюю структуру (модель, представление и тесты), таким как видит его программист. Модульные тесты помогут написать код чистым и лаконичным.

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

Напишем первый модульный тест для тестирования представления. Открываем news/test.py и размещаем следующий код:

from django.test import TestCase
from django.urls import resolve
from news.views import news_list
class NewsPageTest(TestCase)
	def test_resolve_url_to_news_list_page(self):
		‘’’тест: url news преобразуется в представление news_list’’’
		response = resolve(‘news’)
		self.assertEqual(response.func, news_list)

Запускаем тест:

./python manage.py test
ImportError : невозможно импортировать имя news_list

Почему появилась ошибка? Произошел импорт того, что еще не существует.

Все старания свелись к тому, что уже есть не работающий ФТ и модульный тест. Это главная идиома TDD, которая говорит о том, что пора уже приступить к разработке приложения, т.е. непосредственного написания кода приложения. Во news/views.py создаем:

News_list = None

Снова запускаем модульный тест. Теперь в трейсбэке замелькали исключения django.urls.exceptions.Resolver404:…… На самом деле тест показывает, что требуется отображение url - адреса на обработчик.

Подключаем приложение New в kiteup/urls.py:

"""kiteup URL Configuration"""
from news import  views 
urlpatterns = [
    path('', views.index , name='index'),
]

Еще раз выполняем модульные тесты ./python manage.py test

[….]
TypeError: представление должно быть вызываемым объектом……

Исчезла ошибка 404 и тест пожаловался на то, что представление news_list не является вызываемым объектом. Исправляем код:

from django.shortcuts import render
def news_list():
	pass
Снова запускаем ./python manage.py test и получаем на выходе:

...

Ran 1 test in 0.001 s Ok ...


Модульный тест представления сработал. Но ФТ еще не проходит. Путем подобных маленьких шагов и запуска тестов, 
доработки модели News в News/models.py и подключении приложения в kiteup/settings.py пришел к тому, что ФТ выдал ОК.
Подобным образом были разработаны минимально функциональные приложения Pages (статические страницы), Articles (статьи), 
Events (мероприятия) соответствующие основным разделам сайта kiteup.ru

А также приложение Accounts – регистрация и авторизация пользователей на сайте. Для тестирования каждого нового 
приложения я добавлял соответствующий файл ФТ в папку functional_test и внутри самого приложения удалив test.py создал 
паку test в котором разместил файлы модульных тестов отдельно для views и отдельно для models
 (tests/test_views.py и test/test_models.py). На определенных этапах и  при всех работающих тестах производил 
 рефакторизацию кода, чтобы привести код в лаконичный, компактный и удобочитаемый вид. После рефакторизации убеждался, 
 что все тесты снова проходят.

## Развертывание.

Основная часть дипломного проекта готова, и настало время пройти следующий квест – развертывание на реальном сервере, чтобы предоставить на проверку.
На данном этапе приобрел  VDS по минимальному тарифу, настроил DNS и сервер стал доступен по адресу http://dev.kiteup.ru , установил и настроил окружение: 

1. Centos 7, авторизация ssh по RSA ключу (чтобы не вводить постоянно пароли)
2. Скачал и скомпилировал python3.7.1
3. Настроил Nginx и Gunicorn и PostgresSql

Вся автоматизация развертывания основана на использовании fabric – инструмента выполнения определенных команд. 

Ставим fabric:

./pip install fabric3


Создаем  папку deploy_tools и размещаем код в файле fabfile.py (показан фрагмент кода):

from fabric.contrib.files import append, exists, sed from fabric.api import env, local, run import random

REPO_URL = 'https://github.com/kolun4ik/diplom_kiteup'

def deploy(): """развернуть""" site_folder = f'/home/{env.user}/sites/{env.host}' source_folder = site_folder + '/source' _create_directory_structure_if_necessery(site_folder) _get_latest_source(source_folder) _update_settings(source_folder, env.host) _updatevirtualenv(source_folder) _update_static_file(source_folder) _update_database(source_folder)

def _create_directory_structure_if_necessery(site_folder): """создаем, если нужно, структуру каталогов""" for subfolder in ('database', 'static', 'virtualenv', 'source'): run(f'mkdir -p {site_folder}/{subfolder}') …..


Конфигурационные файлы сервисов кладем здесь же deploy_tools/*.template.service и все руководства к развертыванию 
будут находиться в файле provisionins_notes.md.

С ПК, на котором осуществлялась разработка, с помощью fabric заливаем исходный код на сервер под правами 
непривилегированного пользователя (запускаем в папке с файлом fabfile.py):

fab -i c:\Temp\s_key.ppk deploy:host=deploy@dev.kiteup.ru

s_key.ppk - файл приватного ключа (предварительно настроен доступ к ssh с помощью публичного ключа)


Для того, чтобы сообщить ФТ, что требуется проверка удаленного сервера, модифицировал setUp(self) введя переменную 
STAGING_SERVER:

def setUp(self): """Установка, выполняется для каждого метода test_*()""" self.browser = webdriver.Firefox() staging_server = os.environ.get('STAGING_SERVER') if staging_server: self.live_server_url = 'http://' + staging_server


Запускаем функциональные тесты для проверки работоспособности проекта, размещенного на dev.kiteup.ru:

$ export STAGING_SERVER=dev.kiteup.ru ../python manage.py test functional_test


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

## Заключение.

На самом деле при разработке диплома я столкнулся со многими трудностями. Такими, что до обучения не справился бы с 
ними и сдался. На курсе otus.ru получил теоретические знания и практические навыки разработки на Python. Плюс освоение 
методологии TDD позволило пусть маленькими шагами, но уверено  топать к намеченной цели – переделать сайт kiteup.ru и 
развернуть на нем новый функционал.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published