[Python Flask] SQLAlchemyでORMを利用して、レコードを更新(Update)する方法

Flask
スポンサーリンク

こんにちは。
プログラミングを勉強しているロペです。

SQLAlchemyでORMを利用してレコードを更新する方法を学習しましたので、
自分なりに纏めて記事にしました。

この記事が誰かの役に立ったら幸いです。

この記事で勉強したコードが上手くできずに大分はまり、本業が忙しかったこともあり、前回の更新から時間が空いてしまいました・・・
(↓のエラーコードを修正するにメチャメチャ時間がかかりました)

‘NullSession’ object has no attribute ‘query’

スポンサーリンク

概要

データベースアクセスの基本は、「Create(新規作成)」、「Read(データ取得)」、「Update(更新)」、「Delete(削除)」の4つの操作なのですが、この記事では「Update(更新)」について書いています。

「Create(新規作成)」の記事は↓で書いていますで、よければ覗いてみてください。

出力する画面

今回の記事で作成して、出力した画面は↓になります。

データベースにはIDが1~6の情報(名前、メールアドレス、年齢)が格納されており、指定したIDの情報を書き換えるとうコードを書きました。

書き換えたい情報を記載してupdateのボタンを押すと情報が書き換わる仕組みになっています。

idの受け取り方

編集したいID番号の受け取り方を書きます。

@app.route(‘/ajax/<id>’, methods=[‘GET’])

とパスにidを記入できるようにしておき、ajax/ 以降記入された番号をidとして認識するようにしています。

指定したidのデータを取得する方法

↓のように関数を定義して、データベースの指定のidだけを抜き出しています。

def ajax_id(id):
    Session = sessionmaker(bind=engine)
    ses = Session()
    mydata = ses.query(Mydata).filter(Mydata.id == id).one()
    ses.close()
    return jsonify(mydata.toDict());

セッションの作成

Session = sessionmaker(bind=engine)
ses = Session()

指定のidを取得

mydata = ses.query(Mydata).filter(Mydata.id == id).one()

セッションの開放

ses.close()

指定idの情報を更新する

↓の関数で抜き出したidに紐づいたデータベースの情報を更新しています。

def form_id(id):
    name = request.form.get('name')
    mail = request.form.get('mail')
    age = int(request.form.get('age'))
    Session = sessionmaker(bind=engine)
    ses = Session()
    mydata = ses.query(Mydata).filter(Mydata.id == id).one()
    mydata.name = name
    mydata.mail = mail
    mydata.age = int(age)
    ses.add(mydata)
    ses.commit()
    ses.close()
    return 'ok'

送信された値(ユーザーが指定した値)を変数に取り出す

name = request.form.get('name')
mail = request.form.get('mail')
age = int(request.form.get('age'))

セッションを用意する

Session = sessionmaker(bind=engine)
ses = Session()

指定idのモデルクラス・インスタンスの値を得る

mydata = ses.query(Mydata).filter(Mydata.id == id).one()

指定idのモデルクラス・インスタンスの値を変更する

mydata.name = name
mydata.mail = mail
mydata.age = int(age)

モデルクラス・インスタンスを更新して終了

ses.add(mydata)
ses.commit()
ses.close()

コードの全文

最後に今回作成したコードを全文の載せておきますね。

Flaskのスクリプト

from flask import Flask, render_template, request, session, url_for, redirect, jsonify,g
from flask.views import MethodView
import sqlite3,pickle
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
# from sqlalch import (Table, Column, Integer, String)
 
app = Flask(__name__)
 
engine = create_engine('sqlite:///sample.sqlite3')
Base = declarative_base()
 
# get Database Object.
def get_db():
    if 'db' not in g:
        g.db = sqlite3.connect('sample.sqlite3')
        return g.db
 
# close Database Object.
def close_db(e=None):
    db = g.pop('db', None)
 
    if db is not None:
        db.close()
 
#model class
class Mydata(Base):
    __tablename__ = 'mydata'
 
    id = Column(Integer, primary_key=True)
    name = Column(String(255))
    mail = Column(String(255))
    age = Column(Integer)
 
    # get Dict data
    def toDict(self):
        return{
            'id':int(self.id),
            'name':str(self.name),
            'mail':str(self.mail),
            'age':int(self.age)
        }
# get List data
def getByList(arr):
    res=[]
    for item in arr:
        res.append(item.toDict())
    return res
 
# get all mydata record
def getAll():
    Session = sessionmaker(bind=engine)
    ses = Session()
    res = ses.query(Mydata).all()
    ses.close()
    return res
 
# @app.route('/', methods=['GET'])
# def index():
#     return render_template('index.html',\
#         title='This is smaple of ORM',)
 
@app.route('/ajax', methods=['GET'])
def ajax():
    mydata = getAll()
    return jsonify(getByList(mydata));
 
@app.route('/form', methods=['post'])
def form():
    name = request.form.get('name')
    mail = request.form.get('mail')
    age = int(request.form.get('age'))
    mydata = Mydata(name=name, mail=mail, age=age)
    Session = sessionmaker(bind=engine)
    ses = Session()
    ses.add(mydata)
    ses.commit()
    ses.close()
    return'ok'
 
@app.route('/<id>', methods=['GET'])
def index_id(id):
    return render_template('index.html',\
        title='Sample of Update', id=id, \
        message='SQL',
        alert='Hello SQL')

