【9/29まで】無料で3,500円分のビットコインをもらう »

【保存版】30分でFlask入門!Webアプリの作り方をPythonエンジニアが解説

こんにちは、はやたす(@hayatasuuu )です。

この記事では「Flaskを使ったWebアプリ(Todoアプリ)の作り方」を分かりやすく紹介していきます。

Flaskの日本語情報は少ないので、この記事が間違いなく役立つはずです!

この記事を読めば、Python初心者でもFlaskを使ったWebアプリを作成できるようになりますよ。

動画版:Flask入門コース

本記事で紹介するFlask入門は、YouTubeで動画をアップしています。

テキストだと動きが分かりづらいので、初心者であれば動画を使って学習するのがオススメです。

独学に役立つLINE配信

Python独学のコツや役に立つ情報を配信するLINEアカウントを作りました!

いまなら学習に役立つ限定音声コンテンツ73本や、YouTubeで使えるソースコードをプレゼントしています。

無料で追加できるので、よかったら友達になってください!

\ 無料で使えるソースコードをプレゼント /

目次

Flaskアプリ開発① : Webアプリを作るための準備をする

まずは、Flaskアプリを作成するための準備をしていきましょう。

主にやることは以下のとおりです。

  • Flaskアプリ用のフォルダ作成
  • 仮想環境の作成
  • 必要なライブラリのインストール

一つずつ解説していきます。

Flaskアプリ用のフォルダ作成

今回はデスクトップにflask-todo-appという名前でフォルダを作成しましょう。

Flask Todoアプリ1

フォルダの作成が完了したら、VSCodeを起動してflask-todo-appを開きます。

ここで、エディター内のターミナルを開いて現在地を確認しておきましょう。

# Macの場合
$ pwd

# Windowsの場合
$ cd

僕はMacを使っていますので、以下のようになります。

$ pwd
# /Users/hayato/Desktop/flask-todo-app

これでフォルダ作成の準備が完了しました。

仮想環境の作成

次に仮想環境を作成していきます。

先ほど起動したエディタ内のターミナルで、以下のコマンドを実行しましょう。

$ virtualenv env

もしvirtualenvが入っていなければ、以下のコマンドでインストールします。

# Anaconda Version
$ conda install virtualenv

# Python Version
$ pip install virtualenv

上記のコマンドでインストールしたら、もう一度virtualenv envを実行してみてください。

無事にvirtualenvを実行できたら、フォルダが作成できたか確認します。

# Macの場合
$ ls

# Windowsの場合
$ dir

コマンドを実行した結果、envというフォルダを確認できれば大丈夫です。

$ ls
# env

これで仮想環境を作成できました。

必要なライブラリのインストール

今回のWebアプリ開発では、以下のライブラリが必要です。

  • Flask : もちろん必須です。
  • Flask-SQLAlchemy : データベース操作に使います。

さっそく、上記のライブラリをインストールしていきましょう!

と言いたいところですが…、まずは仮想環境を有効化する必要があります。

以下のコマンドをターミナルに入力して、仮想環境を有効化しましょう。

# Macの場合
$ source env/bin/activate

# Windowsの場合
$ env\Scripts\activate

仮想環境を有効化できると、ターミナルの見た目が少し変わります。

それでは下記コマンドをターミナルに入力して、ライブラリをインストールしましょう。

$ pip install flask flask-sqlalchemy

インストールが完了すると、「Successfully installed ライブラリ」と表示されます。

もし「WARNING: You are using pip version…」という警告が出てきたら、指示されているとおりにpipをアップグレードしてあげましょう。

$ pip install --upgrade pip

上記を実行したところ、僕はpipのバージョンが20.1→20.2.3に変更されました。

STEP2 : Flaskを使って、Hello Worldを表示する

まずはFlaskに慣れるべく、Hello Worldを表示するアプリを作成してみましょう。

app.pyの編集

app.pyというファイルを作成して、以下のコードを書いてみます。

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Hello World'

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

ここまで書いたら、以下のコマンドでPythonファイルを実行します。

$ python app.py

また、Pythonを実行するときは、Pythonのインタプリタが、先ほど作成した仮想環境になっているか確認しましょう。

Flask Todoアプリ10

もしenvになっていない場合には、赤枠をクリックすれば下のような画面になります。

Flask Todoアプリ11

そこからenvのPythonを選んであげましょう。

実際にPythonファイルを実行すると、以下のような出力になるはずです。

Flask Todoアプリ12

※途中で出ているWARNINGは、「開発モードになっているから、本番では注意してね!」って意味です。今は気にしなくて大丈夫ですよ。

正常に起動できたら、ブラウザでlocalhost:5000にアクセスしましょう。

そうすると、Hello Worldと書かれた画面が出てくるはずです。

Flask Todoアプリ13

これで、Flaskを使ったHello Worldアプリが完成しました。

たった10行のコードでアプリを作成できるので、Flask恐るべしですね、、、。

見出しを付けて、Hello Worldを表示

Hello Worldが表示されているページのHTMLを見てみると、以下のようになっています。

Flask Todoアプリ14

これは、<body>タグの中にHello Worldが書かれている状態ですね。

Pythonでreturn 'Hello World'と書いていたので、当たり前といえば当たり前です。

それでは、以下のようにコードを変更すると、どうなるでしょうか。

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return '<h1>Hello World</h1>' # 変更

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

Hello Worldを<h1>タグで囲ってあげました。これを保存して、ブラウザをもう一度確認してみたいと思います。

Flask Todoアプリ15

さっきまでとは違い、Hello Worldが見出しになって表示されるようになりました。

HTMLを確認しても、<h1>タグで囲まれていることが分かります。

Flask Todoアプリ16

つまり、「returnの後にHTMLを書くと、ページを作成できる」ということが分かりました。

Pythonはバックスラッシュを使えば文字列の改行ができますので、returnの後にひたすら文字列を書いてページ作成することが可能です。

