14

On Django startup I need to run some code that requires access to the database. I prefer to do this via models.

Here's what I currently have in apps.py:

from django.apps import AppConfig
from .models import KnowledgeBase

class Pqawv1Config(AppConfig):
    name = 'pqawV1'

    def ready(self):
        to_load = KnowledgeBase.objects.order_by('-timestamp').first()
        # Here should go the file loading code

However, this gives the following exception:

django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

So is there a place in Django to run some startup code after the models are initialized?

Serge Rogatch
  • 13,865
  • 7
  • 86
  • 158
  • 1
    Move the `from .models import KnowledgeBase` *inside* the `def ready` method. Here importing it in the header results in the fact that the models are loaded too early. – Willem Van Onsem Jan 05 '19 at 20:09
  • 1
    @WillemVanOnsem, this works, thanks. But how good is this solution? What are the side effects? I'm quite new to Python... – Serge Rogatch Jan 05 '19 at 20:10
  • 1
    the difference is that you simply only import `.models` when the config calls `ready`, you thus postpone importing. It was due to "eager" importing that this resulted in trouble. – Willem Van Onsem Jan 05 '19 at 20:12

1 Answers1

18

The problem is that you import .models at the top of your file. This means that, when the file app.py file is loaded, Python will load the models.py file when it evalutes that line. But that is too early. You should let Django do the loading properly.

You can move the import in the def ready(self) method, such that the models.py file is imported when ready() is called by the Django framework, like:

from django.apps import AppConfig

class Pqawv1Config(AppConfig):
    name = 'pqawV1'

    def ready(self):
        from .models import KnowledgeBase
        to_load = KnowledgeBase.objects.order_by('-timestamp').first()
        # Here should go the file loading code
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Once the data or resources is loaded in `ready()`, how could we use them in `views`? Import appconfig? – avocado Mar 09 '20 at 08:58
  • 1
    @advocado: you can obtain the appconfig for a given app with `from django.apps import apps`; `apps.get_app_config('app_name')`. If you store your resorce that is loaded on the `self` (so `self.to_load = ...`), you thus can access it with `apps.get_app_config('app_name').to_load`. But you should do that in a function, since the models are loaded *before* the `ready` function is triggered. – Willem Van Onsem Mar 09 '20 at 11:45
  • Great (and also concise) answer! – avocado Mar 09 '20 at 17:32
  • As an aside, `from .models import *` will fail ("SyntaxError: import * only allowed at module level") while `from .models import KnowledgeBase` will succeed – There Jun 22 '21 at 20:31
  • 1
    This is [explicitly discouraged](https://docs.djangoproject.com/en/4.1/ref/applications/#django.apps.AppConfig.ready) by the docs. The reason is if you run tests, the `ready()` code will still run against your production database, not the test database. See [discussion here](https://code.djangoproject.com/ticket/22002). – Yatharth Agarwal Sep 14 '22 at 07:52