Pythonで簡単な掲示板を作成する。（FlaskとSQLを使ったWebアプリ開発入門）#2

# pythonでスレッド付きの掲示板を作る（リレーショナルデータベース）

[前回](https://qiita.com/tomson784/items/a5ad6e47643449dffd18)の続きです。

前回は一つの画面で文章を随時追加していく設計でした。
今回はスレッドを立ててスレッドごとに表示をする掲示板を作成します。

# 実装環境

- Window10 Home 64bit
- Python 3.6.4 |Anaconda, Inc.

# ライブラリ

```
Flask==1.0.2
Flask-SQLAlchemy==2.3.2
Jinja2==2.10
SQLAlchemy==1.2.15
sqlite3（恐らく標準）
```

# データベースについて

データベースではは表形式で管理されるデータを扱います。ここで作る掲示板はスレッドごとに管理をするのでリレーショナルデータベースを用います。構成は以下のようにします。

投稿文書と名前を管理するテーブル

| id |  日付  |  名前  |    文章    | スレッドID  |
|:--:|:------:|:------:|:---------:|:----------:|
|  1 |  date1 | name1  |   text1   | thread_id1 |
|  2 |  date2 | name2  |   text2   | thread_id2 |

スレッドを管理するテーブル

| id | スレッド名 |
|:--:|:----------:|
|  1 | thread_name1 |
|  2 | thread_name2 |


# 使用するデータベース
ここではPythonで簡単に扱えるSqlite3を使います。


# Flask-SQLAlchemy
[公式チュートリアル](http://flask-sqlalchemy.pocoo.org/2.3/quickstart/)を参考にします。

SQLAlchemyではデータベースの操作をオブジェクト指向のように扱います

```python:app.py
class Article(db.Model):
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    pub_date = db.Column(db.DateTime, nullable=False,
                                default=datetime.utcnow)
    name = db.Column(db.String(80))
    article = db.Column(db.Text())
    thread_id = db.Column(db.Integer, db.ForeignKey('thread.id'), nullable=False)

    def __init__(self, pub_date, name, article, thread_id):
        self.pub_date = pub_date
        self.name = name
        self.article = article
        self.thread_id = thread_id

class Thread(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    threadname = db.Column(db.String(80))
    articles = db.relationship('Article', backref='thread', lazy=True)

    def __init__(self, threadname, articles=[]):
        self.threadname = threadname
        self.articles = articles
```

```def __init__()```に関しては追加しないとデータベースを作る際になぜかエラーが出るのでここでは記述してます。
db.relationship()やdb.ForeignKey()を使うことで関連付けをします。

pythonのterminalで以下のようなコマンドを実行するとデータベースが作成されます。

```
>>> from app import db
>>> db.create_all()
>>>
```

# 実装してみる
html部分は面倒なので端折ります。[こちらに](https://github.com/tomson784/bbs)ソースがあります。
flaskとデータベースの設定に関しては前回と同じようにして、あとはスレッドごとに表示する機能を付けると以下のようなプログラムになります。

```python:app.py
@app.route("/")
def main():
    threads = Thread.query.all()
    return render_template("index.html", threads=threads)

@app.route("/thread", methods=["POST"])
def thread():
    thread_get = request.form["thread"]
    threads = Thread.query.all()
    thread_list = []
    threads = Thread.query.all()
    for th in threads:
        thread_list.append(th.threadname)
    if thread_get in thread_list:
        thread = Thread.query.filter_by(threadname=thread_get).first()
        articles = Article.query.filter_by(thread_id=thread.id).all()
        return render_template("thread.html",
                                articles=articles,
                                thread=thread_get)
    else:
        thread_new = Thread(thread_get)
        db.session.add(thread_new)
        db.session.commit()
        articles = Article.query.filter_by(thread_id=thread_new.id).all()
        return render_template("thread.html",
                                articles=articles,
                                thread=thread_get)

@app.route("/result", methods=["POST"])
def result():
    date = datetime.now()
    article = request.form["article"]
    name = request.form["name"]
    thread = request.form["thread"]
    thread = Thread.query.filter_by(threadname=thread).first()
    admin = Article(pub_date=date, name=name, article=article, thread_id=thread.id)
    db.session.add(admin)
    db.session.commit()
    return render_template("bbs_result.html", article=article, name=name, now=date)

if __name__ == "__main__":
    app.run(debug=True)
```

これで掲示板と同じような動きをするwebアプリの完成です。
HerokuでデプロイしたものにこちらのURLからアクセスできます。
https://bbsapp1.herokuapp.com/

リレーショナルデータベースとのたまっていますがこの記述方法はあまりスマートな気がしないのでもっと簡潔に書ける方法を知っている方は是非ご教授ください。

次回はHerokuでデプロイする方法について解説します。
[Herokuでデプロイ](https://qiita.com/tomson784/items/c4bf310efb6237813954)