質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

SQLAlchemy

SQLAlchemyとはPython 用のORMライブラリです。MIT Licenceのオープンソースとして提供されています。

Q&A

2回答

801閲覧

Flaskのデータベースのテーブルを自由自在に操作したいが、出来ずに困っている。

zero-penguin

総合スコア1

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

SQLAlchemy

SQLAlchemyとはPython 用のORMライブラリです。MIT Licenceのオープンソースとして提供されています。

0グッド

0クリップ

投稿2023/07/01 06:56

編集2023/07/02 03:17

実現したいこと

初めて3か月程度の学習中の者です。
flaskによってサイトを作成するためにデータベースを整理しています。
多くのサイトで見るように、テーブルをmodelというディレクトリの配下でmodel.pyとして定義したいですが、現状のコードではうまくいきません。よって実現したいことは、

・model.pyに正しくデータベースを定義したい。
・そのmodel.pyをapp.pyにインポートしたい。
・方法はいろいろあると思いますが、テーブルの操作を自由自在に行う方法を知りたい。

前提

質問したい内容は、上記の3つを達成しようとした際に生じた問題の解決策を質問したいです。
具体的な問題として、以下の二つがあります。

・テーブル変更を行いマイグレーションを実行しても、データベース内のテーブルは変化していない。
具体的には

backend/app.py

の階層で

python >>>import app from app,db >>>with app.app_context(): >>> db.create_all()

・テーブルに対してCRUD操作を行いたいが、現状はコマンドからReadしかできない。
具体的には、

backend/instance/admin.db

の階層でターミナルから

sqlite3 admin.db (sqlite3).table (sqlite3).schema

発生している問題・エラーメッセージ

先ほどの2つのコードに対してエラーは出ていません。

試したこと

・app.pyにmodel.pyのテーブルを全て書いてマイグレーションしたがやはり変更されなかった。
・backend/instanceからadmin.dbに対してSQLコマンドでCRUD操作を行うことは出来た。
http://blog.e-riverstyle.com/2010/05/sqlite.html参考に

だが、基本的にはCRUD操作をコマンドではなくpyhtonコードで行いたいので、やはり問題は解決していない。

・phpmyadminにadmin.dbをインポートしてCRUD操作は成功した。

だが、中心的に操作したいのはflaskのmodel.pyの部分なので、データベースの管理ツールやコマンドベースのデータベース操作の成功では、今後のデータベース操作で苦労しそう。

補足情報(FW/ツールのバージョンなど)

githubに全体のソースコードを公開しているので、そのURLを載せます。
https://github.com/zero-penguin/original_site

関連のバージョン
python 3.11.3
Flask 2.2.3

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2023/07/01 07:29

「具体的には~」以降に書いてあることを"実際に"試した結果、エラーは何も出ていないのですか? もしエラーが出ているならばその内容を書いてください。
guest

回答2

0

☆Usersテーブルを操作するコードの例を示します。
(frontendと組み合わせることを想定して、JSONでやり取りする形)
下記は、
http://localhost:8000/users でユーザー情報一覧をJSONで返す
http://localhost:8000/users に対して ペイロードをjsonにしてPOSTすると、ユーザーを追加。
http://localhost:8000/users/<id番号> で該当するidのユーザー情報をJSONで返す
http://localhost:8000/admin で、管理画面に入る
というコードになります。

POSTでデータ追記するのが面倒なら、サンプルデータは、http://localhost:8000/admin で、管理画面に入って、「Create」タブを開けば、手動で追加できます。

イメージ説明

追加したあと、
http://localhost:8000/users/1
にアクセスすると、ユーザーの情報がJSON形式で表示されます。


 
admin画面を連携するにはAdmin()ではだめで、Admin(app)とする必要があります。

model.py は app.py ではなく、main.py でインポートしており、ルーティングも main.py で行っています。
したがって、起動するときは

python main.py

とする必要があります。

※「passward」 の正しい綴りは「password」ですが、下記は元のコードを尊重してそのままにしています。


コード

app.py

py

1from flask import Flask 2 3app = Flask(__name__, 4 static_folder="../frontend/dist/static", 5 template_folder="../frontend/dist" 6 ) 7 8app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///admin.db' 9app.config['SECRET_KEY'] = 'secret_key'

main.py

py

