😸
sqlalchemyで検索値指定によるテーブルリレーションを動的に行う方法
はじめに
sqlalchemyを使用して、リクエストで検索値のカラムを文字列で指定する場合、その対象のテーブルをリレーションして値を参照しに行く必要があります。
それをclassを使って動的に実装する方法を紹介します。
実際のコード
まずは検索値をpythonのenumモジュールを使ってあらかじめ定義しておきます。
enum.py
from enum import Enum
class SearchItem(Enum):
USER_NAME = "userName" # UserInfoテーブルのカラム
ORDER_ITEM = "orderItem" # Orderテーブルのカラム
SUBSCRIPTION_DATE = "subscription_date" # Subscriptionテーブルのカラム
この3つのカラム値が検索値として使われると仮定します。
では、次にそれぞれの検索値に対してclassを定義していきます。
まずはabcモジュールを使って、baseとなる親クラスを定義します。
search_condition.py
from abc import ABCMeta, abstractmethod
from enum import SearchItem
from models import User, UserInfo, Order, Subscription
class SearchConditionBase(metaclass=ABCMeta):
"""baseとなる親クラス"""
@abstractmethod
def item(self) -> SearchItem:
raise NotImplementedError()
@abstractmethod
def table(self):
raise NotImplementedError()
def table_join_condition(self):
"""リレーションの結合条件"""
return User.id == self.table().user_id
次に、各検索値用のclassをSearchConditionBaseの子クラスとして定義していきます。
class UserNameSearchCondition(SearchConditionBase):
def item(self) -> SearchItem:
return SearchItem.USER_NAME
def table(self):
return UserInfo
class OrderItemSearchCondition(SearchConditionBase):
def item(self) -> SearchItem:
return SearchItem.ORDER_ITEM
def table(self):
return Order
class SubscriptionDateSearchCondition(SearchConditionBase):
def item(self) -> SearchItem:
return SearchItem.SUBSCRIPTION_DATE
def table(self):
return Subscription
そして、定義したclassのインスタンスをリストに格納します。
SEARCH_CONDITION_DEFINES: list[SearchConditionBase] = [
UserNameSearchCondition(),
OrderItemSearchCondition(),
SubscriptionDateSearchCondition(),
]
さらに、格納したインスタンスを引数で指定した検索値によって動的に取り出せるように関数化します。
def find_search_condition(search_item: SearchItem) -> SearchConditionBase:
return [con for con in SEARCH_CONDITION_DEFINES if con.item() == search_item][0]
これで、後はこの関数を呼び出し元から呼び出すと完成です!
from search_condition import find_search_condition
search_condition = find_search_condition(request.search_item)
table = search_condition.table()
query = query.join(
table,
search_condition.table_join_condition(),
)
終わりに
以上、今回は検索値による動的なテーブルリレーションの方法を紹介しました!
今回紹介したクラスの使い方は使いどころは多いと思うので、応用して色んな場面で使っていけたらと思います。
Discussion