Разделение сигналов Django от классов, которые касаются БД - PullRequest
0 голосов
/ 15 мая 2018

У меня есть одно приложение, которое отправляет сигнал, назовем его signal_x. В другом приложении определено @receiver для signal_x, а в его apps.py 'ready() есть файл, содержащий импортированный получатель.

Функция @receiver имеет одну проблему. Он имеет зависимость от объекта, назовем его object_y, который имеет в своем конструкторе зависимость от БД. Из значений, извлеченных из БД, создаются некоторые тяжелые объекты. Эти тяжелые объекты должны находиться в памяти для очень быстрых вычислений, и поэтому их нельзя загружать лениво, поскольку это займет слишком много времени, когда они используются в первый раз. self.location_ids также нельзя загружать лениво, так как он используется двумя compute_heavy _... функциями.

Все работает отлично, пока мы не отбросим базу данных, не создадим ее снова и не запустим manage.py makemigrations . Теперь makemigrations потерпит неудачу, потому что Django сначала запускает django.setup(), который запускает функцию ready() каждого приложения. Когда он достигнет функции ready() с импортом, он, как и ожидалось, импортирует файл и попытается создать object_y. Но object_y нужны модели, которые еще не существуют, и, следовательно, ошибка. Как я мог элегантно решить / обойти это?

class Recommender:
    def __init__(self):
        self.location_ids = self.get_location_ids()
        self.heavy_object1 = self.compute_heavy_object1(location_ids)
        self.heavy_object2 = self.compute_heavy_object2(..., location_ids)

    def get_location_ids():
        locations = LocationNode.objects.filter(level=1, parent_id=1)
        return [location.id for location in locations]

... meantime in another file

object_y = Recommender()

@receiver(signal_x, dispatch_uid="update_state")
def recompute(sender, **kwargs):
    client_id = kwargs['client_id']
    # prepare some things
    heavy_recompute(object_y, client_id)

1 Ответ

0 голосов
/ 15 мая 2018

Это общий случай использования.Поскольку вы не предоставили так много кода, трудно дать вам очень точный ответ, но учтите следующее:

  • В функции AppConfig.ready() вы всегда должны использовать self.get_model() для получения ссылки на модель, определенную в другом приложении.Это обеспечит актуальность реестра приложения, если require_ready=True (по умолчанию).Вне метода AppConfig вы можете использовать apps.get_model()
  • Не создавать экземпляр модели на уровне модуля (object_y = HeavyObject()).Примечание: я не знаю, является ли HeavyObject моделью Джанго или нет.Но в целом вы можете объявить object_y = None по умолчанию и инициализировать переменную позже
...