[Python] FlaskとSQLiteで作るシンプルな本管理アプリ

## 概要

今回は、FlaskとSQLiteを使って簡単な本管理アプリを作成します。このアプリは本のタイトルと著者を登録し、一覧で表示、削除ができる機能を備えています。HTMLとCSSを使って、フォームやテーブルのデザインも行い、使いやすいUIを作成します。

## 完成イメージ
![スクリーンショット 2024-10-23 18.59.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75802/5123ca8a-f359-2a67-94b4-02a5a7a3fc0a.png)
![スクリーンショット 2024-10-23 19.00.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75802/5bc23702-7416-3497-c97b-996107dfd3eb.png)


## 使用する技術

- Python 3.x
- Flask
- SQLite
- HTML & CSS

## プロジェクト構成

ディレクトリの構成は次のようになります。

```
/book_manager
|-- app.py
|-- books.db
|-- templates
|   |-- add_book.html
|   `-- book_list.html
`-- static
    `-- styles.css
```

## 1. 環境のセットアップ

まず、必要なライブラリをインストールします。ターミナルで以下のコマンドを実行してください。

```bash
pip install Flask
```

## 2. Flaskアプリケーションの作成

### `app.py`

次に、`app.py` ファイルを作成し、以下のコードを追加します。

```python
from flask import Flask, render_template, request, redirect
import sqlite3

app = Flask(__name__)

# データベース接続関数
def get_db_connection():
    conn = sqlite3.connect('books.db')
    conn.row_factory = sqlite3.Row
    return conn

# 初回リクエスト時にテーブルを作成
@app.before_first_request
def create_table():
    conn = get_db_connection()
    conn.execute('''
        CREATE TABLE IF NOT EXISTS books (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            title TEXT NOT NULL,
            author TEXT NOT NULL
        )
    ''')
    conn.commit()
    conn.close()

# 本の追加画面
@app.route('/add-book', methods=['GET', 'POST'])
def add_book():
    if request.method == 'POST':
        title = request.form['title']
        author = request.form['author']
        conn = get_db_connection()
        conn.execute('INSERT INTO books (title, author) VALUES (?, ?)', (title, author))
        conn.commit()
        conn.close()
        return redirect('/books')
    return render_template('add_book.html')

# 本の一覧表示
@app.route('/books')
def book_list():
    conn = get_db_connection()
    books = conn.execute('SELECT * FROM books').fetchall()
    conn.close()
    return render_template('book_list.html', books=books)

# 本の削除機能
@app.route('/delete-book/<int:id>', methods=['POST'])
def delete_book(id):
    conn = get_db_connection()
    conn.execute('DELETE FROM books WHERE id = ?', (id,))
    conn.commit()
    conn.close()
    return redirect('/books')

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

## 3. フロントエンドの作成

次に、HTMLとCSSでフロントエンドを作成します。

### `templates/add_book.html`

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Add Book</title>
    <link rel="stylesheet" href="/static/styles.css">
</head>
<body>
    <div class="container">
        <h1>Add a New Book</h1>
        <form action="/add-book" method="POST">
            <label for="title">Title:</label>
            <input type="text" id="title" name="title" placeholder="Enter book title" required>
            
            <label for="author">Author:</label>
            <input type="text" id="author" name="author" placeholder="Enter author's name" required>
            
            <button type="submit">Add Book</button>
        </form>
        <a href="/books" class="btn-back">Back to Book List</a>
    </div>
</body>
</html>
```

### `templates/book_list.html`

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Book List</title>
    <link rel="stylesheet" href="/static/styles.css">
</head>
<body>
    <div class="container">
        <h1>Book List</h1>
        <table>
            <thead>
                <tr>
                    <th>Title</th>
                    <th>Author</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody>
                {% for book in books %}
                <tr>
                    <td>{{ book.title }}</td>
                    <td>{{ book.author }}</td>
                    <td>
                        <form action="/delete-book/{{ book.id }}" method="POST" style="display:inline;">
                            <button type="submit" class="delete-button">Delete</button>
                        </form>
                    </td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
        <a href="/add-book" class="btn-add">Add Another Book</a>
    </div>
</body>
</html>
```

## 4. CSSでスタイリング

### `static/styles.css`

```css
/* 全体のスタイル */
body {
    font-family: 'Poppins', sans-serif;
    background-color: #f0f2f5;
    margin: 0;
    padding: 0;
}

.container {
    width: 90%;
    max-width: 800px;
    margin: 50px auto;
    background-color: #fff;
    border-radius: 10px;
    padding: 20px;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
}

h1 {
    text-align: center;
    color: #333;
    margin-bottom: 20px;
    font-size: 2rem;
}

form {
    display: flex;
    flex-direction: column;
}

label {
    font-size: 1.1rem;
    margin-bottom: 5px;
    color: #555;
}

input[type="text"] {
    padding: 10px;
    margin-bottom: 20px;
    border: 1px solid #ddd;
    border-radius: 5px;
    font-size: 1rem;
}

button {
    padding: 10px 20px;
    background-color: #007bff;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
    font-size: 1rem;
    transition: background-color 0.3s ease;
}

button:hover {
    background-color: #0056b3;
}

/* リストテーブルのスタイル */
table {
    width: 100%;
    border-collapse: collapse;
    margin-bottom: 20px;
}

th, td {
    padding: 15px;
    text-align: left;
    border-bottom: 1px solid #ddd;
}

th {
    background-color: #f8f9fa;
    font-size: 1.2rem;
    color: #555;
}

tr:hover {
    background-color: #f1f1f1;
}

.delete-button {
    background-color: #dc3545;
    color: white;
    border: none;
    border-radius: 5px;
    padding: 5px 10px;
    cursor: pointer;
}

.delete-button:hover {
    background-color: #c82333;
}

.btn-add, .btn-back {
    display: block;
    text-align: center;
    background-color: #28a745;
    color: white;
    padding: 10px 20px;
    border-radius: 5px;
    text-decoration: none;
    margin: 10px 0;
}

.btn-add:hover, .btn-back:hover {
    background-color: #218838;
}
```

## 5. アプリの実行

以下のコマンドでアプリケーションを実行します。

```bash
python app.py
```

ブラウザで `http://127.0.0.1:5000/add-book` にアクセスし、本を追加します。その後、 `http://127.0.0.1:5000/books` で本の一覧を確認し、削除も行えます。

## まとめ

このアプリケーションでは、FlaskとSQLiteを使用して簡単なCRUDアプリケーションを構築しました。SQLiteは小規模なデータベースアプリケーションに最適で、Flaskとの組み合わせにより、非常に手軽にデータを管理するアプリケーションが作成できます。

今後はさらに機能を追加したり、フロントエンドを強化したりすることで、より実用的なアプリへと発展させることができます。ぜひこの機会に試してみてください！