メタクラスを使用しない Python での 4 つのフィールドベース ORM 実装方法

この記事は、Huawei クラウド コミュニティ「メタクラスを使用しない Python でのフィールドベースの ORM 実装」(著者: Lemony Hug) から共有されたものです。

メタクラスを使用しないシンプルな ORM 実装

Python における ORM (Object-Relational Mapping) は、オブジェクトとデータベース間のマッピング関係を変換し、データベースをオブジェクト指向で操作しやすくする技術です。通常、ORM を実装するにはメタクラスを使用しますが、この記事ではメタクラスを使用しない簡単な ORM 実装を紹介します。

フィールドクラス

まず、データベース テーブル内のフィールドを表すField クラスを定義します。このクラスには、フィールドの名前やタイプなどの情報が含まれており、その後のクエリ条件の構築を容易にするためにいくつかの比較演算をサポートします。

クラス フィールド:
    def __init__(self, **kwargs):
        self.name = kwargs.get('name')
        self.column_type = kwargs.get('column_type')

    def __eq__(自分, 他):
        return Compare(self, '=', other)

    # その他比较操作略...

クラスの比較

クエリ条件を構築するために、フィールド間の比較関係を表す Compare クラスを導入しました。チェーン操作をサポートし、複雑なクエリ条件を構築できます。

クラス比較:
    def __init__(self、左: フィールド、操作: str、右: Any):
        self.condition = f'`{left.name}` {operation} "{right}"'

    def __or__(self, other: "比較"):
        self.condition = f'({self.condition}) OR ({other.condition})'
        自分自身を返す

    def __and__(self, other: "比較"):
        self.condition = f'({self.condition}) AND ({other.condition})'
        自分自身を返す

モデルクラス

次に、データベース内のテーブルを表すクラスを定義Modelします。このクラスはFieldクラスのインスタンスを通じてテーブルのフィールドを定義し、データを挿入するためのメソッドを提供します。

クラスモデル:
    def __init__(self, **kwargs):
        _meta = self.get_class_meta()

        kwargs.items() の k、v の場合:
            _meta の k の場合:
                self.__dict__[k] = v

    @classmethod
    def get_class_meta(cls) ->辞書:
        if hasattr(cls, '_meta'):
            return cls.__dict__['_meta']
        _meta = {}

        cls.__dict__.items() の k、v の場合:
            if isinstance(v, Field):
                v.name が None の場合:
                    v.name = k
                名前 = v.name
                _meta[k] = (名前, v)

        table = cls.__dict__.get('__table__')
        table = cls.__name__ if table is None else table
        _meta['__table__'] = テーブル

        setattr(cls, '_meta', _meta)

        return _meta

    def insert(self):
        _meta = self.get_class_meta()
        column_li = []
        val_li = []

        self.__dict__.items() の k、v の場合:
            field_tuple = _meta.get(k)
            if field_tuple:
                列、フィールド = field_tuple
                column_li.append(列)
                val = str(v) if field.column_type == 'INT' else f'"{str(v)}"'
                val_li.append(val)

        sql = f'INSERT INTO {_meta["__table__"]} ({",".join(column_li)}) VALUES ({",".join(val_li)});' ;
        印刷(SQL)

クエリクラス

最後に、データベース クエリを構築するためのQuery クラスを実装しました。このクラスはチェーン呼び出しをサポートしており、クエリ条件や並べ替えなどを設定できます。

クラス クエリ:
    def __init__(self, cls: モデル):
        self._model = cls
        self._order_columns = なし
        self._desc = ''
        self._meta = self._model.get_class_meta()
        self._compare = なし
        self.sql = ''

    def _get(self) -> str:
        SQL = ''

        if self._compare:
            SQL += f' WHERE {self._compare.condition}'

        self._order_columns の場合:
            SQL += f' {self._order_columns} で注文'

        SQL += f' {self._desc}'
        SQL を返す<​​/span>
        自分自身を返す
        self._compare = 比較
    def where(self, Compare: "比較") -> 「クエリ」:
        自分自身を返す
        self._desc = 'DESC' if 記述 else ''
            self._order_columns = ','.join([f'`{x}`' for x in columns])
        elif isinstance(列, リスト):
            self._order_columns = f'`{columns}`'
        if isinstance(columns, str):
    def order_by(self, columns: Union[List, str], desc: bool = False) -> 「クエリ」:
        print(self.sql)
        self.sql = sql
        sql = f'SELECT {columns} FROM {table} {sql}'
        columns = ",".join(column_li)
                    column_li.append(f'`{v[0]}`')
                type(v) == タプルおよび isinstance(v[1], Field) の場合:
            self._meta.values() の v の場合:
        それ以外:
                column_li.append(f'`{field.name}`')
            引数のフィールド:
        if len(args) > 0:
        column_li = []
        table = self._meta['__table__']
        sql = self._get()

    def get(self, *args: フィールド) ->リスト[モデル]:





