Closed10

Flaskでtodoアプリ作成(練習)

みたらしだんごみたらしだんご

ディレクトリ構造

|-- app.py
|-- createdb.py  #DBを作成するだけのソース
|-- static
|   |-- css
|   |   `-- bootstrap.css
|   |-- jquery-3.6.1.min.js
|   `-- js
|       `-- bootstrap.bundle.min.js
|-- templates
|   |-- base.html
|   |-- create.html
|   |-- detail.html
|   |-- index.html
|   `-- update.html
`-- todo.db  #createdb.pyで作成したDB
みたらしだんごみたらしだんご

コメントないけどapp.py

app.py
from flask import Flask, render_template, url_for, request, redirect, g
from datetime import datetime
import sqlite3

app = Flask(__name__)

def get_db():
    if 'db' not in g:
        dbname = 'todo.db'
        g.db = sqlite3.connect(dbname)
    return g.db

@app.route('/', methods=['GET', 'POST'])
def index():
    conn = get_db()
    cur = conn.cursor()
    if request.method == 'GET':
        res = cur.execute('SELECT id, title, detail, date(datetime(due)) as due FROM todo').fetchall()
        conn.close()
        return render_template('index.html', posts=res)

    else:
        res = cur.execute('SELECT id FROM todo ORDER BY id DESC').fetchone()
        if res is None:
            id = 1
        else:
            id = res[0] + 1
        title = request.form.get('title')
        detail = request.form.get('detail')
        due = request.form.get('due')
        due = datetime.strptime(due, '%Y-%m-%d')
        cur.execute('INSERT INTO todo VALUES(:id, :title, :detail, :due)',
         {'id': id, 'title': title, 'detail': detail, 'due': due})
        conn.commit()
        conn.close()
        return redirect('/')

@app.route('/create')
def create():
    return render_template('create.html')

@app.route('/detail/<int:id>')
def read(id):
    conn = get_db()
    cur = conn.cursor()
    res = cur.execute('SELECT title, detail, date(datetime(due)) as due FROM todo WHERE id =:id', {'id': id}).fetchone()
    conn.close()
    return render_template('detail.html', post=res)

if __name__ == "__main__":
    app.run(debug=True, host='xxx.xxx.xxx.xxx', port=1234)
みたらしだんごみたらしだんご

改変 index.html

index.html
{% extends 'base.html' %}

{% block body %}
<div class="container">
    <a class="btn btn-info btn-lg m-5" href="/create" role="button">新しいタスク</a>
    {% for post in posts %}
    <div class="card w-50 mb-3" style="margin: auto;">
        <div class="card-body">

            <h2>タイトル : {{ post[1] }}</h2>
            <p>期限 : {{ post[3] }}</p>
            <a href="/detail/{{ post[0] }}" role="button">詳細</a>
            <a href="/update/{{ post[0] }}" role="button">更新</a>
            <a href="/delete/{{ post[0] }}" role="button">削除</a>
        </div>
    </div>
    {% endfor %}
</div>
{% endblock %}
``` 
みたらしだんごみたらしだんご

改変 detail.html

detail.html
{% extends 'base.html' %}

{%block body %}

<h2 class="m-5" style="text-align: center;">詳細</h2>
<div class="card w-50 mb-3" style="margin: auto;">
    <div class="card-body">
        <h2 class="card-title">{{ post[1] }} <span class="ml-3"
                style="font-size: 0.5em;">期限:{{ post[3] }}</span></h2>
        <p>{{ post[2] }}</p>
        <div class="pt-2">
            <a class="btn btn-outline-success" href="/" role="button">戻る</a>
            <a class="btn btn-success" href="/update/{{ post[0] }}" role="button">更新</a>

        </div>
    </div>
</div>
{% endblock %}
みたらしだんごみたらしだんご

todoテーブル

CREATE TABLE todo(id INTEGER PRIMARY KEY, title VARCHAR(30) NOT NULL, detail VARCHAR(100), due TIMESTAMP not null);
id title detail due
1 aaa bbbbb 2022-10-18 00:00:00
2 テスト でーす 2022-10-19 00:00:00
みたらしだんごみたらしだんご

テーブルレイアウトが良くないかなぁ
app.pyでこれをするならIDはAUTOINCLIMENTでもよかったかも?
それかデータの論理削除項目を追加するか

        res = cur.execute('SELECT id FROM todo ORDER BY id DESC').fetchone()
        if res is None:
            id = 1
        else:
            id = res[0] + 1
みたらしだんごみたらしだんご
update.html
{% extends 'base.html' %}

{% block body %}
<h2 class="m-5">編集</h2>
<form class="m-5" action="/update/{{ post[0] }}" method="POST">
    <div class="form-group pb-3">
        <label for="title">Title : </label>
        <input type="text" class="form-control" name="title" aria-describedby="title-help" value={{ post[1] }}>
    </div>
    <div class="form-group pb-3">
        <label for="detail">Detail : </label>
        <input type="text" class="form-control" name="detail" value={{ post[2] }}>
    </div>
    <div class="form-group pb-3">
        <label for="due">Due : </label>
        <input type="date" name="due" value={{ post[3] }} required>
    </div>
    <a class="btn btn-outline-primary" href="/" role="button">Return</a>
    <button type="submit" class="btn btn-primary">Change</button>
</form>
{% endblock %}
みたらしだんごみたらしだんご

jQueryはなくても良かった

base.html
<!DOCUTYPE html>
<html lang="ja">

<head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <link rel="stylesheet" href="{{url_for('static', filename='css/bootstrap.css')}}")>
    <title>Todoアプリ</title>
        {% block head %}{% endblock %}
</head>

<body>
    <nav class="navbar navbar-light bg-light p-3">
        <a class="navbar-brand p1-3" href="/" style="font-size: 2rem;">Todoアプリ</a>
    </nav>

        {% block body %}{% endblock %}
        <!-- <script src="{{url_for('static', filename='jquery-3.6.1.min.js')}}")></script>  -->
        <script src="{{url_for('static', filename='js/bootstrap.bundle.min.js')}}"></script>
</body>
</html>
みたらしだんごみたらしだんご

参考サイトには期限切れのタスクは注意書きが表示されるようになっていたけどjinjaで日付を文字列から日付型に変換する必要があった。
やり方がわからないから削る。

このスクラップは2022/10/22にクローズされました