この記事ではWebアプリケーションフレームワークのFlaskを使用して掲示板をつくってみます。
この記事のサンプルコードでは画像のような掲示板を作成できます。
Flaskのインストールや基本的な使い方は以下の記事で紹介していますので、まだの方はご覧ください。
【初心者向けWebサイト開発】FlaskでWebページを作成してみよう
この記事ではWebアプリケーションフレームワークのFlaskを使用して、簡単なWebページを作成する方法を紹介します。 FlaskはPython用のフレームワークのため、事前にPyth…
目次
ディレクトリ構成
今回つくるアプリケーションは、以下のようなディレクトリ構成になっています。
my_flask_app/
├── app.py
├── models.py
├── templates/
│ ├── index.html
│ ├── new_post.html
│ └── post_detail.html
└── static/
└── style.css
サンプルコード
app.py
from flask import Flask, render_template, request, redirect, url_for
from models import db, Post, Reply
from datetime import datetime
def create_app():
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///bbs.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db.init_app(app)
with app.app_context():
db.create_all()
return app
app = create_app()
@app.route('/')
def index():
posts = Post.query.order_by(Post.timestamp.desc()).all()
return render_template('index.html', posts=posts)
@app.route('/new', methods=['GET', 'POST'])
def new_post():
if request.method == 'POST':
title = request.form['title']
content = request.form['content']
new_post = Post(title=title, content=content)
db.session.add(new_post)
db.session.commit()
return redirect(url_for('index'))
return render_template('new_post.html')
@app.route('/post/<int:post_id>', methods=['GET', 'POST'])
def post_detail(post_id):
post = Post.query.get_or_404(post_id)
if request.method == 'POST':
content = request.form['content']
reply_count = Reply.query.filter_by(post_id=post_id).count() + 1
new_reply = Reply(content=content, post_id=post_id, reply_number=reply_count)
db.session.add(new_reply)
db.session.commit()
return redirect(url_for('post_detail', post_id=post_id))
return render_template('post_detail.html', post=post)
@app.route('/delete/<int:post_id>', methods=['POST'])
def delete_post(post_id):
post = Post.query.get(post_id)
if post:
db.session.delete(post)
db.session.commit()
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
models.py
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
replies = db.relationship('Reply', backref='post', cascade="all, delete-orphan", lazy=True)
def __init__(self, title, content):
self.title = title
self.content = content
class Reply(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.Text, nullable=False)
timestamp = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
reply_number = db.Column(db.Integer, nullable=False)
def __init__(self, content, post_id, reply_number):
self.content = content
self.post_id = post_id
self.reply_number = reply_number
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>掲示板</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div class="container">
<h1>掲示板</h1>
<a href="{{ url_for('new_post') }}">新規投稿</a>
<hr>
{% for post in posts %}
<div class="post">
<h2><a href="{{ url_for('post_detail', post_id=post.id) }}">{{ post.title }}</a></h2>
<p>{{ post.content }}</p>
<small>{{ post.timestamp }}</small>
<a href="{{ url_for('post_detail', post_id=post.id) }}">返信</a>
<!-- 削除ボタンの追加 -->
<form action="{{ url_for('delete_post', post_id=post.id) }}" method="post" style="display:inline;">
<button type="submit" onclick="return confirm('本当に削除しますか?');">削除</button>
</form>
</div>
<hr>
{% endfor %}
</div>
</body>
</html>
new_post.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>新規投稿</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div class="container">
<h1>新規投稿</h1>
<form action="{{ url_for('new_post') }}" method="post">
<label for="title">タイトル:</label><br>
<input type="text" id="title" name="title"><br>
<label for="content">内容:</label><br>
<textarea id="content" name="content"></textarea><br>
<input type="submit" value="投稿">
</form>
<a href="{{ url_for('index') }}">戻る</a>
</div>
</body>
</html>
post_detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ post.title }}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<div class="container">
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
<small>{{ post.timestamp }}</small>
<!-- 削除ボタンの追加 -->
<form action="{{ url_for('delete_post', post_id=post.id) }}" method="post" style="display:inline;">
<button type="submit" onclick="return confirm('本当に削除しますか?');">削除</button>
</form>
<hr>
<form action="{{ url_for('post_detail', post_id=post.id) }}" method="post">
<label for="content">返信:</label><br>
<textarea id="content" name="content"></textarea><br>
<input type="submit" value="返信">
</form>
<hr>
{% for reply in post.replies %}
<div class="reply">
<p>{{ reply.content }}</p>
<small>{{ reply.timestamp }} - #{{ reply.reply_number }}</small>
</div>
<hr>
{% endfor %}
<a href="{{ url_for('index') }}">戻る</a>
</div>
</body>
</html>
style.css
/* static/style.css */
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh; /* Full viewport height */
margin: 0;
font-family: Arial, sans-serif;
background-color: #f5f5f5;
}
.container {
width: 80%;
max-width: 800px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ccc;
border-radius: 8px;
background-color: #ffffff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
/* 投稿や返信のタイトル、内容のボックスサイズ調整 */
textarea {
width: 100%;
max-width: 100%;
padding: 10px;
box-sizing: border-box;
}
input[type="text"], textarea {
margin-bottom: 10px;
}
実行結果
実行すると、以下のようなホーム画面が表示されます。
「新規投稿」をクリックして新しい掲示板を作成してみます。
ホーム画面に投稿が追加されました。
「テスト」をクリックして、先ほどの投稿に移動し、返信してみます。
返信が追加されました。