STEP3 : render_templateを使って、HTMLを表示する

HTMLタグを含んだ文字列を書いてあげれば、物理的にはページ作成できることが分かりました。

でもPythonファイルに、HTMLの文字列を書き連ねるのは得策ではありません。

フロント部分はHTMLファイルに書き、PythonではHTMLファイルを表示するバックエンドの処理だけ書いてあげるのが望ましい形です。

というわけで、まずはHTMLファイルを作成してあげましょう。

新しくtemplatesというフォルダを作成して、その中にindex.htmlを作成します。

まずはフォルダを作成していきましょう。VSCodeで以下の部分をクリックすれば、フォルダを作成できます。

Flask Todoアプリ17

さらに、作成したフォルダを右クリックして、新しいファイルを作成しましょう。

Flask Todoアプリ18
Flask Todoアプリ19

index.htmlの中身には、以下を書いてあげます。※return後に書いていたことを、HTMLファイルで書き直しただけです。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Hello World</h1>
</body>
</html>

ここまで書けたら、後はPythonで表示するロジックを書くわけですが、そのためにはrender_templateを使ってあげます。

Pythonファイルの中身を、以下のように書き換えてあげましょう。

from flask import Flask, render_template # 追加

app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html') # 変更

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

render_templateをインポートして、少し変更を加えました。

これで、もう一度Pythonファイルを実行してみましょう。※すでに実行済みなら、保存してブラウザ更新で大丈夫です

そうすると以下のように、HTMLファイルを表示する形に変更できているかと思います。

Flask Todoアプリ20

分かりづらければ、HTMLファイルの中身を少し変更してみましょう。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 以下を変更 -->
    <h1>Hello World2</h1> 
</body>
</html>

変更を保存して、ブラウザを更新してみます。

Flask Todoアプリ21

上のように、変更がしっかりと反映されていることが分かりますね。

これで、HTMLを表示する部分が完成しました。だんだんアプリ作成らしくなってきましたね。

STEP4 : 共通テンプレート(base.html)の作成

たとえば、「See you」と書かれたページを追加で準備したいとき、どんなHTMLを書くでしょうか。

おそらく思いつくのは、以下のようなHTMLを記述することですよね。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>See you</h1> 
</body>
</html>

上記のようなコードを記述すれば、当たり前ですが、新しく「See you」が表示されるページを作成できます。

ただ、これって、少し冗長になってしまいますよね。というのも、先ほど書いていたコードと見比べてみると明らかです。

Diff Checkerというツールを使って、先ほどのコードと「See you」を表示するコードを見比べてみました。

Flask Todoアプリ22

そうすると、1行違うだけで、ほぼ同じコードであることが分かります。言い方を換えると、<h1>タグ以外は同じ構造を持つということです。

このような場合に、Flaskでは基盤になるHTMLを準備して、そのファイルを他のHTMLに継承させることができます。

Pythonで言えば、Classに似ていますよね。基底クラスを準備して、そのクラスを継承するイメージです。

というわけで、さっそく基盤になるテンプレートを準備していきましょう。

base.htmlを作成して、いまindex.htmlに記述していた内容を書き写したいと思います。

要するに、以下のような状況になっています。

Flask Todoアプリ23

この状態から、以下のようにコードを書き換えます。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    {% block head %}{% endblock %}
</head>

<body>
    {% block body %}{% endblock %}
</body>

</html>

変更した点は、以下のとおりです。

  • <head>部分に、{% block head %}{% endblock %}が増えた
  • <body>部分に、{% block body %}{% endblock %}が増えた
  • <h1>Hello World</h1>を削除した

こうすることで、基盤になるHTMLファイルを作成することができました。

あとは、何も書かれていないindex.htmlを編集していくだけです。以下の5行を書いてみましょう。

{% extends 'base.html' %}

{% block body %}
<h1>extended!!!</h1>
{% endblock %}

上記のように編集できたら、サーバーを立ち上げ(=python app.pyを実行し)て表示を確認してみます。

Flask Todoアプリ24

そうすると、このように「extended!!!」が表示されているはずです。

ページのHTMLを見てみると、base.htmlで書いていた内容を、しっかりと反映できていることが分かります。

Flask Todoアプリ25

今後、色々なHTMLファイルを追加していきます。

そのときも同様に、base.htmlを拡張してあげれば、少ないコードでページを追加できるってわけですね。

STEP5 : データベースの準備

Todoアプリに書いたタスクを保存しておくために、データベースを準備していきましょう。

今回作成するTodoアプリでは、以下のようなデータを持っておきたいと思います。

  • id : 基本的に、今回に限らず必要になります。
  • title : タスクに名付けるタイトルです。
  • detail : タスクの詳細部分を書いていきます。
  • due : タスクには期限も設けておきましょう。

上記の項目ですね。もちろん他に追加できる、もしくは変更できる点があると思います。

その辺りはご自身で好きにアレンジを加えてみてください。

また、データベースには色々な種類がありますが、今回はSQLiteを使っていきます。

※SQLiteについては、今回のスコープ外とさせてください。ネット上に、参考になる記事がたくさんあります。

それでは、データベースの準備をしていきましょう。

まずは、app.pyに以下のコードを追加します。

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
db = SQLAlchemy(app)

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

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

コードを増やした部分だけピックアップすると、以下のとおりです。

from flask_sqlalchemy import SQLAlchemy

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
db = SQLAlchemy(app)

このflask-sqlalchemyは、Flaskと一緒にインストールしておいたライブラリです。

flask-sqlalchemyを使うと、Pythonオブジェクトのようにデータベースを扱うことができます。

実際に、データベースの項目定義をおこなっていきましょう。

以下のコードを、app.pyに追加します。

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(30), nullable=False)
    detail = db.Column(db.String(100))
    due = db.Column(db.DateTime, nullable=False)

どこに追加すれば良いのか分からない方向けに!コードの全体像は、以下のようになります。

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
db = SQLAlchemy(app)


