Django.db.models.loading.get_model против импорта

Есть ли недостаток в использовании чего-то вроде

from django.db.models.loading import get_model

def get_something():
    model = get_model('app', 'Model')
    return model.something()

вместо

from app.models import Model

def get_something():
    return Model.something()

Второй пример может привести к циклическим зависимостям, в то время как в первом примере это не так, но второй пример показан гораздо чаще.

Обновить. Вы получите ошибки циклической зависимости, если второй пример был в модели под названием Other_Model и Model импортировал Other_Model, а также - простой циклический импорт.

Ответ 1

Как правило, функциональность get_model зарезервирована для времени, когда модель должна загружаться динамически (скажем, если вы не знаете, будет ли кто-то передавать услугу myapp.Person, myapp.Place или myapp.Thing и все они имеют один и тот же интерфейс). Я пойду так далеко, чтобы сказать, что любое другое использование должно быть автоматически помечено в обзоре кода, если только по той причине, что он вводит неожиданное.

Что касается внутренней механики, то действительно нет существенной разницы. Неизбежно версия get_model вызовет __import__. Тем не менее, не без ошибок. Использование фактических операторов import позволит избежать этой проблемы.


Что касается вопросов MRO, это редкая ситуация, когда циклический импорт не может быть решен путем рефакторинга. Если у вас есть два приложения, которые настолько взаимозависимы, что они вызывают циклический импорт, вам действительно нужно переосмыслить эти приложения. (Мое предположение, что вы действительно имеете дело с одним приложением.)

Ответ 2

Использование get_model может сбивать с толку, если путь к вашему приложению не так прямо.

Например, если ваша модель существует в apps.MyApp.models.misc.MyModel, тогда вызов будет get_model('MyApp', 'misc.MyModel'), который не слишком интуитивно понятен. Вероятно, вам придется выяснить это методом проб и ошибок или выкапыванием в исходный код.

(Обратите внимание, что это относится к Django 1.6 и ранее. Django 1.7+ имеет множество изменений в названии приложения, и это может измениться)


Другой способ избежать круговых зависимостей - сделать импорт непосредственно в методе следующим образом:

def get_something():
    from app.models import Model
    return Model.something()

Это отложит импорт до первого вызова метода.