Как я построил электронный гараж для мотоцикла: Создание веб-приложения на Flask

Итак. Эта идея мне пришла после того, как я переобул свой мотоциклик. Тогда я стал вспоминать, когда последний раз менял масло. Однако вспомнить мне не удалось. И я подумал: а почему бы не сделать сервис, который мог бы отслеживать техническое состояние техники и показывать предстоящее обслуживание. Так мне и пришла в голову идея создать веб-приложение MotoDiag.

Разработка идеи и выбор технических инструментов

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

После настал момент выбора стека. Фронт я писал на чистом HTML CSS JS. А для бэка мой выбор пал на "Flask". Flask я решил выбрать как минимум потому, что python - единственный язык, который я хорошо знаю. А если говорить о выборе между Django и Flask, то в данном случае Flask мне приглянулся его простотой

База данных. Использовал SQLite в связке с SQLalchemy. Для деплоя на хостинге и дальнейшего масштабирования, конечно, нужно будет использовать другую СУБД (MySQL, например).

Потихоньку пишем

Настала самая интересная часть разработки проекта. В этой публикации я кратко пробегусь по серверной и "фронтовой" части сайта. Если я увижу активность на этом посте, что меня очень замотивирует, то я обязательно подробнее остановлюсь на реализации роутов и функций.

Модели

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

Используются следующие модели: User - пользователь; PendingRegistration - запись пользователя до подтверждения его почты; Motorcycle - мотоцикл; ElementsFluid - компоненты мотоцикла, статистика которых отслеживается приложением; MaintenanceHistory - история обслуживания.

Роуты

Кратко пробежимся по роутам приложения.

Basic - базовый роут, который перенаправляет на страницы index и login в зависимости от того, вошел ли пользователь

Register - роут регистрации, как можно понять из названия

Logout - логин выхода из аккаунта, не сложно догадаться

Add moto info - роут для добавления мотоцикла. Обязательная процедура при первом входе

Add motorcycle - роут для записи мотоцикла в базу данных

Index - главный роут всего приложения. В нем формируется страница с краткой статистикой по мотоциклам и предстоящем обслуживании

My moto - страница с мотоциклами пользователя. Формирует данные для отображения мотоциклов пользователя и краткую статистику по ним

Moto image - используется для декодирования изображения мотоцикла из базы данных

Maintenance - роут, на котором происходит формирование предстоящего обслуживания мотоциклов пользователя

Add maintenance - роут для добавления обслуживания мотоцикла

Update mileage- роут для обновления пробега мотоцикла

Moto page - роут для отображения страницы мотоцикла

Функция расчета состояния мотоцикла

Сейчас хочу объяснить работу функции для расчет состояния мотоцикла

def calculate_moto_condition(moto, elements): if not elements: return "Нет данных", 0 WEIGHTS = { 'oil_filter': 1.5, 'air_filter': 1.2, ... } MAINTENANCE_INTERVALS = { 'oil_filter': 5000, 'air_filter': 8000, ... } current_mileage = moto.mileage total_score = 0 max_score = 0 for element in MAINTENANCE_INTERVALS.keys(): last_change_mileage = getattr(elements, f"{element}_mileage", 0) interval = MAINTENANCE_INTERVALS[element] km_since_last = current_mileage - last_change_mileage if km_since_last == 0: element_score = 1.0 else: overdue_percent = max(0, (km_since_last - interval) / interval * 100) element_score = max(0, 1 - min(1, overdue_percent / 100)) weight = WEIGHTS.get(element, 1.0) total_score += element_score * weight max_score += weight normalized_score = (total_score / max_score) * 100 if normalized_score >= 80: return "Отличное", normalized_score elif normalized_score >= 60: return "Хорошее", normalized_score ... else: return "Критическое", normalized_score

Итак. Кратко пробегусь и постараюсь понятно объяснить. У каждого элемента мотоцикла есть свой вес и интервал обслуживания. Функция получает пробег мотоцикла. Далее нужно узнать, а не пора ли обслужить элемент. Это происходит посредством сравнения пробега мотоцикла и значения пробега при последнем обслуживании элемента. Если получившееся значение не превышает интервал обслуживания элемента, то все хорошо, переходим к следующему элементу. Но если все-таки интервал превышен, то тогда мы как бы добавляем плюсик в копилку плохого состояния мотоцикла.

По итогу полученные данные обрабатываются с учетом веса элементов и формируется конечный ответ

Ниже прилагаю скрины:

А шо в итоге?

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

Ну а в заключении скажу. Спасибо, что дочитали мою, моментами, бредовую статью. Это мой первый опыт. Как в написании статьи, так и в разработке более крупного проекта, чем калькулятор)). Если у тебя есть опыт с подобными проектами – пиши в комментарии! Интересно узнать твои решения.

И напоследок:

Если закрыть глаза, становится темно.

Джейсон Стэтхэм
3
10 комментариев