class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(30), nullable=False)
    detail = db.Column(db.String(100))
    due = db.Column(db.DateTime, nullable=False)

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

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

上記のとおりです。追加した部分を、少し深掘りします。

データベースのURI設定

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
db = SQLAlchemy(app)

上記を書くことで、todo.dbという名前のデータベースを設定しています。

データベースの作成をしたときには、todo.dbという名前になるってことですね。

そのあとで、SQLAlchemy()内にappを入れて、dbを生成します。

データベースの項目定義

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(30), nullable=False)
    detail = db.Column(db.String(100))
    due = db.Column(db.DateTime, nullable=False)

データベースで使う項目は、Pythonのクラスオブジェクトで定義できます。

それぞれの項目は、以下のように設定しました。

  • id : 整数値で設定しています。また、主キーに設定しました。
  • title : 30字以内の文字列で設定しています。空にするのはNGです。
  • detail : 100字以内の文字列で設定しています。こちらは空でもOKです。
  • due : 日付型で設定しています。期限空はNGです。

上記ですね。

detailに関しては、空でもOKにしました。というのも、titleだけ見ればどんなタスクか分かると思うので。

あくまで補助的な機能ということにしておきます。

ここまで書けたら、いま定義したデータベースを作成していきます。

VSCodeでターミナルを開いて、Pythonの対話型シェルを起動しましょう。

まずVSCodeでターミナルを開くには、上のタブからターミナルを選択してあげます。

Flask Todoアプリ27

ターミナルを開いたら、pythonと入力して対話型シェルを起動してあげます。

対話型シェルになったら、以下のコマンドを入力しましょう。

>>> from app import db
>>> db.create_all()

>>>は対話型シェルを表しているだけで、実際に入力する必要はありません。

ここまでのところをキャプチャしたのが以下です。

Flask Todoアプリ26

問題なく実行できていれば、todo.dbが作成されているはずです(`・ω・´)!

Flask Todoアプリ28

そうしたら、もうターミナルは使わないので閉じてしまいましょう。

以下を入力します。

>>> exit()

これでデータベースの準備ができました。

あとは「追加したタスクの内容を、データベースに保存するコード」を書けばOKですね!

STEP6 : タスク作成ページとルーティング設定

前のステップでは、タスクを保存するためのデータベースを準備しました。

今回は、タスクを追加できるようにするために、Todoの作成ページを作っていきます。

新しくcreate.htmlを作成して、以下のコードを書いていきましょう。

{% extends 'base.html' %}

{% block body %}
<div class="form">
    <form action="/" method="POST">
        <label for="title">Title</label>
        <input type="text" name="title">
        <label for="detail">Detail</label>
        <input type="text" name="detail">
        <label for="due">Due</label>
        <input type="date" name="due" required>
        <input type="submit" value="Create">
    </form>
</div>
{% endblock %}

これは純粋にHTMLのコードになります。

Pythonとは少し離れた内容になるので、細かい部分は割愛しますが、これで必要な項目を入力するフォームが完成します。

各値を入力してsubmitすると、そのデータをトップページにPOSTするようになっています。

と、フォームの見た目は作成できましたが、まだこのページにアクセスできません。タスクを作成するページにアクセスするには、Python側で「ルーティング」する必要があります。

app.pyに戻って、以下のコードを追加してあげましょう。

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

これはトップページへのアクセスを可能にしたときと同じコードですね。

今回であれば、https://〇〇.com/createにアクセスすれば作成ページを開けるようになります。手元のパソコンで開発している間は、localhost:5000/createですね。

というわけで、サーバーを起動してタスク作成ページにアクセスしてみましょう。

Flask Todoアプリ29

このように、タスク作成に必要な内容を入力できるページに遷移しました。

試しに、フォームにタスクを書いてみましょう。

Flask Todoアプリ30

この状態でCreateをクリックしてみます。

そうすると、以下のようなエラー画面になるはず。

Flask Todoアプリ31

なぜこのような画面になるのかといえば、それはフォームのアクセス先の設定が原因です。

というのも、フォーム送信の宛先はaction="/"でトップページになっていますが、そのトップページではPOSTを受けられる状態になっていません。

言い換えると、GETしか受け取れない状態になっています。

そこで、トップページにルーティングしている関数のデコレータ部分を、少し変更してあげます。

@app.route('/') # 元々はこれだったけど
@app.route('/', methods=['GET', 'POST']) # こちらに変更

上記のように書き換えることで、トップページでPOSTメソッドを受け入れる準備ができました。

なので、もう一度/createにアクセスして、タスクを入力して送信してみましょう。

そうすると、元の画面に戻ってこれるはず。少し現状を整理すると、以下のとおりです。

  • /createページにアクセスして、タスクを作成できるようになった
  • タスク作成後は、トップページ(localhost:5000)に繊維できるようになった
  • でも、入力したタスクを保存、および表示はできていない

このような状況ですよね。

なので、あとはトップページのコードを変更してあげて、「①データベースにタスクを保存②保存されているタスクを表示する」を実装すれば良さそうです。

STEP7 : タスクの保存と表示

前のステップで、以下の内容を実装すれば良いことが分かりました。

  • ①データベースにタスクを保存
  • ②保存されているタスクを表示する

これをトップページで実装したいので、以下のコードを編集していけばOKですね。

@app.route('/', methods=['GET', 'POST'])
def index():
    return render_template('index.html')

追加のインポート

まずは、追加で以下をimportしましょう。

from flask import Flask, render_template # これだけだったけど、
from flask import Flask, render_template, request, redirect # 追加で2つimportする

これらが必要になる理由ですが、これから追加したい内容は以下でした。

  • ①データベースにタスクを保存
  • ②保存されているタスクを表示する

そして、これらの実装は、リクエストメソッドによって対応が変わってきますよね。

具体的に言うと、以下のような挙動になるはずです。

  • POSTメソッドのとき : データベースにタスクを保存
  • GETメソッドのとき : 保存されているタスクを表示する

このように、リクエスト方法に応じて実装内容を変更していくために、requestが必要になります。

またredirectは、POSTで受け取った内容をデータベースに反映したあとに、もう一度トップページへアクセスするために使います。

コードの編集

それでは、タスクの保存と表示をするコードを書いていきましょう。

結論、以下のように編集してあげます。

from datetime import datetime

# <-----中略----->

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        posts = Post.query.all()
        return render_template('index.html', posts=posts)

    else:
        title = request.form.get('title')
        detail = request.form.get('detail')
        due = request.form.get('due')
        
        due = datetime.strptime(due, '%Y-%m-%d')
        new_post = Post(title=title, detail=detail, due=due)

        db.session.add(new_post)
        db.session.commit()
        return redirect('/')

GETとPOSTに分解して、考えてみたいと思います。

まずはGETから。

if request.method == 'GET':
    posts = Post.query.all()
    return render_template('index.html', posts=posts)

GETの部分でやっていることは、「データベースからすべての投稿を取り出し(Post.query.all())、それをトップページに渡してあげる」です。

トップページに投稿をわたすってどういうこと…?」と思われるかもですが、これからHTMLを編集していけば分かるはずです。

とりあえずPython側だけ理解しておきましょう(`・ω・´)!

