web-dev-qa-db-ja.com

(Django)気流のORM-それは可能ですか?

Airflowタスク内でDjangoモデルを操作する方法は?

公式のAirflowドキュメントによると、Airflowは、後で行クエリを実行するためにOperatorsで使用できるデータベース(MySqlHook/PostgresHookなど)と対話するためのフックを提供します。コアコードフラグメントの添付:

からコピー https://airflow.Apache.org/_modules/mysql_hook.html

class MySqlHook(DbApiHook):
    conn_name_attr = 'mysql_conn_id'
    default_conn_name = 'mysql_default'
    supports_autocommit = True

    def get_conn(self):
        """
        Returns a mysql connection object
        """
        conn = self.get_connection(self.mysql_conn_id)
        conn_config = {
            "user": conn.login,
            "passwd": conn.password or ''
        }
        conn_config["Host"] = conn.Host or 'localhost'
        conn_config["db"] = conn.schema or ''
        conn = MySQLdb.connect(**conn_config)
        return conn

からコピー https://airflow.Apache.org/_modules/mysql_operator.html

class MySqlOperator(BaseOperator):
    @apply_defaults
    def __init__(
            self, sql, mysql_conn_id='mysql_default', parameters=None,
            autocommit=False, *args, **kwargs):
        super(MySqlOperator, self).__init__(*args, **kwargs)
        self.mysql_conn_id = mysql_conn_id
        self.sql = sql
        self.autocommit = autocommit
        self.parameters = parameters

    def execute(self, context):
        logging.info('Executing: ' + str(self.sql))
        hook = MySqlHook(mysql_conn_id=self.mysql_conn_id)
        hook.run(
            self.sql,
            autocommit=self.autocommit,
            parameters=self.parameters)

ご覧のとおり、Hookは接続構成をカプセル化し、Operatorはカスタムクエリを実行する機能を提供します。

問題:

次の理由により、生のSQLの代わりにデータベースオブジェクトのフェッチと処理に異なるORMを使用すると非常に便利です。

  1. 単純なケースでは、ORMがはるかに便利なソリューションになる可能性があります。 ORM定義 を参照してください。
  2. Djangoのような、定義されたモデルとそのメソッドを備えたシステムがすでに確立されていると仮定します。これらのモデルのスキーマが変更されるたびに、エアフローの生のSQLクエリを書き直す必要があります。ORMは、そのようなものを操作するための統合インターフェースを提供します。モデル。

何らかの理由で、フックとオペレーターの観点から、AirflowタスクでORMを使用する例はありません。 Django Djangoの外部のデータベースレイヤーを使用していますか? 質問によると、データベースへの接続構成をセットアップしてから、ORMでクワイアを直接実行する必要があります。しかし、適切なフック/演算子の外でそれを行うと、Airflow principles が壊れます。これは、 "python work_with_Django_models.py"コマンドでBashOperatorを呼び出すようなものです。

最後に、これが必要です。

では、この場合の最良の方法は何ですか? Django ORM /他のORMのフック/演算子を共有しますか?次のコードを実際にするために(疑似コードとして扱います!):

import os
import Django
os.environ.setdefault(
    "Django_SETTINGS_MODULE",
    "myapp.settings"
)
Django.setup()
from your_app import models

def get_and_modify_models(ds, **kwargs):
    all_objects = models.MyModel.objects.filter(my_str_field = 'abc')
    all_objects[15].my_int_field = 25
    all_objects[15].save()
    return list(all_objects)

Django_op = DjangoOperator(task_id='get_and_modify_models', owner='airflow')

この機能を生のSQLに実装する代わりに。

この場合、ORMベースのフレームワークとプロセスの全体がAirflowに飛び込むことができないため、これは非常に重要なトピックだと思います。

前もって感謝します!

12
Pleeea

アクセスDjango ORMを使用すると、ソリューションの複雑さを大幅に軽減できるため、この議論を継続する必要があることに同意します。

私のアプローチは、1)DjangoOperatorを作成することでした。

import os, sys

from airflow.models import BaseOperator


def setup_Django_for_airflow():
    # Add Django project root to path
    sys.path.append('./project_root/')

    os.environ.setdefault("Django_SETTINGS_MODULE", "myapp.settings")

    import Django
    Django.setup()


class DjangoOperator(BaseOperator):

    def pre_execute(self, *args, **kwargs):
        setup_Django_for_airflow()

2)論理/演算子のためにそのDjangoOperatorを拡張し、ORMにアクセスすることで何が得られるか

from .base import DjangoOperator


class DjangoExampleOperator(DjangoOperator):

    def execute(self, context):
        from myApp.models import model
        model.objects.get_or_create()

この戦略を使用すると、Raw SQL/ORMを使用する演算子を区別できます。また、Django演算子の場合、すべてのDjangoモデルのインポートは、上記で示した実行コンテキスト内にある必要があることに注意してください。

12
Ryan Stack