(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 по следующим причинам:

  1. в простых случаях, ORM может быть гораздо более удобным решение см. определения ORM.
  2. предположим, что уже установлены системы, такие как 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 должен находиться в контексте выполнения, показанном выше.