次にPOSTです。

else:
    title = request.form.get('title')
    detail = request.form.get('detail')
    due = request.form.get('due')

    due = datetime.strptime(due, '%Y-%m-%d')
    new_post = Post(title=title, detail=detail, due=due)

    db.session.add(new_post)
    db.session.commit()
    return redirect('/')

もしリクエスト方法がPOSTなら、データベースに投稿を保存してあげます。

上記でやっていることは、主に3つです。

  • ① : POSTされた内容を受けとる
  • ② : Postクラスに受け取った内容を渡す
  • ③ : データベースに投稿を保存する

上記がデータベースへ投稿するまでのステップです。

データベースへ保存するときは、まずaddで内容を追加して、実際に反映するためにcommitします。

また、途中でdueをキャスト(型変換)している部分があります。これは、データベースの定義で日付型を指定していたけど、フォームから受け取る値が文字列だからです。よって、Python上で文字列→日付型にキャストしています。

これでPython側でやることは完了したので、あとは投稿内容を反映するためにHTMLを変更していきます。

index.htmlを以下のように変更しましょう。

{% extends 'base.html' %}

{% block body %}
<h1>トップページ</h1>
{% for post in posts %}
    <h2>タイトル : {{ post.title }}</h2>
    <p>期限 : {{ post.due.date() }}</p>
{% endfor %}
{% endblock %}

このように書くことで、投稿内容を表示できるようになります。

{% for post in posts %}{% endfor %}で、先ほどPythonから渡しておいた投稿たちをfor loopしています。

さらに、ループしたpostに入っているタイトルをpost.title、日付をpost.due.date()のように書けば中身を取り出せます。

なお、表示したい変数部分は、{{ 変数名 }}のように書きます。波カッコが2つ付くことに注意しましょう。

これで、サーバーを立ち上げて、/createにアクセスして、タスクを作成したいと思います。

Flask Todoアプリ30

Createを押してみます。

Flask Todoアプリ32

このように、今回はタスクを作成すると、トップページに遷移しつつ投稿内容が表示されるようになりました。

さらにタスクを追加すれば、ちゃんと2つとも表示されるようになります。

Flask Todoアプリ33

これでタスクを作成と表示ができるようになりました!

これだけでも、だいぶアプリケーションらしくなってきましたね。

投稿の作成(Create)に加えて、あとは以下の実装を加えたいと思います。

  • 投稿の詳細を確認(Read)する
  • 投稿を編集(Update)する
  • 投稿を削除(Delete)する
  • 見た目を整える

現状だと、終わったタスクを削除したり、または変更を加えたりする機能がありません。

また、トップページではタイトルしか見えていないので、タスクの詳細を見れるページを作成していきましょう。

STEP8 : タスクの詳細を表示するページの作成

タスクの詳細を表示するには、PythonとHTMLの両方を編集する必要があります。

まずは、Python側からコードを追加していきましょう。

Pythonファイル(app.py)の編集

タスクの詳細を表示するためにPythonでやることは、以下のコード追加だけです。

@app.route('/detail/<int:id>')
def read(id):
    post = Post.query.get(id)

    return render_template('detail.html', post=post)

全体を確認しておくと、以下のようになっています。

from datetime import datetime

from flask import Flask, render_template, request, redirect
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
db = SQLAlchemy(app)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(30), nullable=False)
    detail = db.Column(db.String(100))
    due = db.Column(db.DateTime, nullable=False)


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        posts = Post.query.all()
        return render_template('index.html', posts=posts)

    else:
        title = request.form.get('title')
        detail = request.form.get('detail')
        due = request.form.get('due')

        due = datetime.strptime(due, '%Y-%m-%d')
        new_post = Post(title=title, detail=detail, due=due)

        db.session.add(new_post)
        db.session.commit()
        return redirect('/')


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


@app.route('/detail/<int:id>')
def read(id):
    post = Post.query.get(id)

    return render_template('detail.html', post=post)


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


詳細ページにアクセスするためには、「どの投稿の詳細ページを開くのか」を指定する必要があります。

そのため、URLは/detailではなく、/detail/<int:id>と指定しましょう。

「え、idってなんですか…?」と思われるかもしれないですが、これはテーブルを作成するときに定義しました。

作成したフォームにはidを指定しませんでしたが、データベースにタスクを登録するとき、自動的に番号は割り振られています。

post = Post.query.get(id)を使うことで、該当するidの投稿内容を取得し、そのタスクをdetail.htmlに渡しているということですね。

Pythonで処理する部分は、たったこれだけです。あとはHTML側に変更を加えていきましょう。

