最近、個人的なプロジェクトとして、シンプルな日程調整サービス「ご都合くん」を作りました。
≫ ご都合くん
トップページはこんな感じです。

飲み会・送別会・歓迎会・打ち合わせなどで、候補日を作ってURLを共有するだけで参加可否を集められる、いわゆる調整系ツールです。
いままでは「調整さん」というサービスを使っていたのですが、これなら比較的簡単に作れそうだと思ったので、自作してみることにしました。
普段はLaravelやSpring Bootで開発することが多いのですが、今回はあえて Python + Flask を使ってみました。
その中で感じたことを、エンジニア目線で正直に書いてみます。

なぜPython+Flaskを選んだのか
理由は簡単です。
- Pythonで何かを作ってみたかった
- 小規模サイトならFlaskが使いやすそう
その程度の動機です。最近はFlaskが多くのプロジェクトで使われているので、試しに使ってみるか、という程度です。
機能
日程調整するためだけのサービスなので、機能はシンプルです。
- イベントの作成
- 候補日の登録
- URL共有
- 参加希望者が◯△✕で回答&コメント入力
- 回答の一覧表示(日付ごとに◯△✕の数の表示も)
どうやって作ったのか
今回は、ChatGPTに聞きながら作っていきました。
最初は、以下の質問から始めました。
構成の選定
PythonでWebアプリを作るとしたら、どのような構成がおすすめ?
以下のフレームワークが提案されました。
- Flask
- Django
- FastAPI
- StreamLit
Flaskが小規模向けみたいなので、Flaskを選択。
DB接続には、SQLAlchemyが定番ということなので、あまり考えずにこれを採用。
プロジェクトを作成
構成が決まったので、プロジェクトを作成します。
mkdir go2gokun cd go2gokun
仮想環境を作れと言われたので、よくわからないまま作ります。
python3 -m venv venv source venv/bin/activate
Flaskをインストールします。
pip install flask pip freeze > requirements.txt
ChatGPTに言われるままに、ファイルを作成します。
app/__init__.py
from flask import Flask
def create_app():
app = Flask(__name__)
from .routes import main
app.register_blueprint(main)
return app
app/routes.py
from flask import Blueprint, render_template, current_app
main = Blueprint("main", __name__)
@main.route("/")
def index():
return render_template(
"index.html",
app_name=current_app.config["APP_NAME"]
)
app/templates/index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>ご都合くん</title>
</head>
<body>
<h1>ご都合くん</h1>
<p>みんなの「行ける」をすぐ決める日程調整サービス</p>
</body>
</html>
run.py
from app import create_app
app = create_app()
if __name__ == "__main__":
app.run(debug=True)
起動します。
python run.py
http://localhost:5000/ にアクセスしたら、動きました。
動いてしまえば、あとは必要な機能を順に作り込んでいくだけです。
基本的には、ルーティングを app/routes.py に記述して、app/templates/ にHTMLテンプレートを置いておけば動く感じです。
DBの準備
この辺もChatGPTにお任せです。
FlaskにSQLAlchemyを追加します。
pip install flask-sqlalchemy flask-migrate psycopg2-binary pip freeze > requirements.txt
FlaskにDB設定を追加します。
app/config.py
class Config:
APP_NAME = "ご都合くん"
SECRET_KEY = "dev-secret-key"
SQLALCHEMY_DATABASE_URI = (
"mysql://go2go:password@localhost:5432/go2go"
)
SQLALCHEMY_TRACK_MODIFICATIONS = False
app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from .config import Config
db = SQLAlchemy()
migrate = Migrate()
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
db.init_app(app)
migrate.init_app(app, db)
from .routes import main
app.register_blueprint(main)
return app
Modelを作ります。
app/models.py
from . import db
import uuid
from datetime import datetime
class Event(db.Model):
__tablename__ = "events"
id = db.Column(db.Integer, primary_key=True)
public_id = db.Column(
db.String(36),
unique=True,
nullable=False,
default=lambda: str(uuid.uuid4())
)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
マイグレーションを実行します。
flask db init flask db migrate -m "create events table" flask db upgrade
Python+Flaskをよくわかってないままやってるので、いろいろと細かいところでつまづきながらも、少しずつ作っていきました。
本番で一般公開
VPS上で動作させるために、VPS上でもいろいろとインストールさせられました。
ローカル環境では、開発サーバーで動かすのですが、本番環境では gunicorn というのが必要みたいです。
とりあえず手動で起動してみて、動いたらサービス化します。
pip install gunicorn gunicorn -w 3 -b 127.0.0.1:8000 run:app
気になった点
Python+Flaskを初めて使ってみたのですが、設計的に気になるところがいくつかありました。
models.pyに集まりがち問題
今回のアプリでは、models.py いすべてのモデルが入った状態になってます。
たぶんモデル別にファイルを分割する方法もあるのだと思いますが、ファイル名が models.py なだけに、ここに全部書けという意図を感じます。
この書き方だと、ファイルが肥大化しやすいし、凝集度が下がりがちだし、結果的に見通しがわるくなる弊害があります。
routes.pyに全部が集まりがち問題
ChatGPTが提案したコードは、ルーティングとロジックとDBアクセスのすべてが routes.py に集まってます。
今回は小さなアプリでしたが、これでもヤバい感じしかないです。
ルーティングとロジックとDBアクセスは、別ファイルに分離したいですね。
実行環境がめんどう
作っていて、venv するのを忘れて、動かないことが多かったです。
まとめ
Flaskは小規模システムなら学習コストが低くていいかなと思いましたが、設計面ではファイル分割をきちんと考慮しないととっ散らかるなと思いました。