(Django) ORM in airflow - возможно ли это?
как работать с моделями Django внутри задач воздушного потока?
согласно официальной документации Airflow, Airflow предоставляет крючки для взаимодействия с базами данных (например, MySqlHook / PostgresHook / etc), которые могут быть позже использованы в операторах для выполнения запроса строки. Прикрепление фрагментов кода ядра:
копировать из 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)
как мы видим, крюк инкапсулирует конфигурацию соединения, а оператор предоставляет возможность выполнять пользовательские запросы.
проблема:
очень удобно использовать различные ORM для выборки и обработки объектов базы данных вместо raw SQL по следующим причинам:
- в простых случаях, ORM может быть гораздо более удобным решение см. определения ORM.
- предположим, что уже установлены системы, такие как Django с определенными моделями и их методами. Каждый раз, когда схемы этих моделей меняются, запросы airflow raw SQL должны быть переписаны. ORM предоставляет унифицированный интерфейс для работы с такими моделями.
по какой-то причине нет примеров работы с ORM в задачах воздушного потока с точки зрения крючков и операторов. Согласно использование базы данных Django слой за Джанго? вопрос, необходимо настроить конфигурацию соединения с базой данных, а затем прямо вперед выполнить queires в ORM, но делать это вне соответствующих крючков / операторов нарушает воздушный поток принципы. Это похоже на вызов BashOperator с "python work_with_django_models.py" команда.
наконец, мы хотим этого:
Итак, каковы лучшие практики в этом случае? Разделяем ли мы какие-либо крючки / операторы для Django ORM / других ORMs? Для того, чтобы иметь следующий код real (рассматривать как псевдо-код!):
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')
вместо реализации этой функции в raw SQL.
Я думаю, что это довольно важная тема, так как весь банк рамок и процессов на основе ORM не в состоянии погрузиться в Воздушный поток в этом случае.
спасибо заранее!
1 ответов
Я согласен, что мы должны продолжать эту дискуссию, поскольку доступ к 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 должен находиться в контексте выполнения, показанном выше.