HTMLファイルの編集(index.htmlとdetail.html)

まずはdetail.htmlのファイル作成をしていきます。

ファイルの作成ができたら、以下のコードを書いてあげましょう。

{% extends 'base.html' %}

{% block body %}
<h2>詳細</h2>

<h2>{{ post.title }}</h2>
<p>{{ post.detail }}</p>
<p>{{ post.due.date() }}</p>

{% endblock %}

index.htmlではfor loopを使って投稿内容を表示していましたが、今回はpostだけです。なぜなら、Pythonから渡される投稿が、常に1つだからです。

これで詳細を表示するページの作成もできました。

あとは、index.htmlも少し編集してあげましょう。

「なぜindex.htmlの編集をするんですか…?」と聞かれるかもです。それは、各投稿ごとに詳細ページへのリンクを設置したいからです。

以下のように、詳細ページへ飛べるURLを設置してあげましょう。

{% extends 'base.html' %}

{% block body %}
<h1>トップページ</h1>
{% for post in posts %}
    <h2>タイトル : {{ post.title }}</h2>
    <p>期限 : {{ post.due.date() }}</p>
    <a href="/detail/{{ post.id }}" role="button">Detail</a>
{% endfor %}
{% endblock %}

追加したのは、<a>タグの部分だけです。

postに含まれているidをURL部分に書いてあげることで、それぞれの投稿に対応する詳細ページへアクセスできるようになります。

※タグの中といえど、postの中身を使うには、{{  }}のように波カッコを2つ付けます。

これで準備が整いました。コードを保存して、まずはトップページへアクセスしましょう。

Flask Todoアプリ34

そうすると、上のように詳細ページへのリンクが作成されています。実際にアクセスしてみましょう。

Flask Todoアプリ35

こちらのように、最初に作成したタスクはlocalhost:5000/detail/1のURLになってアクセスできるようになりました。

もう一つ作成しておいたタスクがあるので、そちらにもアクセスしてみましょう。

Flask Todoアプリ36

こちらのタスクは、localhost:5000/detail/2でアクセスできました。

タスクによってidが異なっていて、別々の詳細ページを表示できていることが分かりますね。

あとはTodoアプリが無法地帯にならないように、編集する機能と削除する機能を付け足していきましょう。

STEP9 : タスクを削除する

タスクを追加し放題の無法地帯を避けるべく、タスクを削除する機能を付けていきましょう。

タスクの削除については、新しいページを追加せずに、トップページから行えるようにすれば良いですね。

app.pyに、以下のコードを追加していきましょう。

@app.route('/delete/<int:id>')
def delete(id):
    post = Post.query.get(id)

    db.session.delete(post)
    db.session.commit()
    return redirect('/')

タスクを追加するときは、commit()する前にaddをおこなっていました。

今回はタスクを削除していきますので、「delete()を使ってあげれば良い」ということは、直感的にも分かりますね。

データベースの処理が終わったら、トップページへリダイレクトしてあげます。

app.pyのコード全体で確認すると、以下のようになりますね。

from datetime import datetime

from flask import Flask, render_template, request, redirect
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///todo.db'
db = SQLAlchemy(app)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(30), nullable=False)
    detail = db.Column(db.String(100))
    due = db.Column(db.DateTime, nullable=False)


@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        posts = Post.query.all()
        return render_template('index.html', posts=posts)

    else:
        title = request.form.get('title')
        detail = request.form.get('detail')
        due = request.form.get('due')

        due = datetime.strptime(due, '%Y-%m-%d')
        new_post = Post(title=title, detail=detail, due=due)

        db.session.add(new_post)
        db.session.commit()
        return redirect('/')


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


@app.route('/detail/<int:id>')
def read(id):
    post = Post.query.get(id)

    return render_template('detail.html', post=post)


@app.route('/delete/<int:id>')
def delete(id):
    post = Post.query.get(id)

    db.session.delete(post)
    db.session.commit()
    return redirect('/')


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


あとはトップの一覧ページで、投稿を削除するためのURLを追加すればOKです。

これはdetailとほぼ同じで大丈夫ですね。

{% extends 'base.html' %}

{% block body %}
<h1>トップページ</h1>
{% for post in posts %}
    <h2>タイトル : {{ post.title }}</h2>
    <p>期限 : {{ post.due.date() }}</p>
    <a href="/detail/{{ post.id }}" role="button">Detail</a>
    <a href="/delete/{{ post.id }}" role="button">Delete</a>
{% endfor %}
{% endblock %}

このようにdeleteを追加してあげましょう。

コードを保存したら、トップページを確認してあげます。

Flask Todoアプリ37

そうすると、上の画像のように削除ボタンが追加されました。

試しに削除するリンクをクリックしてみましょう。

Flask Todoアプリ38

僕は「スタバに行く」タスクを削除してみました。

