対象
Djangoから、DBに接続してデータをごにょごにょやりたいんだけど、ORMが嫌いで「Viva! SQL」 な人。
やりたいこと
Djangoのconnectionsを使うと、SELECT文の結果カーソルがtupleになってしまいフィールド順序でのアクセスになってしまうので、こんな風に{'name': 'Taro Yamada', 'age': 25}
Dictionaryで結果がほしい。
やったこと (簡潔編)
ORM使わないなら、Djangoのconnectionsいらないから、自分でconnectする。参考URL: YoheiM.NET
やったこと (だらだら編)
Djangoで、settings.pyにDBを以下のusersのように追加して、(docs.djangoproject.jpより引用)DATABASES = {
'default': {
'NAME': 'app_data',
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'USER': 'postgres_user',
'PASSWORD': 's3krit'
},
'users': {
'NAME': 'user_data',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'priv4te'
}
}
で、データがほしいところでfrom django.db import connections
conn = connections["users"]
cur = conn.cursor()
cur.execute("SELECT * FROM persons WHERE id = %s", 100)
row = cur.fetchone()
print(row)
てな感じで、書くとprintされるのが、以下みたいな感じ (100, "Taro Yamada", 25, 1, True)
{えーっ。tupleですかー? これじゃ、templateにrowを渡した時に、{{ row.1 }} な感じで読み取らないといけないから、わけわかめじゃんよー・・・。俺は、class Person を作りたくないんだってば }
どうやら調べると、DictCursorなるものを使えば、rowがtupleでなく
{'id': 100, 'name': 'Taro Yamada', 'age': 25, 以下略}
のようにdictionaryで取れるらしい。(参照: stackoverflow) 押忍。じゃあ、そこに
connection.cursor(pymysql.cursors.DictCursor)
なんて記述が、あったからさっきの上のコードをこんなふうに変更してみたところ
--- cur = con.cursor()
+++ cur = con.cursor(pymysql.cursors.DictCursor)
こんなエラーが cur = connections['users'].cursor(pymysql.cursors.DictCursor)
TypeError: cursor() takes 1 positional argument but 2 were given
{むきーっ!! } どうやら、connections[‘users’]でとれるconnectionと、上記stackoverflowサンプルのconnectionは、別物らしい。
そりゃそうじゃよな。
具体的には、前者が ‘django.db.backends.mysql.base.DatabaseWrapper’
で、後者が ‘pymysql.connections.Connection’
さらに調べると、別のstackoverflowで、
「djangoに、DictCursorなんて、なぁぃですね~↑」(No there is no such support for DictCursor in django.)
{なにーっ!! }
さらに、その回答の解決案がびみょ~~な感じ。
でも、考えてみるとDictCursorを使いたいって時点で、djangoのORM無視してSQL投げたいってことなんだから、自分でconnectすればいいじゃんか。 ← 早く気がつけ。
幸い、親切な人が素晴らしい解説を書いている(YoheiM.NET)ように、使い方は簡単。
ただ、DB接続設定は、settings.pyに残しておきたいのと、データを使う側でのコードを簡潔にしたいので、最終的に以下のようになった。
まず、settings.py に、connectionまで定義してしまってアプリ全体で使い回す。
import pymysql.cursors
USERS_DB = pymysql.connect(
host='localhost',
user='db_user',
password='db_pass',
db='users',
charset='utf8',
cursorclass=pymysql.cursors.DictCursor)
最後の一行が、ポイント。 settings.pyってpythonファイルだから、こんなものも置けるんだ・・・ DBにアクセスしたい方では、
from django.conf import settings
conn = settings.USERS_DB # ←これ便利
cur = con.cursor()
cur.execute("SELECT * FROM persons WHERE id = %s", 100)
row = cur.fetchone()
print(row)
これで、 {'id': 100, 'name': 'Taro Yamada', 'age': 25, 以下略}
が、めでたくprintされる。ついでに書くと、templateに渡すところでは、↑のrowを利用して、views.py で
render(request, 'users.html', {'person': row})
なふうに、簡単に渡して、template側では、{{ person.name }}
とか{{ person.age }}
みたいに、見てすぐにわかるように呼び出せるようになった。でも、django.db.backends.mysql.base.DatabaseWrapperと pymysql.connections.Connectionのようにオブジェクト自体が異なっていても、executeの書き方やfetchoneで呼ぶところなど、共通だからほとんどコード変更の必要が無いのって、pythonからのDBアクセス方法がPEP 249で規定されてるからなんだよね。
pythonって文法が好きになれないんだけど(俺が好きなのはscala)、取り巻く環境がいろいろと整ってるから結局使っちゃうのよ。
長いところ、最後までお読みいただきありがとうございました。
0 件のコメント :
コメントを投稿