Задачи, Статьи, Недельный Python Дайджест, FAQ, Курсы по Python, Видео-уроки, Скринкасты
Пишем простые проекты. Проект #1. Часть #2
Продолжаем писать проект "Страница со статистикой отжимания" с помощью flask + google chart's.
В этой части дополним шаблон javascript'ом, продумаем и реализуем сохранение/загрузки истории.
Ранее (http://bit.ly/20cxo8i) создан базовый проект flask и html файл с текстом Hiiii.
Структура файлов перед второй частью:
. ├── app.py ├── requirements.txt └── templates └── index.html
Начинаем вторую часть.
Обращаю внимание что код в цикле этих статей очевидный и простой. Автор не ставит цели писать идеальный код.
Сначала разберемся какие данные есть в проекте и как будем их хранить.
В этом проекте нет разнообразия данных. Одна величина - количество отжиманий в момент времени T. Поэтому хранилище или крутая база данных не требуется - хватит и файла. В файл запишем список (массив) элементов из двух значений - время и количество отжиманий
Пример:
data = [ (date1, value1), (date2, value2), ]
Дата будет в виде unixtime - т.е. количество секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года - т.е. целое число. Будем вычислять так:
import datetime int(datetime.datetime.now().timestamp() * 1000)
Количество отжиманий тоже целое число.
Формат определен. Теперь начнем сохранять/загружать данные из файла. Для удобства будет использован модуль pickle из стандартной библиотеки.
Модуль pickle позволяет преобразовывать python-объект (переменную) в бинарный формат и обратно.
Это позволит не думать о способе хранения описанной структуры. Достаточно будет сформировать список кортежей, прогнать через модуль и сохранить в файл. Это и сделаем:
Далее страшный код с глобальной переменной :) Это аля домашнее задание - переписать код без глобальной переменной.
import pickle DATA = [] # переменная в которой состояние сервера - список кортежей PATH = 'store.pkl' # путь до файла, для сохранения состояния # функция записи значения в файл, значение это (date1, value1) (кортеж, два элемента - целые числа) def write(value): global DATA DATA.append(value) with open(PATH, 'wb') as fio: pickle.dump(DATA, fio) # функция чтения данных def read(): global DATA try: with open(PATH, 'rb') as fio: DATA = pickle.load(fio) except FileNotFoundError: DATA = []
На что стоит обратить внимание:
- модуль pickle. Этот проект пишем под Python3. Для Python2 необходимо написать cPickle
- 'rb' и 'wb' - буква r означает read, w - write, а буква b - binary. Напомню, что pickle преоразует Python объект в бинарную структуру.
Практика: попрактикуйтесь с этим кодом - запишите данные с помощью функции write, прочитайте с помощью read
Справки: использование модуля six (ставится дополнительно) позволяет упростить написание переносимого кода. (т.е. совместимый с Python 2 и 3)
Поправим код запуска:
if __name__ == "__main__": read() app.run(debug=True)
Таким образом при запуске сервера в переменной DATA будет статистика отжиманий. Вспомним основную задачу проекта - отобразить статистику об отжиманиях на web-странице. Чтобы передать эти данные на страницу перепишем функцию index():
import json @app.route("/") def index(): global DATA return render_template("index.html", data=json.dumps(DATA))
Что здесь интересного? В функцию render_template добавили аргумент data и передали данные в JSON формате. Название data играет роль. По этому имени будет доступны данные в html шаблоне.
Справка: Формат JSON подходит для web-проектов благодаря поддержке браузерами и простой структуре данных. Про JSON можно прочиать по ссылке
На данный момент с Python-кодом закончим и перейдем к шаблону. Теперь надо отобразить данные.
Заменив текст Hiiiiiiii на {{ data }}, как можно догадаться, получим отображение переменной json.dumps(DATA) (передали в методе index). Пока DATA пустая (нет файла с данными) можно присвоить какое-то свое значение - попробуйте.
Справка: формат записи {{ data }} это часть языка движка шаблонов Jinja2. Почитать возможности движка можно по ссылке. Подобный формат синтаксиса используется и в другом веб-фреймворке (django)
Теперь пойдем дальше, визуализируем данные.
Для этого будет использоваться Google charts. Это библиотека для Javascript, которая обладает хорошей документацией и примерами. Разговор про Javascript можно вести долго, поэтому приведу итоговый код и кратко опишу его.
<!DOCTYPE html> <html lang="en"> <head> <script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1.1','packages':['corechart', 'timeline']}]}"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> </head> <body> <div id="chart_div"></div> <script> var dynamic_data = []; var json_data = {{ data|safe }}; json_data.forEach(function (element) { dynamic_data.push([new Date(element[0]), element[1]]); }); var chart = new google.visualization.LineChart( document.getElementById('chart_div')); google.load('visualization', '1', {packages: ['corechart']}); google.setOnLoadCallback(drawChart); function genOptions() { return { height: 500, legend: {position: 'none'}, enableInteractivity: false, title: 'Статистика отжиманий от пола', chartArea: { width: '85%' }, hAxis: { title: 'Время', gridlines: { count: -1, units: { days: {format: ['MMM dd']}, hours: {format: ['HH:mm', 'ha']} } }, minorGridlines: { units: { hours: {format: ['hh:mm:ss a', 'ha']}, minutes: {format: ['HH:mm a Z', ':mm']} } } }, vAxis: { title: 'Количество отжиманий', minValue: 0 } }; } function genData(dynamic_data) { var data = new google.visualization.DataTable(); data.addColumn('datetime', 'X'); data.addColumn('number', 'Отжимания'); data.addRows(dynamic_data); return data; } function drawChart() { chart.draw(genData(dynamic_data), genOptions()); } </script> </body> </html>
В этом коде происходит следующее
- В теге head подключаем библиотеки для рисования графиков
- В блоке
<div id="chart_div"></div>
будет сам график - В блоке
<script>...</script>
описана инициализация графика (сделано форматирование осей и прочее)
А выглядит это все так:
Итог на данный момент:
- Есть flask приложение с возможностью сохранять и загружать данные в/из файла. Определен формат данных.
- Есть страничка, на которой отображается график (пока без данных)
Остается связать эти две части вместе.
На этом прерву эту часть.
Продолжение следует.
Комментарии