※どうでも良いですが、この記事を書いている日は、ちゃんとスタバに行ったのでタスク完了しています(`・ω・´)!笑

というわけで、削除する機能の実装も完了しました。あとは、投稿の変更(Update)だけですね。

STEP10 : タスクを編集(アップデート)する

間違えてタスクを作成してしまったり、あとからメモとして詳細に書き加えたいときがあるかと思います。

なので、作成したタスクの内容を変更できるようにしましょう。

まずは、app.pyに以下のコードを追加してあげます。

@app.route('/update/<int:id>', methods=['GET', 'POST'])
def update(id):
    post = Post.query.get(id)
    if request.method == 'GET':
        return render_template('update.html', post=post)
    else:
        post.title = request.form.get('title')
        post.detail = request.form.get('detail')
        post.due = datetime.strptime(request.form.get('due'), '%Y-%m-%d')

        db.session.commit()
        return redirect('/')

編集するページは、/update/◯にアクセスがあったとき、以下のような挙動になることが望ましいです。

  • GETメソッドのとき : 今まで書かれていた内容を表示
  • POSTメソッドのとき : 変更内容を更新する

なので、Pythonファイルでも、GETとPOSTで挙動を変えてあります。

POSTするとき、今まではadddeleteを使っていましたが、今回は投稿内容を編集するだけです。

よって、編集した内容をフォームから受け取ったら、そのままcommit()してあげます。

あとはupdate.htmlを作成していきましょう。フォームを実装するので、コードはcreate.htmlとほとんど変わりません。

{% extends 'base.html' %}

{% block body %}
<h2>編集</h2>
<div class="form">
    <form action="/update/{{ post.id }}" method='POST'>
        <label for="title">Title</label>
        <input type="text" name="title" value={{ post.title }}>
        <label for="detail">Detail</label>
        <input type="text" name="detail" value={{ post.detail }}>
        <label for="due">Due</label>
        <input type="date" name="due" value={{ post.due.date() }} required>
        <input type="submit" value="Change">
    </form>
</div>
{% endblock %}

create.htmlとの違いは、actionで飛ばすURLですね。

このページから投稿を編集したとき、以下のような動きになります。

  • ① : フォームでタスクを編集する
  • ② : 編集した内容がPythonのupdate関数にいく
  • ③ : update関数のPOSTメソッド側の処理(=更新)が行われる

index.htmlに、投稿を編集するためのリンクを設置して、実際にタスクをアップデートしてみましょう。

index.htmlに追加する中身は、detaildelete同様です。

{% extends 'base.html' %}

{% block body %}
<h1>トップページ</h1>
{% for post in posts %}
    <h2>タイトル : {{ post.title }}</h2>
    <p>期限 : {{ post.due.date() }}</p>
    <a href="/detail/{{ post.id }}" role="button">Detail</a>
    <a href="/update/{{ post.id }}" role="button">Update</a>
    <a href="/delete/{{ post.id }}" role="button">Delete</a>
{% endfor %}
{% endblock %}

これでコードを保存して、ブラウザにアクセスします。

Flask Todoアプリ39

そうすると新しくupdateボタンが作成されました。クリックすると、以下のように、元の投稿内容がフォーム内に入っています。

Flask Todoアプリ40

あとはこの中身を編集してみましょう。僕は簡単のため「プログラミング学習をする2」に変更してみました。

Flask Todoアプリ41

トップページに戻るようredirectしておいたので、編集した内容が反映された状態で、タスク一覧が見れるかと思います。

Flask Todoアプリ42

しっかりと変更内容が反映された形で、タスクを見れるようになりましたね。

これで、Todoアプリの基本的な部分が完成しました。

あとは細かい調整をしてあげて、フロント部分を整えていきましょう。

STEP11 : トップページの細かい調整

いまのアプリだと、 手打ちで/createを検索しないとタスクを作成できません。

これだと不便極まりないので、トップページからタスクを作成する画面に遷移できるようにしましょう。

また、現状タスクの表示方法が”作成日順”になっています。ただ、タスクは”締切が近い順”にした方が使いやすいですよね。

なので、これら2点の編集を付け加えていきます。

タスクを作成するボタンの設置

タスクを作成するボタンの追加はカンタンで、「詳細・編集・削除」で使っていた<a>タグを少し編集するだけでOKです。

タスクを表示しているfor loopの前に、作成ボタンを設置しましょう。

{% extends 'base.html' %}

{% block body %}
<h1>トップページ</h1>
<a href="/create" role="button">CREATE NEW TASK</a>
{% for post in posts %}
    <h2>タイトル : {{ post.title }}</h2>
    <p>期限 : {{ post.due.date() }}</p>
    <a href="/detail/{{ post.id }}" role="button">Detail</a>
    <a href="/update/{{ post.id }}" role="button">Update</a>
    <a href="/delete/{{ post.id }}" role="button">Delete</a>
{% endfor %}
{% endblock %}

これでOKですね。

あとは、コードを保存してブラウザを確認してみます。

Flask Todoアプリ43

こんな感じで、タスクを作成するボタンが設置できています。ちゃんとアクセスできるか確認しましょう。作成ボタンをクリックします。

Flask Todoアプリ44

しっかりタスク作成する画面に遷移しました。これで、前よりも便利なTodoアプリになりましたね。

タスクを締切が近い順に並べる

少しタスクを追加してみました。タスクの期限を見ていただきたいのですが、現状だと並び順がバラバラで非常に使いにくいです。

Flask Todoアプリ45

これを締切が近い順に変更していきましょう。

今回編集するコードは、Python側になります。

これも編集はカンタンで、以下の1行だけコードを変更します。

posts = Post.query.all() # このコードを
posts = Post.query.order_by(Post.due).all() # こちらに変更

上記のように変更することで、締切が近い順に変更できました。

実際にコードを保存して、アプリのトップページを見てみましょう。

Flask Todoアプリ46

このように、タスクの締切が近い順に変更できました。これで、締切が近いタスクから消化できますね!

STEP12 : BootStrapを使って、見た目を整える

現状のTodoアプリだと、まったく持って見た目がイケていません。笑

ただ、自分で一からCSSを当てていくのも面倒ですので、今回はBootStrapを使ってサクッといい感じのアプリを作っていきましょう。

BootStrapのダウンロード

まずはBootStrapの公式ページから、必要なファイルをダウンロードしてきます。

»参考 : Bootstrap – 世界で最も人気のあるフロントエンドのコンポーネントライブラリ

トップページから、ダウンロードボタンを押して、次の画面に進みます。

Flask Todoアプリ47

今回使うのは、コンパイル済みのファイルですので、以下の赤枠をクリックしてファイルをダウンロードでOKです。

Flask Todoアプリ48

そうすると、以下のようなzipファイルをダウンロードできます。こちらを解凍しましょう。

Flask Todoアプリ49

解凍したフォルダの中身を見てみると、cssjsが入っています。今回はCSSだけ当てていくので、jsは不要です。

中身の確認ができたところで、自分たちが作っていたFlaskアプリのフォルダに戻りましょう。

Flask Todoアプリ50

現状は上の画像のようになっていますので、ここでstaticフォルダを作成します。

Flask Todoアプリ51

作成できたら、先ほどダウンロードしてきたBootStrapのcssだけFlaskアプリ側に移しておきましょう。

Flask Todoアプリ52

これでBootStrapのダウンロードが完了しました。

CSSを使う準備

FlaskでCSSを使うには、Python側とHTML側で少し準備が必要です。

先にPython側から追加部分を書いていきましょう。といっても、やることはシンプルで、importするものを増やすだけです。

from flask import Flask, render_template, request, redirect # ここの部分で
from flask import Flask, render_template, request, redirect, url_for # url_forを追加する

url_forはHTMLファイルでCSSを読み込むときに使います。

というわけで、あとはHTMLの編集ですが、こちらは通常のCSS読み込みとあまり変わりません。

base.html<head>部分に、以下を追記しましょう。

<link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.min.css') }}">

これでBootStrapのCSSを使えるようになります。変更したコードを保存して、トップページを確認してみましょう。

こちらは変更前です。

Flask Todoアプリ53

それに対してこちらが変更後。

Flask Todoアプリ54

このように、BootStrapを読み込めていると、見た目が少し変わった状態になります。

BootStrapは、すでに準備されているclassを指定することで使用できます。

※ここでBootStrapについて詳しく書いていると、それだけで分量が大変なことになりますので、割愛させていただきますm(_ _)m

共通部分(base.html)の編集

まずは、どのページでも共通で使う部分をbase.htmlに書いていきます。

今回はナビゲーションだけ全てのページで共通にしたいので、以下のようなコードに変更しましょう。

<!DOCTYPE html>
<html lang="ja">

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

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

</html>

»参考 : Navbar – Bootstrap 4.5 – 日本語リファレンス

公式ドキュメントに載っているコードを、ほぼそのままコピペで作成しています(`・ω・´)!笑

