【初心者向き】pythonでユーザー新規登録をプログラムしよう
ログイン機能があるwebアプリには、必須の新規登録導線の作り方を紹介します。
これは、私が初心者の時にでも実施できた難易度ですので、これからpythonを学んでいこうと思っている初心者にピッタリの内容だと思います。
ぜひ、pythonの初めの一歩として、プログラムしていただけたらなと思います。
この記事は、以下記事の続きになります。別々でも理解できますが、併せてみるとより理解が深まると思います。
目次(クリックで読みたい部分にジャンプできます)
この記事で "できるもの"
今回コーディングしていくものは、ユーザーの新規登録導線を実装していきます。
ちなみに、以下のURLにおいて完成版があるので、見てみていただけたらと思います。
(無料サーバーなので、起動30秒くらいかかるかもです。m(__)m)
身に着けられるスキル
- DBへの登録・削除
- 新規登録の実装方法
- ログアウトの実装方法
DBはwebアプリには欠かせないものです。
静的なサイト以外であれば、ほとんどDBは使われているでしょう。
前回、すでにDBに登録してあるユーザーをチェックし、ログインするかどうかの判定をする実装をしました。
今回は、その続きで、DBにないユーザーを新規に加える導線を実装します。
全コード&解説範囲
今回取り扱うコードは以下になります。
(今理解する必要はなく、全体から見た今回の学習範囲を理解していただければ十分です。)
from flask import Flask, render_template, session, request, redirect, url_for,flash
import os
from pref_question import pref_location
from wiki import wiki
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
#インスタンスの作成
app = Flask(__name__)
key = os.urandom(21)
app.secret_key = key
#DBの準備(SQLiteを使う)
URI = 'sqlite:///note.db'#SQLIteを使ってnote.dbという名前のファイルを管理する。
app.config['SQLALCHEMY_DATABASE_URI'] = URI
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)#SQLAlchemyはインスタンスを作成し、変数DBに割り当てている。
#ORMでDBを操作するためにクラスを継承
class Note(db.Model):
__tablename__ = 'notes'
userid = db.Column(db.String(30),primary_key=True)
userpw = db.Column(db.String(300))
nicname = db.Column(db.String(300))
secretq1 = db.Column(db.String(300))
secretq1_answer = db.Column(db.String(300))
secretq2 = db.Column(db.String(300))
secretq2_answer = db.Column(db.String(300))
date = db.Column(db.DateTime, nullable=False, default=datetime.now())
#DBの生成
@app.cli.command('initialize_DB')
def initialize_DB():
db.create_all()
#メイン
@app.route('/')
def index():
if not session.get('login'):
return redirect(url_for('login'))
else:
return render_template('index.html')
@app.route('/login')
def login():
return render_template('login.html')
@app.route('/logincheck', methods=['POST'])
def logincheck():
user_id_pre = request.form['user_id']
user_pw_pre= request.form['password']
#DBから登録情報をチェック
org_data = Note.query.get(user_id_pre)
if not org_data:
session['login'] = False
flash('登録がありませんでした。。新規会員登録してください。')
else:
org_data_id = org_data.userid
org_data_pw = org_data.userpw
if user_pw_pre == org_data_pw:
session['login'] = True
else:
session['login'] = False
flash('パスワードが違います。')
if session['login']:
return render_template('index.html',user_nicname = org_data.nicname)
else:
return redirect(url_for('login'))
#<ーーーーーーーーー今回学習する範囲ここからーーーーーーーーーーーー>
@app.route('/registration', methods=['POST'])
def registration():
return render_template('new_registration.html')
@app.route('/registration_action',methods=['POST'])
def registration_action():
user_id_new = request.form['user_id_new']
user_pw_new = request.form['user_pw_new']
org_data = Note.query.get(user_id_new)
if not org_data:
if user_id_new:
if user_pw_new:
register_data=Note(userid=user_id_new,userpw=user_pw_new)
db.session.add(register_data)
db.session.commit()
return render_template('regist_nicname.html',user_id=user_id_new)
else:
flash('登録できませんでした。パスワードを入力してください')
return render_template('new_registration.html')
else:
flash('登録できませんでした。入力項目を確認してください。')
return render_template('new_registration.html')
else:
flash('このIDは登録されています')
return render_template('new_registration.html')
@app.route('/regist_nicname', methods=['POST'])
def regist_nicname():
org_userid = request.form['user_id']
org_data = Note.query.get(org_userid)
org_data.nicname = request.form['nicname']
if org_data.nicname:
db.session.merge(org_data)
db.session.commit()
flash('ニックネーム登録完了!(あと2ステップです)')
return render_template('regist_secretquestion1.html', user_id = org_userid)
else:
flash('ニックネームを入力してください')
return render_template('regist_nicname.html')
@app.route('/regist_secretq1', methods=['POST'])
def regist_secretq1():
org_userid = request.form['user_id']
org_data = Note.query.get(org_userid)
org_data.secretq1 = request.form['secretq1']
org_data.secretq1_answer = request.form['secretq1_answer']
if org_data.secretq1_answer:
db.session.merge(org_data)
db.session.commit()
flash('秘密1登録完了')
return render_template('regist_secretquestion2.html', user_id=org_userid)
else:
flash('秘密の答えを入力して下さい')
return render_template('regist_secretquestion1.html')
@app.route('/regist_secretq2', methods=['POST'])
def regist_secretq2():
org_userid = request.form['user_id']
org_data = Note.query.get(org_userid)
org_data.secretq2 = request.form['secretq2']
org_data.secretq2_answer = request.form['secretq2_answer']
if org_data.secretq2_answer:
db.session.merge(org_data)
db.session.commit()
flash('新規登録完了です!')
return render_template('login.html', user_id=org_userid)
else:
flash('秘密の答えを入力して下さい')
return render_template('regist_secretquestion2.html')
@app.route('/logout')
def logout():
session.pop('login',None)
return redirect(url_for('index'))
#<-----------ここまでーーーーーーーーーーーーーーーー>
#アプリケーションの起動
if __name__ == '__main__':
app.run(debug=True)
コードの解説
解説は、動作が追いやすいようにPCの処理順で解説しています。
新規登録画面のメソッド
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>ログイン</title>
</head>
<body>
<!--flashメッセージここから-->
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<p style="background-color:aqua;">
<b>{{message}}</b>
</p>
{% endfor %}
{% endif %}
{% endwith %}
<!---flashメッセージここまで-->
<h2>ユーザーIDとパスワードを入力してください</h2>
<form method="POST" action="/logincheck">
<input placeholder="ユーザーID" type="text" name="user_id">
<input placeholder="パスワード" type="password" name="password">
<input type="submit" value="送信">
</form>
<br>
<form method="POST" action="/registration">
<input type="submit" value="新規会員登録">
</form>
</body>
</html>
まずは、「login.html」内の【新規会員登録】ボタン押下時の動きです。
<form method="POST" action="/registration">
<input type="submit" value="新規会員登録">
</form>
このボタンを押下すると、action = "registration" につながります。
@app.route('/registration', methods=['POST'])
def registration():
return render_template('new_registration.html')
そこから「new_registration.html」の画面へ飛ばします。
その画面で、初めて登録する「ユーザー名」「パスワード」を登録します。
<html lang="ja">
<head>
<meta charset="utf-8">
<title>新規登録</title>
</head>
<body>
<!--flashメッセージここから-->
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<p style="background-color:aqua;">
<b>{{message}}</b>
</p>
{% endfor %}
{% endif %}
{% endwith %}
<!---flashメッセージここまで-->
<h2>ユーザーIDとパスワードを教えてください</h2>
<form method="POST" action="/registration_action">
<input placeholder="新規ユーザーID" type="text" name="user_id_new">
<input placeholder="新規パスワード" type="password" name="user_pw_new">
<input type="submit" value="登録">
</form>
<br>
<a href="/">ログイン画面に戻る</a>
</body>
</html>
これは、「new_registration.html」のコードです。
<form method="POST" action="/registration_action">
<input placeholder="新規ユーザーID" type="text" name="user_id_new">
<input placeholder="新規パスワード" type="password" name="user_pw_new">
<input type="submit" value="登録">
</form>
以上のformに「ユーザーID」「新規パスワード」を入力し、【登録】ボタンを押したら、action = "/registration_action" に飛ばすよう設定してあります。
/registration_action ルート
@app.route('/registration_action',methods=['POST'])
def registration_action():
user_id_new = request.form['user_id_new']
user_pw_new = request.form['user_pw_new']
org_data = Note.query.get(user_id_new)
if not org_data:
if user_id_new:
if user_pw_new:
register_data=Note(userid=user_id_new,userpw=user_pw_new)
db.session.add(register_data)
db.session.commit()
return render_template('regist_nicname.html',user_id=user_id_new)
else:
flash('登録できませんでした。パスワードを入力してください')
return render_template('new_registration.html')
else:
flash('登録できませんでした。入力項目を確認してください。')
return render_template('new_registration.html')
else:
flash('このIDは登録されています')
return render_template('new_registration.html')
まず、request.form[]で、入力された「ユーザーID」と「パスワード」を取得します。
org_data = Note.query.get(user_id_new)についてです。
query.get(key)でデータ内のprimary_key列(以下参照)からkeyを検索することができます。
今回だと、データ内のuseridからuser_id_newと一致するものを、org_dataに格納しています。
class Note(db.Model):
__tablename__ = 'notes'
userid = db.Column(db.String(30),primary_key=True)
userpw = db.Column(db.String(300))
nicname = db.Column(db.String(300))
secretq1 = db.Column(db.String(300))
secretq1_answer = db.Column(db.String(300))
secretq2 = db.Column(db.String(300))
secretq2_answer = db.Column(db.String(300))
date = db.Column(db.DateTime, nullable=False, default=datetime.now())
以下では、データが存在しているかの判定と、登録を行っています。
if not org_data:
if user_id_new:
if user_pw_new:
register_data=Note(userid=user_id_new,userpw=user_pw_new)
db.session.add(register_data)
db.session.commit()
return render_template('regist_nicname.html',user_id=user_id_new)
else:
flash('登録できませんでした。パスワードを入力してください')
return render_template('new_registration.html')
else:
flash('登録できませんでした。入力項目を確認してください。')
return render_template('new_registration.html')
else:
flash('このIDは登録されています')
return render_template('new_registration.html')
register_data=Note(userid=user_id_new,userpw=user_pw_new)
db.session.add(register_data)
では、データの登録を行っています。
最初のif文は、データが格納されていない場合にはじくためにif文を用いています。
/regist_secretq1 , /regist_secretq2 のルート
ここは、セキュリティの向上のために、秘密の質問を追加登録しています。(なくてもいいですw)
また、ここで使われているメソッドは、全て先ほど使ったものと全く同じものです。
ちなみに、db.session.merge()はデータの上書きができます。
@app.route('/regist_secretq1', methods=['POST'])
def regist_secretq1():
org_userid = request.form['user_id']
org_data = Note.query.get(org_userid)
org_data.secretq1 = request.form['secretq1']
org_data.secretq1_answer = request.form['secretq1_answer']
if org_data.secretq1_answer:
db.session.merge(org_data)
db.session.commit()
flash('秘密1登録完了')
return render_template('regist_secretquestion2.html', user_id=org_userid)
else:
flash('秘密の答えを入力して下さい')
return render_template('regist_secretquestion1.html')
@app.route('/regist_secretq2', methods=['POST'])
def regist_secretq2():
org_userid = request.form['user_id']
org_data = Note.query.get(org_userid)
org_data.secretq2 = request.form['secretq2']
org_data.secretq2_answer = request.form['secretq2_answer']
if org_data.secretq2_answer:
db.session.merge(org_data)
db.session.commit()
flash('新規登録完了です!')
return render_template('login.html', user_id=org_userid)
else:
flash('秘密の答えを入力して下さい')
return render_template('regist_secretquestion2.html')
ログアウトのメソッド
@app.route('/logout')
def logout():
session.pop('login',None)
return redirect(url_for('index'))
こちらはそんなに難しくありません。
session['login'] にログイン判定(True or False )を格納していました。
.popではそれらを削除しています。
まとめ
今回は、