Airflowタスク内でDjangoモデルを操作する方法は?
公式のAirflowドキュメントによると、Airflowは、後で行クエリを実行するためにOperatorsで使用できるデータベース(MySqlHook/PostgresHookなど)と対話するためのフックを提供します。コアコードフラグメントの添付:
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
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を使用すると非常に便利です。
何らかの理由で、フックとオペレーターの観点から、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に飛び込むことができないため、これは非常に重要なトピックだと思います。
前もって感謝します!
アクセス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モデルのインポートは、上記で示した実行コンテキスト内にある必要があることに注意してください。