変更したコードを保存して、ブラウザを確認してみましょう。

Flask Todoアプリ55

画面上部分に、ナビゲーションが追加されていますね。

CREATE NEW TASKをクリックして画面を遷移してみても、ナビゲーションが付いていることが分かります。

トップページ(index.html)の編集

次はトップページの編集をしていきます。

トップページでは、単純にCSSを当てるだけでなく、「タスクの期限が切れていたら、注意表示する」機能を付け加えたいと思います。

先にHTMLだけ書いておくと、以下のとおりです。

{% extends 'base.html' %}

{% block body %}
<div class="container">
    <a class="btn btn-info btn-lg m-5" href="/create" role="button">CREATE NEW TASK</a>
    {% for post in posts %}
    <div class="card w-50 mb-3" style="margin: auto;">
        <div class="card-body">
            {% if post.due.date() < today %}
            <div class="alert alert-warning" role="alert">
                期限切れです!
            </div>
            {% endif %}
            <h2 class="card-title">{{ post.title }}</h2>
            <p>期限:{{ post.due.date() }}</p>
            <a class="btn btn-secondary btn-sm" href="/detail/{{ post.id }}" role="button">Detail</a>
            <a class="btn btn-success btn-sm" href="/update/{{ post.id }}" role="button">Update</a>
            <a class="btn btn-danger btn-sm" href="/delete/{{ post.id }}" role="button">Delete</a>
        </div>
    </div>
    {% endfor %}
</div>

{% endblock %}

上記のコードで使っているBootStrapは、以下の3つですね。

前まではfor文だけ使っていましたが、今回はif文を使っています。

もしタスクの期限が切れていたら、「期限切れです!」というアラートを出力するようにしました。

あれ、if文に入っているtodayって何だろう…」と疑問に思ったかもしれません。

それは今からPythonのコードを編集して追加していきます。

トップページを表示するときにHTML側に渡していたのはpostsだけでしたが、新しくtodayも渡してあげましょう。

return render_template('index.html', posts=posts) # この部分を
return render_template('index.html', posts=posts, today=date.today()) # こちらに変更する

また、dateを使えるようにするために、importも追加してあげます。

from datetime import datetime # この部分を
from datetime import datetime, date # こちらに変更する

これで変更が完了しました。

コードを保存して、昨日までの日付で、タスクを作成してみてください。

Flask Todoアプリ56

僕の画面では、このようになりました。黄色い注意書きで、期限が切れていることを表示できていますね。

タスク作成(create.html)ページの編集

次はタスクを作成する画面の編集をしましょう。

使うコードは、以下のとおりです。

{% extends 'base.html' %}

{% block body %}
<h2 class="m-5">新規追加</h2>
<form class="m-5" action="/" 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">
        <small id="title-help" class="form-text text-muted">To doを入力してください。</small>
    </div>
    <div class="form-group pb-3">
        <label for="detail">Detail : </label>
        <input type="text" class="form-control" name="detail">
    </div>
    <div class="form-group pb-3">
        <label for="due">Due : </label>
        <input type="date" name="due" required>
    </div>
    <a class="btn btn-outline-primary" href="/" role="button">Return</a>
    <button type="submit" class="btn btn-primary">Create</button>
</form>

{% endblock %}

»参考 : Forms – Bootstrap 4.5 – 日本語リファレンス

BootStrapページに載っているコードを、ほとんどコピペして作っています。笑

タスクを編集するだけではなく、戻れるボタンも一緒に付け加えてみました。

コードを保存したら、タスクを作成する画面を見てみましょう。

Flask Todoアプリ57

そうすると、上のような画面になります。いい感じの見た目になりましたね!(BootStrapのおかげで!)

タスク編集(update.html)画面の編集

タスクを編集する画面は、作成ページとほとんど変わりません。

{% extends 'base.html' %}

