DjangoのORMを使わないでクエリを実行する方法
ORM(object relational mapper)を使うべきか、使わざるべきかの議論を時々目にします。
Author.objects.all()
←こういうやつです。
今回は、DjangoでORMを使わずにクエリを書いてDBからデータを取得する方法を紹介します。
クエリの生成にはjinjasql
というpythonのライブラリを使用します。
ライブラリは↓のようにインストールが可能です。
pip install jinjasql
jinjasqlはjinja2というテンプレートエンジンを基にしているので、柔軟にクエリを書くことができます。
紹介
まずはModelについてです。
class Data(models.Model): title = models.TextField(max_length=400) is_deleted = models.BooleanField(default=False) created_at = models.DateTimeField(auto_now_add=True) modified_at = models.DateTimeField(auto_now=True) class Meta: db_table = 'card' def select_data_list(self, limit): template, data = select_data_list_template(limit) query, bind_params = j.prepare_query(template, data) datas = Data.objects.raw(query, bind_params) return list(datas)
このモデル(Data)を使って、dataテーブルからデータを取得します。
select_data_list
メソッドの中身に注目してください。
template, data = select_data_list_template(limit) # 1 query, bind_params = j.prepare_query(template, data) # 2 datas = Data.objects.raw(query, bind_params) # 3
1でクエリのもととなる文字列と、データを用意します。
1の関数は↓のように作成します。
def select_data_list_template(limit): template = """ select id, title, is_deleted, created_at from data order by created_at desc limit {{limit}} """ data = { 'limit': limit, } return template, data
jinjasqlではjinja2と同じようにfor文を使ったり、if文を使ったりできます。
例ではlimitの指定しかしていませんが、「ある値の場合には条件1を、別の値の場合は条件2をwhereに設定する」といったことができます。
これはspringというjavaのフレームワークで使えるmybatisと同じようなことができるということです。
次に、2でjinjasqlというライブラリを使ってDjangoで使えるクエリを生成します。
query
には↓の文字列が作成されます。
select id, title, is_deleted, created_at from data order by card.created_at desc limit %s
bind_params
には↓のオブジェクトが作成されます。
odict_values([30])
最後に、3でquery
とbind_params
をDjangoで用意されているraw関数を使って実行します。
取得されるデータはlist化する必要があるので少し面倒ですが、複雑なクエリをORMを使って書くよりは面倒ではないと思います。