6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CRUD機能を作成してみる

Last updated at Posted at 2021-01-11
# はじめに Flaskを使用して1からアプリケーションを作り、必要な技術を学んでいただけるようにまとめています。

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)

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?