{% block body %}
<h2 class="m-5">編集</h2>
<form class="m-5" action="/update/{{ post.id }}" 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.title }}>
    </div>
    <div class="form-group pb-3">
        <label for="detail">Detail : </label>
        <input type="text" class="form-control" name="detail" value={{ post.detail }}>
    </div>
    <div class="form-group pb-3">
        <label for="due">Due : </label>
        <input type="date" name="due" value={{ post.due.date() }} required>
    </div>
    <a class="btn btn-outline-primary" href="/" role="button">Return</a>
    <button type="submit" class="btn btn-primary">Change</button>
</form>
{% endblock %}

こんな感じです。

コードを保存して、見た目を確認してみましょう。

Flask Todoアプリ58

このように、タスク編集画面もキレイになりましたね!(BootStrapのおかげで!)

詳細画面(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.title }} <span class="ml-3"
                style="font-size: 0.5em;">期限:{{ post.due.date() }}</span></h2>
        <p>{{ post.detail }}</p>
        <div class="pt-2">
            <a class="btn btn-outline-success" href="/" role="button">Return</a>
            <a class="btn btn-success" href="/update/{{ post.id }}" role="button">Update</a>
        </div>
    </div>
</div>
{% endblock %}

投稿の詳細を確認できるのはもちろん、そのまま編集ページに遷移できるようにボタンを追加してみました。

コードを保存して、ブラウザを確認してみましょう。

Flask Todoアプリ59

こんな感じです。詳細確認ページもキレイな見た目になりましたね!(BootStrapのおかげで!)

これで見た目の変更も完了しました。

STEP13 : アプリをデプロイする

あとは、作成したアプリを公開するだけです。アプリの公開は、Herokuを使っていきます。

Flask Todoアプリ60

»参考 : Heroku公式ページ

アプリ公開に必要なものは、以下のとおりです。

  • Heroku CLI
  • Procfile
  • requirements.txt

順を追って、準備を進めていきましょう。

Heroku CLIをダウンロード

まずはHeroku CLIをダウンロード&インストールします。

Flask Todoアプリ61

画面に従って、ポチポチするだけで大丈夫です。おそらく、ほとんどの人は64bitだと思われます(`・ω・´)!

requirements.txtの作成

アプリを公開するには、requirements.txtを準備する必要があります。

まずは、アプリ公開に必要なgunicornをインストールしていきましょう。

$ pip install gunicorn

インストールが完了したら、いま入っているライブラリ一覧を確認します。pip freezeを入力していきましょう。

いまインストールしたgunicornも一緒に入っていますね。

そうしたら、これをrequirements.txtに書き起こします。

といっても、以下のコマンドを入力すればOKです!

$ pip freeze > requirements.txt

これで、アプリを公開するときに必要なライブラリ一覧を作成できました。

Procfileの作成

こちらはHerokuにデプロイするとき、必ず必要になります。

以下をコピペして、Procfileを作成しましょう。

web: gunicorn app:app --log-file=-

これだけでOKです!

gitリポジトリの準備

まずはapp.pyでデバッグモードにしていたので、これを外します。

# app.run(debug=True)
app.run() # こちらに変更

そうしたら必要なファイルが揃ったので、gitリポジトリを準備していきます。

VSCodeで以下のコードを実行していきましょう。

$ git init
$ git add .
$ git commit -m "first commit"

※Gitについては、今回のスコープ外とさせてください。

Herokuにログインして、サーバーの作成

VSCodeのターミナルで、以下のコマンドを入力してHerokuにログインします。

$ heroku login

入力すると、ブラウザが立ち上がって以下の画面に遷移します。

Flask Todoアプリ63

Log Inをクリックして、ログインを完了させましょう。以下の画面になれば成功です。

Flask Todoアプリ64

次にVSCodeのターミナルに戻って、以下のコマンドを実行します。

$ heroku create <アプリ名>

アプリ名の部分は、そのままURLに使われます。ゆえに他のアプリと重複していると、その名前は使えませんので、ユニークな名前にしてください!

僕はflask-todo-app-techdiaryにしました。成功すると、以下の画面になります。

Flask Todoアプリ65

アプリを公開する

あとは、アプリを公開するだけです。

いったん以下のコマンドを実行して、リモートリポジトリの設定が完了しているか確認してみましょう。

$ git remote -v

以下のようになっていれば、アプリを公開する準備が整っています。

Flask Todoアプリ66

あとはアプリの公開だけです。下記のコマンドを実行しましょう。

$ git push heroku master

※少し時間がかかるので、焦らずお待ちください(`・ω・´)!

pushが完了すると、以下のような画面になるかと思います。

Flask Todoアプリ67

そうしたら、heroku openをターミナルで実行するか、以下のURLにアクセスしてアプリが公開できているか確認しましょう。

https://<自分のアプリ名>.herokuapp.com/

僕の場合は、なんのエラーもなくアプリを公開することができました!

Flask Todoアプリ68

おそらく、はじめてアプリを公開するときは、上手くいかないことがあると思います。

そんなときは根気強く、色々調べながら頑張っていきましょう(`・ω・´)!

いきなり上手くいくことなんて、滅多にありませんから!笑

まとめ

というわけで、Flaskを使ったTodoアプリの開発方法を紹介しました。

このチュートリアルで学んだことを活かして、自分オリジナルのアプリを開発してみてください。

また、本格的にWebアプリ開発を学ぶなら、FlaskよりDjangoを学びましょう。

Djangoは国内・海外問わず採用する企業が多いので、市場価値の高いスキルを習得できますよ!

↓↓↓画像をクリックして「期間限定30%オフ」で購入する↓↓↓

参考 : 【知識ゼロからデプロイまで】 Django基礎マスターコース〜PythonでWebアプリを開発できるようになろう〜

SNSに投稿して読み返す
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

フリーランス(Python)/クリプト投資家/YouTuber3.23万人&Udemy講師(案件獲得者/転職者複数)/ 好きなブロックチェーンはAvalanche(アバランチ)です

目次