目次
1.アプリ開発のきっかけ
2.開発方法
3.修正・改良時の工夫
4.ソースコード
1.アプリ開発のきっかけ
転職活動のためです。
私は新卒から5年間営業として続けてきましたが、技術系の職種に興味を持ち、独学でプログラミングを始めました。
実際にWebアプリを作成することで、実践力を身に付けたいと考えています。
2.開発方法
Youtubeにて、以下の動画を参考にしました。
https://youtu.be/EQIAzH0HvzQ?si=jUDIGKnPLmBChcXj
PythonプログラミングYoutuberのサプーさんです。
動画で環境構築の方法も含めて、書店の新刊情報を記録・表示するアプリの作成方法を解説しています。
動画で解説している内容をもとに、こちらの通りアプリを作成しました。
こちらはホーム画面です。「サプー書店」という書店を想定し、今月の新刊一覧を表示しています。
ホーム画面下部の「編集」リンクをクリックすると、新規登録画面に遷移します。こちらの画面で入荷日・タイトル・金額のデータを入力できます。
作成したうえで、以下のように改善したいと思いました。
①実用的に考えると、書店ではなく「読んだ本を記録するアプリ」として作成したい
②登録済みのレコードに対し、データを編集・削除する機能を実装
そこで、作成済みのコードに対して以下の通り改良を加えました。
①「読書記録」アプリとしての作成
・タイトルを「読書記録」に変更
・データベースのカラムを、「入荷日」「タイトル」「金額」から、「購入日」「タイトル」「感想」に変更(それに伴う変数も変更)
②編集・削除機能の追加
・HTMLにて、各レコードに対する編集ボタン・削除ボタンの追加
・新しくedit.htmlというファイルを作成し、編集の機能を追加 それに紐づく処理をmain.pyに追加
・main.pyに削除の処理を追加
その他微修正
・required属性を追加し、タイトルが空の状態で登録できないように改良
・新規登録するためのリンクの表示名を「編集」から「新規登録」に変更
3.修正・改良時の工夫
できるだけ動画の解説を参考に、「どこに何が、どういう意味合いで記載されているのか」を考えながら紐解きました。
自力で解決できない部分はChatGPTに質問し、コードを記述しました。
修正する内容は、システムのユーザになりきり、見た目や操作性で必要なものを考えました。
4.ソースコード
以下、7種類のファイルを作成しました。
・index.html
・form.html
・edit.html
・main.py
・init__.py
・db.py
・style.css
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Webアプリ</title>
<link rel="stylesheet" href="{{url_for('static',filename='style.css')}}">
</head>
<body>
<h1>読書記録</h1>
{% if books == [] %}
<p>読書記録はありません</p>
{% else %}
<table border="1">
<tr>
<th>購入日</th>
<th>タイトル</th>
<th>感想</th>
</tr>
{% for book in books %}
<tr>
<td><p>{{ book.purchase_day }}</p></td>
<td><p>{{ book.title }}</p></td>
<td><p>{{ book.report }}</p></td>
<td><a href="{{ url_for('edit', title=book['title']) }}">編集</a></td>
<td>
<form method="post" action="{{ url_for('delete', title=book.title) }}">
<input type="submit" value="削除">
</tr>
{% endfor %}
</table>
{% endif %}
<a href="{{ url_for('form') }}">新規登録</a> <!--ボタンを押したときに、formを表示する formはmain.pyで指定-->
</body>
</html>
form.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>読書記録</title>
<link rel="stylesheet" href="{{url_for('static',filename='style.css')}}">
</head>
<body>
<h1>読書記録</h1>
<form method="post" action="{{url_for('register')}}"> <!--post:リクエストの種類 action:登録ボタンを押した後に実行する関数(registerはmain.pyで記述)-->
<table border="1">
<tr>
<th>購入日</th>
<th>タイトル</th>
<th>感想</th>
</tr>
<!--テキストボックスの作成-->
<tr>
<td><input type="text" name="purchase_day"></td>
<td><input type="text" name="title" required></td> <!-- required:空の状態で登録しようとするとエラーを表示 -->
<td><input type="text" name="report"></td>
</tr>
</table>
</br>
<input type="submit" value="登録"> <!--登録ボタンの作成-->
</form>
</body>
</html>
edit.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>読書記録 - 編集</title>
<link rel="stylesheet" href="{{url_for('static',filename='style.css')}}">
</head>
<body>
<h1>本の情報を編集</h1>
<form method="post" action="{{ url_for('update', title=book['title']) }}">
<label for="purchase_day">購入日:</label>
<input type="text" name="purchase_day" value="{{ book['purchase_day'] }}"><br>
<label for="title">タイトル:</label>
<input type="text" name="title" value="{{ book['title'] }}"><br>
<label for="report">感想:</label>
<input type="text" name="report" value="{{ book['report'] }}"><br>
<input type="submit" value="更新">
</form>
<a href="{{ url_for('index') }}">戻る</a>
</body>
</html>
main.py
from flaskr import app #flaskアプリのオブジェクトをインストール
from flask import render_template, request, redirect, url_for
import sqlite3
DATABASE='database.db'
@app.route('/')
def index():
con = sqlite3.connect(DATABASE)
db_books=con.execute('SELECT*FROM books').fetchall()
con.close()
books=[]
for row in db_books:
books.append({'title':row[0], 'report':row[1], 'purchase_day':row[2]})
return render_template(
'index.html',
books=books
)
@app.route('/form')
def form():
return render_template(
'form.html' #新規登録ボタンが押された時の表示の仕方を記述(ボタンはindex.htmlのAタグ)
)
#登録処理
@app.route('/register', methods=['POST']) #/register:register関数の内容がURLとして紐づく postのリクエストの場合にregisterが呼び出される
def register():
title=request.form['title']
report=request.form['report']
purchase_day=request.form['purchase_day']
con=sqlite3.connect(DATABASE)
con.execute('INSERT INTO books VALUES(?,?,?)',
[title,report,purchase_day]) #1つ目の?にtitle、2つ目の?にreport、3つ目の?にpurchase_dayの値に当てはまり、booksのテーブルに登録される
con.commit()
con.close()
return redirect(url_for('index')) #main.pyのindexのURLにリダイレクトされるようになる
# 編集処理(登録済みのレコード)
@app.route('/edit/<string:title>', methods=['GET'])
def edit(title):
con = sqlite3.connect(DATABASE)
book = con.execute('SELECT * FROM books WHERE title = ?', (title,)).fetchone()
con.close()
if book:
book_data = {'title': book[0], 'report': book[1], 'purchase_day': book[2]}
return render_template('edit.html', book=book_data)
else:
return redirect(url_for('index'))
# 更新処理
@app.route('/update/<string:title>', methods=['POST'])
def update(title):
new_title = request.form['title']
new_report = request.form['report']
new_purchase_day = request.form['purchase_day']
con = sqlite3.connect(DATABASE)
con.execute('UPDATE books SET title = ?, report = ?, purchase_day = ? WHERE title = ?',
(new_title, new_report, new_purchase_day, title))
con.commit()
con.close()
return redirect(url_for('index'))
# 本の削除処理
@app.route('/delete/<string:title>', methods=['POST'])
def delete(title):
con = sqlite3.connect(DATABASE)
con.execute('DELETE FROM books WHERE title = ?', (title,))
con.commit()
con.close()
return redirect(url_for('index'))
init__.py
from flask import Flask
app = Flask(__name__)
import flaskr.main
from flaskr import db
db.create_books_table()
db.py
import sqlite3
DATABASE='database.db'
def create_books_table():
con = sqlite3.connect(DATABASE) #DATABASEへの接続用オブジェクトを作る
con.execute("""
CREATE TABLE IF NOT EXISTS books(
title TEXT,
report TEXT,
purchase_day TEXT)
""")
con.close()
#SQLite:flaskをインストールすると初めから入っている 表形式のデータをためておくことができる 小規模で、1ファイルだけに貯めておくもの
style.css
h1{
position: relative;
background:#dfefff;
box-shadow: 0px 0px 0px 5px #dfefff;
border: dashed 2px white;
padding: 0.2em 0.5em;
color: #454545;
}
h1:after {
position: absolute;
content: '';
left: -7px;
top: -7px;
border-width: 0 0 15px 15px;
border-style: solid;
border-color: #fff #fff #a8d4ff;
box-shadow: 1px 1px 1px rgba(0,0,0,0.15);
}