I have one app that dispatches a signal, let's call it signal_x
. In another app, a @receiver
for signal_x
is defined, and in it's apps.py's ready()
function is the file containing the receiver imported.
The @receiver
function has one issue though. It has a dependency to an object, let's call it object_y
, that has in it's constructor a dependency to the DB. With the values extracted from the DB, some heavy objects are built. These heavy_objects must be in memory, for very fast computations and thus they can't be lazily loaded as it would take too long when they're used for the first time. self.location_ids
can't be lazily loaded either, as it's used by the two compute_heavy_... functions.
Everything works completely fine until we drop the database, create it again and run manage.py makemigrations. Now makemigrations will fail because Django first runs django.setup()
, which runs the ready()
function of each app. When it reaches the ready()
function with the import it will, as expected, import the file and try creating object_y
. But object_y
needs models which don't yet exist and thus the error. How could I elegantly solve/circumvent this?
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)
This is a common use case. Since you didn't provide so much code, it's difficult to give you a very accurate answer, but, consider this:
AppConfig.ready()
function, you should always use self.get_model()
to retrieve a reference to a model defined in another app. This will ensure the app registry is up-to-date if require_ready=True
(the default). Outside a AppConfig
method, you can use apps.get_model()
object_y = HeavyObject()
). Note: I don't know if HeavyObject
is a Django model or not. But in general, you may declare object_y = None
by default and initialize the variable later