【Python】FullCalendarとMySQLを連携して予定を登録できるようにする

2018年6月19日Javascript,Python,開発

おはようございます。

昨日に引き続き FullCalendar。
今回は MySQLにテーブルを作成してカレンダーに表示するデータを登録できるところまでやってみました。

プログラムは前回のものを流用。

スポンサーリンク

下準備

MySQLのインストール

MySQL(フリーのMariaDBを使います)のインストールは次の記事を参照していただければ。

テーブルの作成

CREATE TABLE IF NOT EXISTS TBL_SCHEDULE (
          USER_CD VARCHAR(10)
        , ID INT(10)
        , TITLE VARCHAR(100)
        , START DATETIME
        , END DATETIME
        , TEXTCOLOR VARCHAR(20)
        , COLOR VARCHAR(20)
        , URL VARCHAR(100)
        , ALLDAY VARCHAR(10)
        , PRIMARY KEY(USER_CD, ID)
)

データ登録

ひとまずサンプルのデータを登録しておきます。

DELETE FROM TBL_SCHEDULE;
INSERT INTO TBL_SCHEDULE VALUES('001','1','定例会','2018-06-06T19:00:00','2018-06-06T21:00:00','','','', 'FALSE');
INSERT INTO TBL_SCHEDULE VALUES('001','2','外出','2018-06-18T14:00:00','2018-06-18T17:30:00','','','', 'FALSE');
INSERT INTO TBL_SCHEDULE VALUES('001','3','有給','2018-06-28','2018-06-28','','','', 'TRUE');    

ライブラリの追加

次のライブラリを「メニュー」>「Default Settings」よりインストールします。

  • mysql-connector-python-rf

画面の修正

fullCalendar のオプションで時刻の形式を指定するようにしたのと、
予定を入力した際にサーバーのメソッドを呼び出してデータ登録するようにしました。

index.html

    <!DOCTYPE html>
    <html>
       <head>
          <title>カレンダーサンプル</title>
          <link rel="stylesheet" href="{{ static_url('css/fullcalendar.min.css') }}"/>
          <link rel="stylesheet" href="{{ static_url('css/style.css') }}"/>
          <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
          <script type="text/javascript" src="{{ static_url('js/moment.min.js') }}"></script>
          <script type="text/javascript" src="{{ static_url('js/fullcalendar.min.js') }}"></script>
          <script type="text/javascript" src="{{ static_url('lang/ja.js') }}"></script>
          <script>
             // ページ読み込み時の処理
             $(document).ready(function () {
    
             // カレンダーの設定
             $('#calendar').fullCalendar({
                height: 550,
                lang: "ja",
                header: {
                   left: 'prev,next today',
                   center: 'title',
                   right: 'month,basicWeek,basicDay'
                },
                timeFormat: 'HH:mm',
                selectable: true,
                selectHelper: true,
                navLinks: true,
                eventSources: [{
                   url: 'http://localhost:8080/getCalendar',
                   dataType: 'json',
                   async: false,
                   type : 'GET',
                   error: function() {
                      $('#script-warning').show();
                   }
                }],
                select: function(start, end, resource) {
                   var title = prompt("予定タイトル:");
                   var eventData;
                   if (title) {
                      eventData = {
                         title: title,
                         start: start,
                         end: end,
                         allDay: true
                      };
                      $('#calendar').fullCalendar('renderEvent', eventData, true);
    
                      $.ajax({
                         url: "http://localhost:8080/regist",
                         type: "POST",
                         data: JSON.stringify(eventData),
                         success: function(jsonResponse) {
                            alert("予定を登録しました。")
                         },
                         error: function() {
                         }
                      });
                   }
                   $('#calendar').fullCalendar('unselect');
                   },
                   editable: true,
                   eventLimit: true,
                });
             });
          </script>
       </head>
       <body>
          <div id='calendar'></div>
       </body>
    </html>

サーバープログラムの修正

新規クラス追加

MySQL用クラスを追加

MySQLUtil.py

import mysql.connector
import logging
from contextlib import closing