使用例

これで、モデル クラスを定義し、この単純な ORM 実装をデータ操作に使用できるようになりました。

クラス ユーザー(モデル):
    名前 = フィールド()
    年齢 = フィールド()

# 插入データ
ユーザー = ユーザー(名前='トム'、年齢=24)
user.insert()

# 蟥询条件の構築
User.query().where((User.name == 'Tom') & (User.age >= 20)).order_by('age').get( )

このようにして、メタクラスを使用しない単純な ORM 実装が完成しました。コード構造はメタクラスを使用するよりも単純ですが、実際のアプリケーションでは、プロジェクトの要件とチームの合意に基づいて適切な実装方法を選択することが重要です。
メタクラスに依存しない、Python に基づくシンプルな ORM 実装を導入しました。このパートでは、この実装について引き続き調査し、クエリの構築とより複雑な使用方法を詳しく見ていきます。

拡張クエリ機能

私たちのクエリ関数はまだ比較的単純ですが、複雑なクエリをより適切にサポートするために、より多くのクエリ メソッドと条件を追加できます。

LIMIT と OFFSET をサポート

クラス クエリ:
    # ...

    def limit(self, num: int) -> 「クエリ」:
        self.sql += f' LIMIT {num}'
        自分自身を返す

    def offset(self, num: int) -> 「クエリ」:
        self.sql += f'オフセット {num}'
        自分自身を返す

GROUP BY と HAVING をサポート

クラス クエリ:
    # ...

    def group_by(self, columns: Union[List, str]) -> 「クエリ」:
        if isinstance(columns, str):
            列 = [列]
        self.sql += f' GROUP BY {",".join([f"`{x}`" for x in columns])}'
        自分自身を返す

    def getting(self, 条件: 比較) -> 「クエリ」:
        self.sql += f' HAVING {condition.condition}'
        自分自身を返す

使用例

クラス ユーザー(モデル):
    名前 = フィールド()
    年齢 = フィールド()

# データを挿入
ユーザー = ユーザー(名前='トム'、年齢=24)
user.insert()

# クエリ条件とクエリ データを構築する
query = User.query().where((User.name == 'Tom') & (User.age >= 20)).order_by('age')。制限(1).オフセット(0)
query.get(User.name, User.age) # 指定されたフィールドのみをクエリします

# より複雑なクエリ
query = User.query().group_by('age').having((User.age > 20) & (User.age < 30)).order_by('age 39;).limit(10).offset(0)
query.get(User.age, User.count(User.name)) # 20 歳から 30 歳までのユーザーの数をクエリします

追加のクエリ機能を導入することで、このシンプルな ORM 実装がより強力かつ柔軟になります。

要約する

この一連の記事では、メタクラスを使用せずに単純な Python ORM を実装しました。データベース フィールドを表す クラス、データベース テーブルを表す クラス、クエリを構築および実行する クラスを定義します。この実装により、メタクラスの概念を深く理解することなく、データ操作を簡単に実行し、柔軟なクエリ条件を構築できます。  Field Model  Query 

ただし、この単純な ORM には、複雑なテーブルの関連付けなどの機能がサポートされていないなど、いくつかの制限があります。実際のプロジェクトでは、メタクラス ORM 実装を使用するか、他の成熟した ORM フレームワークを使用するかの選択は、プロジェクトのニーズとチームのテクノロジーの選択によって異なります。この実装により、異なる考え方が提供され、より多くの思考と議論が促進されることを願っています。

クリックしてフォローし、できるだけ早くHuawei Cloudの新しいテクノロジーについて学びましょう~

 

SenseTime 創設者、Tang Xiaoou 氏が 55 歳で死去 2023 年、PHP は停滞 Wi-Fi 7 が完全に利用可能になる2024 年初頭にデビュー、Wi-Fi 6 の 5 倍高速 Hongmeng システムが独立しつつあり、多くの大学が「Hongmeng クラス」を設立 Zhihui Jun の新興企業が借り換え、金額は 6 億元を超え、事前評価額は 35 億元 Quark Browser PC 版が内部テストを開始 AI コード アシスタントは人気があり、プログラミング言語のランキングはすべてです できることは何もありません Mate 60 Pro の 5G モデムと無線周波数技術ははるかに先を行っています MariaDB が SkySQL を分割し、確立されました独立した企業として<​​/span> Xiaomi、Yu Chengdong 氏の Huawei からの「キールピボット」盗作声明に対応
{{名前}}
{{名前}}

おすすめ

転載: my.oschina.net/u/4526289/blog/10322276