1# -*- coding: utf-8 -*- 2import os 3from app import app 4from model.model import db 5from model.model import Users 6from flask import request 7 8 9@app.route('/',defaults={'path':''}) 10def index(path): 11 db.create_all() 12 return 'ようこそ' 13 14 15@app.route('/users', methods=['POST']) 16def create_user(): 17 data = request.get_json() # POSTされたJSONデータを取得します 18 name = data.get('name') 19 passward = data.get('passward') 20 status = data.get('status') 21 22 if name is None or status is None: 23 return '受け取ったデータが不正です。', 400 24 25 user = Users(name=name, passward=passward, status=status) 26 db.session.add(user) 27 db.session.commit() 28 return 'ユーザーの追加に成功しました。', 200 29 30 31@app.route('/users/<userid>', methods=['GET']) 32def get_user(userid): 33 user = Users.query.filter_by(id=userid).first() 34 35 if user is None: 36 return 'ユーザーが見つかりませんでした。', 404 37 38 data = { 39 'name': user.name, 40 'passward': user.passward, 41 'status': user.status 42 } 43 return data, 200 44 45 46@app.route('/users', methods=['GET']) 47def get_all_users(): 48 users = Users.query.all() 49 50 data = [] 51 for user in users: 52 user_data = { 53 'id': user.id, 54 'name': user.name, 55 'passward': user.passward, 56 'status': user.status 57 } 58 data.append(user_data) 59 60 return {'users': data}, 200 61 62 63if __name__ == '__main__': 64 app.run(host=os.getenv('APP_ADDRESS', 'localhost'), port=8000)

model.py

py

1from datetime import datetime 2import pytz 3from flask_admin import Admin 4from flask_admin.contrib.sqla import ModelView 5from flask_sqlalchemy import SQLAlchemy 6from app import app 7 8db = SQLAlchemy(app) 9 10 11class Users(db.Model): 12 id = db.Column(db.Integer, primary_key=True) 13 name = db.Column(db.String(15), nullable=False) 14 passward = db.Column(db.String(10), nullable=False) 15 status = db.Column(db.String(50), nullable=False) 16 created_data = db.Column(db.DateTime, nullable=False, default=datetime.now(pytz.timezone('Asia/Tokyo'))) 17 18class Users_names(db.Model): 19 id = db.Column(db.Integer, primary_key=True) 20 name = db.Column(db.String(15), nullable=False) 21 created_data = db.Column(db.DateTime, nullable=False, default=datetime.now(pytz.timezone('Asia/Tokyo'))) 22 23class Users_password(db.Model): 24 id = db.Column(db.Integer, primary_key=True) 25 name = db.Column(db.String(15), nullable=False) 26 passward = db.Column(db.String(15), nullable=False) 27 created_data = db.Column(db.DateTime, nullable=False, default=datetime.now(pytz.timezone('Asia/Tokyo'))) 28 29class Users_status(db.Model): 30 id = db.Column(db.Integer, primary_key=True) 31 name = db.Column(db.String(10), nullable=False) 32 gender = db.Column(db.String(10), nullable=False) 33 old = db.Column(db.Integer, nullable=False) 34 created_data= db.Column(db.DateTime, nullable=False, default=datetime.now(pytz.timezone('Asia/Tokyo'))) 35 36class Creates(db.Model): 37 id = db.Column(db.Integer, primary_key=True) 38 title = db.Column(db.String(10), nullable=False) 39 img = db.Column(db.String(10), nullable=False) 40 comment = db.Column(db.String(20), nullable=False) 41 goodcount = db.Column(db.String(50), nullable=False) 42 created_data= db.Column(db.DateTime, nullable=False, default=datetime.now(pytz.timezone('Asia/Tokyo'))) 43 44class Creates_title(db.Model): 45 id = db.Column(db.Integer, primary_key=True) 46 title = db.Column(db.String(10), nullable=False) 47 content = db.Column(db.String(300), nullable=False) 48 created_date = db.Column(db.DateTime, nullable=False, default=datetime.now(pytz.timezone('Asia/Tokyo'))) 49 50class Creates_img(db.Model): 51 id = db.Column(db.Integer, primary_key=True) 52 imgpath = db.VARCHAR(db.String(100)) 53 created_data= db.Column(db.DateTime, nullable=False, default=datetime.now(pytz.timezone('Asia/Tokyo'))) 54 55class Creates_goodcount(db.Model): 56 id = db.Column(db.Integer, primary_key=True) 57 supporter_id = db.Column(db.Integer, primary_key=True) 58 count = db.Column(db.Integer, primary_key=True) 59 created_data= db.Column(db.DateTime, nullable=False, default=datetime.now(pytz.timezone('Asia/Tokyo'))) 60 61class Creates_comment(db.Model): 62 id = db.Column(db.Integer, primary_key=True) 63 supporter_id = db.Column(db.Integer, primary_key=True) 64 supporter_name = db.Column(db.String(10), nullable=False) 65 supporter_content = db.Column(db.String(100), nullable=False) 66 created_data= db.Column(db.DateTime, nullable=False, default=datetime.now(pytz.timezone('Asia/Tokyo'))) 67 68admin = Admin(app) 69admin.add_view(ModelView(Users,db.session)) 70admin.add_view(ModelView(Users_names,db.session)) 71admin.add_view(ModelView(Users_password,db.session)) 72admin.add_view(ModelView(Users_status,db.session)) 73admin.add_view(ModelView(Creates,db.session)) 74admin.add_view(ModelView(Creates_title,db.session)) 75admin.add_view(ModelView(Creates_img,db.session)) 76admin.add_view(ModelView(Creates_goodcount,db.session)) 77admin.add_view(ModelView(Creates_comment,db.session))