class MySQLUtil:
    """
    MySQL 操作用クラス
    """

    def __init__(self, host="localhost", port="3306", user="USER01", password="USER01", database="DB01"):
        self.config = {
            "host": host,
            "port": port,
            "user": user,
            "password": password,
            "database": database
        }
        self.create_db()

    def create_db(self):
        """
        データベース、及び必要なテーブルを作成します.
        :return:
        """

        with closing(mysql.connector.connect(**self.config)) as conn:

            c = conn.cursor()

            # スケジュールテーブル
            sql = "CREATE TABLE IF NOT EXISTS TBL_SCHEDULE ("
            sql += "  USER_CD VARCHAR(10)"
            sql += ", ID VARCHAR(10)"
            sql += ", TITLE VARCHAR(100)"
            sql += ", START DATETIME"
            sql += ", END DATETIME"
            sql += ", TEXTCOLOR VARCHAR(20)"
            sql += ", COLOR VARCHAR(20)"
            sql += ", URL VARCHAR(100)"
            sql += ", ALLDAY VARCHAR(20)"
            sql += ", PRIMARY KEY(USER_CD, ID)"
            sql += ")"
            c.execute(sql)

            c.close()
            conn.commit()

    def delete_data(self):
        """
        データを削除します
        :return:
        """

        logging.info("delete_data")
        with closing(mysql.connector.connect(**self.config)) as conn:

            c = conn.cursor()

            # データクリア
            sql = "DELETE FROM TBL_SCHEDULE"
            c.execute(sql)
            c.close()
            conn.commit()

    def insert_data(self, data):
        """
        データを登録します
        :param ticker:
        :return:
        """

        with closing(mysql.connector.connect(**self.config)) as conn:

            c = conn.cursor()
            # データ登録
            sql = "INSERT INTO TBL_SCHEDULE VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s)"
            c.execute(sql, data)

            c.close()
            conn.commit()

    def get_schedule(self, year_month, user_cd=""):
        """
        データ(テーブル)をデータフレームに変換してかえします
        :return:
        """
        result = []

        with closing(mysql.connector.connect(**self.config)) as conn:

            c = conn.cursor(dictionary=True)

            sql = "SELECT * FROM TBL_SCHEDULE"
            sql += " WHERE (DATE_FORMAT(START, '%Y%m') = '" + year_month + "'"
            sql += " OR DATE_FORMAT(END, '%Y%m') = '" + year_month + "')"
            if user_cd != "":
                sql += " AND USER = '" + user_cd + "'"

            sql += " ORDER BY USER_CD, ID"

            c.execute(sql)
            for r in c.fetchall():
                result.append({
                    "user_cd": r['USER_CD'],
                    "id": r['ID'],
                    "title": r['TITLE'],
                    "start": r['START'],
                    "end": r['END'],
                    "textColor": r['TEXTCOLOR'],
                    "color": r['COLOR'],
                    "url": r['URL'],
                    "allDay": (r['ALLDAY'] == 'TRUE')
                })

        return result

    def get_next_id(self, user_cd=""):
        """
        データ(テーブル)をデータフレームに変換してかえします
        :return:
        """
        result = 0

        with closing(mysql.connector.connect(**self.config)) as conn:

            c = conn.cursor(dictionary=True)

            sql = "SELECT MAX(ID) + 1 AS ID FROM TBL_SCHEDULE WHERE USER_CD = '" + user_cd + "'"

            c.execute(sql)

            result = c.fetchone()

        return result[r"ID"]

URLハンドラー、新規メソッドを追加

Main.py

import json
import logging
import os
import tornado.ioloop

from tornado.web import RequestHandler
from tornado.options import options
from Utils.MySQLUtil import MySQLUtil
from datetime import datetime

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("index.html")


class GetCalendar(RequestHandler):
    """
    カレンダー取得
    """

    def initialize(self):
        logging.info("GetCalendar [initialize]")

    def get(self):
        logging.info("GetCalendar [get]")

        mysql = MySQLUtil()

        data = mysql.get_schedule("201806", "")

        self.write(json.dumps(data, default=support_datetime_default))


class RegistSchedule(RequestHandler):
    """
    スケジュール登録
    """
    def initialize(self):
        logging.info("RegistSchedule [initialize]")

    def post(self):
        logging.info("RegistSchedule [post]")

        mysql = MySQLUtil()

        param = json.loads(self.request.body)
        allday = "TRUE" if param["allDay"] else "FALSE"
        id = mysql.get_next_id('001')

        data = [
            "001",
            id,
            param["title"],
            param["start"],
            param["end"],
            "",
            "",
            "",
            allday
        ]

        mysql.insert_data(data)

def support_datetime_default(o):
    if isinstance(o, datetime):
        return o.isoformat()
    raise TypeError(repr(o) + " is not JSON serializable")


app = tornado.web.Application([
    (r"/", MainHandler),
    (r"/getCalendar", GetCalendar),
    (r"/regist", RegistSchedule),
],
    template_path=os.path.join(os.getcwd(), "templates"),
    static_path=os.path.join(os.getcwd(), "static"),
)

if __name__ == "__main__":
    options.parse_command_line()
    app.listen(8080)
    logging.info("server started")
    tornado.ioloop.IOLoop.instance().start()

起動してみる

データを取得して表示
予定の登録
登録結果

まとめ

なかなか形になってきましたね。
次回は Bootstrap なんかを使ってもう少し詳細な予定を登録できるようにしたり、
登録済みの予定を更新、削除までできたらいいかなと思います。

ではでは。

 

スポンサーリンク


関連するコンテンツ

2018年6月19日Javascript,Python,開発FullCalendar,Javascript,JQuery,MariaDB,MySQL,Python,プログラミング

Posted by doradora