@app.route('/ajax/<id>', methods=['GET'])
def ajax_id(id):
    Session = sessionmaker(bind=engine)
    ses = Session()
    mydata = ses.query(Mydata).filter(Mydata.id == id).one()
    ses.close()
    return jsonify(mydata.toDict());

@app.route('/form/<id>', methods=['post'])
def form_id(id):
    name = request.form.get('name')
    mail = request.form.get('mail')
    age = int(request.form.get('age'))
    Session = sessionmaker(bind=engine)
    ses = Session()
    mydata = ses.query(Mydata).filter(Mydata.id == id).one()
    mydata.name = name
    mydata.mail = mail
    mydata.age = int(age)
    ses.add(mydata)
    ses.commit()
    ses.close()
    return 'ok'

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

HTML(Vue)

{% extends "layout.html" %}
{% block title %}
login-app
{% endblock %}

{% block headline %}
{{title}}
{{message}}
{% endblock %}

{% block content %}
<div id="app" class="m-3">
    <mycomp />
</div>

{% raw %}
<script type="text/x-template" id="mycomp-template">
    <div>
        <div class="alert alert-info">
            <h5>{{alert}}</h5>
        </div>
        <br>
        <div class="form-group">
            <label for = "id">Name</label>
            <input type="text" class="form-control"
            id="name" v-model="f_name">
        </div>
        <div class="form-group">
            <label for = "mail">Mail</label>
            <input type="mail" class="form-control"
            id="mail" v-model="f_mail">
        </div>
        <div class="form-group">
            <label for = "age">Age</label>
            <input type="number" class="form-control"
            id="age" v-model="f_age">
        </div>
        <div class="form-group">
            <button class="btn btn-primary"
            v-on:click="action">Update</button>
        </div>


            <table class="table">
                <thead>
                    <tr>
                        <th>ID</th>
                        <th>Name</th>
                        <th>Mail</th>
                        <th>Age</th>
                    </tr>
                </thead>
                <tbody>
                    <tr v-for= "item in data">
                        <th>{{item.id}}</th>
                        <th>{{item.name}}</th>
                        <th>{{item.mail}}</th>
                        <th>{{item.age}}</th>
                    </tr>
                </tbody>
            </table>
        </div>
    </div>
</script>
{% endraw %}


<script>
// mycomp_board object
Vue.component('mycomp',{
    template:'#mycomp-template',
    data: function(){
        return{
            s_id: {{id}},
            f_name:'',f_mail:'',f_age:'',
            alert: 'This is SQLite3 Database sample_index',
            data:[(-1,'wait...','','')]
        }
    },
    methods:{
        getdata: function(){
            let self = this;
            $.get("/ajax", function(data){
                self.data=eval(data).reverse();
            });
        },
        getById:function(){
            let self =this;
            $.get("/ajax/" + this.s_id, function(data){
                target = eval(data);
                self.f_name = target.name;
                self.f_mail = target.mail;
                self.f_age = target.age;
                self.alert = '*ID番号 ' + self.s_id +' を編集します';
            });
        },
        action: function(){
            let formData = new FormData();
            formData.append("name", this.f_name);
            formData.append("mail", this.f_mail);
            formData.append("age", this.f_age);
            let self = this;
            $.ajax({
                type:'POST',
                url:'/form/' + self.s_id,
                data: formData,
                processData: false,
                contentType: false,

                success: function(data){
                    self.f_name='';
                    self.f_mail='';
                    self.f_age= '';
                    self.getdata();
                },
                error: function(request, status, err) {
                    console.log(err);
                }
            });
        }
    },
    created: function() {
        this.getdata();
        this.getById();
    }
});
    // start Vue.
    new Vue({
        el:'#app',
    });
    </script>
    {% endblock %}
    {% block footer %}
     <h6>Coryright 2020 Rope_blog </h6>
    {% endblock %}

HTML(Layout)

これが最後のコードファイルです。

<!doctype html>
<html lang="ja">
<head>
    <title>{%block title %}{% endblock %}</title>
    <meta charset="utf-8"/>
    <meta name="vieport"
        content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <link rel="stylesheet" href="{{url_for('static',filename='style.css')}}">
            <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
            <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" ></script>
            <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
            <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
    </script> 
</head>
<body>
    <div class="test" style="background-color:rgba(169, 84, 177, 0.055);">
        <div class="target">
            <div class="container"style="max-width: 100%;">
                <div style="display: table;width:100%;">
                    <div style="display:table-cell; vertical-align:middle;font-size: 30px;">
                        <div class="text-left" style="border-bottom:5px solid rgb(135, 250, 196);" >
                        <h1 class="display-3">
                            <div style="font-size: 50px;">
                            {% block headline %}{% endblock %}
                            </div>
                        </h1>
                        </div>
                        <div style="border-bottom:5px solid rgb(135, 250, 196);" >
                            {% block content %}{% endblock %}
                        </div>
 
                        <div class="text-right">
                        {% block footer %}{% endblock %}
                        </div>
                    </div>
                </div>
            </div>
        </div>   
    </div>
</body>
</html>

以上になります。

それでは皆さん良いコーディングライフを!!

コメント

タイトルとURLをコピーしました