# はじめに
Flaskを使用して1からアプリケーションを作り、必要な技術を学んでいただけるようにまとめています。
- flaskによる簡易アプリの作成
- Home画面を作成してみる
- 認証機能を作成してみる
- データベースを扱ってみる
- CRUD機能を作成してみる ← ★現在ここ
CRUDとは
CRUDとは、Create, Read, Update, Delete それぞれの頭文字を撮ったものです。
今回作成しているブログアプリケーションでは、以下になります。
- Create: 新規ブログ作成機能(データの新規作成)
- Read: ブログ一覧表示機能及び詳細表示機能(データの読み込み)
- Update: ブログ更新機能(データの更新)
- Delete: ブログ削除機能(データの削除)
CRUDを満たすことで一通りの機能を作成することができます。今回の機能を他のアプリケーションを作成するときにも応用することができます。
Create
ブログ投稿画面作成
- ナビゲーションバーの追加
src/templates/layout.html
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="nav navbar-nav navbar-lighy">
{% if not session.logged_in %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('login') }}">LogIn</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('new_add') }}">新規登録</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('logout') }}">Logout</a>
</li>
{% endif %}
</ul>
</div>
- 投稿フォーム
src/templates/new.htnl
{% extends "./layout.html" %}
{% block body %}
<form action="{{ url_for('add_entry') }}" method=post class=add-entry>
<div class=form-group>
<label for="InputTitle">タイトル</label>
<input type="text" class="form-control" id="InputTitle" name=title>
</div>
<div class="form-group">
<label for="InputText">本文</label>
<textarea name=text id="InputText" rows="10" class="form-control"></textarea>
</div>
<button type="submit" class="btn btn-primary">作成</button>
</form>
{% endblock %}
~~~
#### ブログ投稿機能作成
~~~:src/views.py
from src import app, db
from flask import flash
from flask import redirect
from flask import request
from flask import render_template
from flask import url_for
from flask import session
from src.domains.entry import Entry
User = {
'username': 'test',
'password': 'testpass'
}
@app.route('/')
def index():
if not session.get('logged_in'):
return redirect('/login')
return render_template('index.html')
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
if request.form['username'] != User['username']:
flash(f'ユーザ名が異なります')
elif request.form['password'] != User['password']:
flash(f'パスワードが異なります')
else:
session['logged_in'] = True
flash('ログインしました')
return redirect('/')
return render_template('login.html')
@app.route('/logout', methods=['GET'])
def logout():
session.pop('logged_in', None)
flash('ログアウトしました')
return redirect('/')
@app.route('/new_add', methods=['GET','POST'])
def new_add():
return render_template('/new.html')
@app.route('/add_entry', methods=['POST'])
def add_entry():
if not session.get('logged_in'):
return redirect(url_for('login'))
entry = Entry(
title = request.form['title'],
text = request.form['text'])
db.session.add(entry)
db.session.commit()
flash('新しく記事が作成されました')
return redirect(url_for('index'))
~~~
## Read
#### 一覧機能
~~~:src/templates/index.html
{% extends "./layout.html" %}
{% block body %}
{% for entry in entries %}
<ul class="card">
<div class="card-body">
<h5 class="card-title">
<a href="{{ url_for('show_entry', id=entry.id) }}">{{ entry.title }}</a>
</h5>
</div>
</ul>
{% else %}
投稿がありません
{% endfor %}
{% endblock %}
~~~
~~~:src/views.py
@app.route('/')
def index():
if not session.get('logged_in'):
return redirect('/login')
entries = Entry.query.order_by(Entry.id.desc()).all()
return render_template('index.html', entries=entries)
~~~
![スクリーンショット 2021-01-01 15.50.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618885/0adac676-a459-cb4b-55f9-08d788095ec8.png)
#### 詳細機能
~~~:src/views.py
@app.route('/entry/<int:id>', methods=['GET'])
def show_entry(id):
if not session.get('logged_in'):
return redirect(url_for('login'))
entry = Entry.query.get(id)
return render_template('show.html', entry=entry)
~~~
~~~:src/templates/show.html
{% extends "./layout.html" %}
{% block body %}
<h2>{{ entry.title }}</h2>
<br />
{{ entry.text }}
<br /><br />
投稿日時:{{ entry.create_at }}
{% endblock %}
~~~
![スクリーンショット 2021-01-01 15.49.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618885/1d553c80-c5d8-482e-ea96-16968b8c87c9.png)
## Update
- 編集ボタンの作成
~~~:src/templates/show.html
{% extends "./layout.html" %}
{% block body %}
<h2>{{ entry.title }}</h2>
<br />
{{ entry.text }}
<br /><br />
投稿日時:{{ entry.create_at }}
<br /><br />
<div class="btn-group">
<form action="{{ url_for('edit_entry', id=entry.id) }}" method="GET">
<button type="submit" class="btn btn-secondary">Edit</button>
</form>
</div>
{% endblock %}
~~~
- 編集画面の作成
~~~:src/templates/edit.html
{% extends "./layout.html" %}
{% block body %}
<form action="{{ url_for('update_entry', id=entry.id) }}" method="POST" class="add-entry">
<div class="form-group">
<label>タイトル</label>
<input type="text" class="form-control" name="title" value={{ entry.title}}>
</div>
<div class="form-group">
<label>本文</label>
<textarea class="form-control" name="text" cols="100" rows="3">{{ entry.text | safe }}</textarea>
</div>
<button type="submit" class="btn btn-primary">Update</button>
</form>
{% endblock %}
~~~
- 更新機能の作成
~~~:src.views.py
@app.route('/entry/<int:id>/edit', methods=['GET'])
def edit_entry(id):
if not session.get('logged_in'):
return redirect(url_for('login'))
entry = Entry.query.get(id)
return render_template('edit.html', entry=entry)
@app.route('/entry/<int:id>/update', methods=['POST'])
def update_entry(id):
if not session.get('logged_in'):
return redirect(url_for('login'))
entry = Entry.query.get(id)
entry.title = request.form['title']
entry.text = request.form['text']
db.session.merge(entry)
db.session.commit()
flash('記事が更新されました')
return redirect(url_for('index'))
~~~
- 詳細画面
![スクリーンショット 2021-01-01 16.22.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618885/ad1557d3-b9c1-e7b1-5c21-8375ef709c6d.png)
- 編集画面
![スクリーンショット 2021-01-01 16.23.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618885/02819324-22de-d5fe-46b9-5724323e20a3.png)
## Delete
- 削除ボタンの作成
~~~:src/templates/show.html
{% extends "./layout.html" %}
{% block body %}
<h2>{{ entry.title }}</h2>
<br />
{{ entry.text }}
<br /><br />
投稿日時:{{ entry.create_at }}
<br /><br />
<div class="btn-group">
<form action="{{ url_for('edit_entry', id=entry.id) }}" method="GET">
<button type="submit" class="btn btn-secondary">Edit</button>
</form>
<form action="{{ url_for('delete_entry', id=entry.id) }}" method="POST">
<button type="submit" class="btn btn-danger" style="margin-left:5px">Delete</button>
</form>
</div>
{% endblock %}
~~~
- 削除機能の作成
~~~:src/views.py
@app.route('/entry/<int:id>/delete', methods=['POST'])
def delete_entry(id):
if not session.get('logged_in'):
return redirect(url_for('login'))
entry = Entry.query.get(id)
db.session.delete(entry)
db.session.commit()
flash('投稿が削除されました')
return redirect(url_for('index'))
~~~
- 詳細画面
![スクリーンショット 2021-01-01 16.34.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618885/9fc8a471-78a0-8be0-7699-103a28862e33.png)
- 削除後の画面
![スクリーンショット 2021-01-01 16.33.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/618885/6dfb53ba-1903-cc44-eb14-65d6b801610a.png)