ディレクトリ構造(githubの通り)

hex

1├model 2│ └model.py 3├app.py 4└main.py

※../frontend/dist ディレクトリの下に、空のファイルでよいので、index.htmlを置いておいてください。

投稿2023/07/03 11:59

編集2023/07/03 12:34
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

zero-penguin

2023/07/04 05:20

Json形式に変換することまで想定しての丁寧なご回答ありがとうございます!少し実行に時間がかかる可能性があるので、解決や問題が発生した場合は随時返信いたします!
guest

0

・テーブル変更を行いマイグレーションを実行しても、データベース内のテーブルは変化していない。

以下を参照ください。

Create the Tables

create_all does not update tables if they are already in the database.

(DeepL翻訳: create_allはすでにデータベースにあるテーブルを更新しません。)
と、いうことなので、データベース内のテーブルに変化が無いのは正しい動作です。

変更したい場合は、続きに以下の様な記載があります。

If you change a model’s columns, use a migration library like Alembic with Flask-Alembic or Flask-Migrate to generate migrations that update the database schema.

(DeepL翻訳: モデルのカラムを変更する場合は、Flask-Alembic や Flask-Migrate を使って Alembic のようなマイグレーションライブラリを使い、データベースのスキーマを更新するマイグレーションを生成します。)

なので、Flask-AlembicやFlask-Migrateを使えばできそうです。

・テーブルに対してCRUD操作を行いたいが、現状はコマンドからReadしかできない。

Selectはできているようなので、Insert/Update/Delete部分は以下を参照ください。

Insert, Update, Delete

試して見ると分かりますが、Insert/Update/Delete操作は、commit()を最後に実行する必要があります。

また、ドキュメントにある例がわかりにくいですが・・・

py

1user = User() 2db.session.add(user) 3db.session.commit()

User()オブジェクトを作成し、(オブジェクトの中身を記載し)、add()してから、commit()すると、それがInsertされます。
例えばUserが

py

1class User(db.Model): 2 id = db.Column(db.Integer, primary_key=True) 3 name = db.Column(db.String(15), nullable=False) 4 passward = db.Column(db.String(10), nullable=False) 5 status = db.Column(db.String(50), nullable=False) 6 created_data = db.Column(db.DateTime, nullable=False, default=datetime.now(pytz.timezone('Asia/Tokyo')))

のような感じの場合は、

py

1user.id = 1 2user.name = "name"

みたいな事をした後に(もしくはModelを初期化する時にuser =User(id=1, name="name",...)の様にして)登録したい情報を登録します。

Updateは新しく作らず、すでにあるものを取得してから、それを変更しcommit()します。

py

1user = db.session.execute(db.select(User).filter_by(username=username)).scalar_one() 2user.id = 2 3db.session.commit()

Deleteも、Updateと同じで、すでにあるものを取得してから、それを削除します。

py

1user = db.session.execute(db.select(User).filter_by(username=username)).scalar_one() 2db.session.delete(user) 3db.session.commit()

sclar_one()は、SQLAlchemyのドキュメントによると、Result.scalars()Result.one().と同じです、ということなので、1個だけ取得していることに注意してください。

投稿2023/07/03 09:33

FiroProchainezo

総合スコア2421

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

zero-penguin

2023/07/04 05:20 編集

丁寧なご回答ありがとうございます!少し実行に時間がかかる可能性があるので、解決や問題が発生した場合は随時返信いたします!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問