5

I have some django code that needs to run once when my app is loaded in the dev server or as a wsgi worker. This code also needs to write to the database. In my particular case I do not need the code to run for many management commands like collectstatic or createsuperuser, etc.

This SO question "Where to put Django startups code?" recommends using AppConfig.ready for startup code.

However, the docs for the ready function clearly warn against interacting with the database:

Although you can access model classes as described above, avoid interacting with the database in your ready() implementation. This includes model methods that execute queries (save(), delete(), manager methods etc.), and also raw SQL queries via django.db.connection. Your ready() method will run during startup of every management command. For example, even though the test database configuration is separate from the production settings, manage.py test would still execute some queries against your production database!

Is there some later startup hook I should use for code that does need to update the database?

The code registers my server as a webhook endpoint with a 3rd party service and stores required connection information in the database. I only register for the webhook if not already configured.

mightyroser
  • 780
  • 6
  • 10
  • 1
    What exactly do you mean by "startup"? The django environment can be initialized in a number of situations - starting the dev server, starting a wsgi worker, running any management command. – Vinay Pai Sep 10 '19 at 15:20
  • And you should be a bit more specific about what this code would do. Why do you think you need to update the database on startup? – Daniel Roseman Sep 10 '19 at 15:30
  • I've edited my question to clarify that I only really need the code to run in the dev server and wsgi worker cases. – mightyroser Sep 10 '19 at 15:30
  • 1
    But surely that only needs to happen once *ever* for each of those, not every time you start up the server. So it would be best as a management command that you can run when you need to. – Daniel Roseman Sep 10 '19 at 15:51
  • 1
    @DanielRoseman, you bring up a good point. Normally this only has to be run once per server. I was hoping for a more automatic solution than a management command. I have multiple copies of my server ( test, stage, production, etc. ) that would need to connect to the webhooks. A management command is one additional step that someone will eventually forget leaving a server out of configuration. – mightyroser Sep 10 '19 at 19:12

1 Answers1

0

We have a similar use case: If the server is restarted, it needs to manage database information in order to not leave some procedures in stall state.

The way we solve this is with a systemd script, only executed once during startup, which calls a script, which performs operations in django's database.

1) Create a python script that will do the required operations and changes to the database:

/djangoproject/boot_script.py

Which contains:

from yourdjangoapp.models import XModel
# DO STUFF WITH XModel

2) Create a script wich calls to a python script for django:

/.../execute_boot_script.sh

Which contains:

cd /djangoproject
python manage.py shell < boot_script.py

And has execution rights:

sudo chmod +x /.../execute_boot_script.sh

3) Create a file for the service:

/etc/systemd/system/execute_boot_script.service

which contains:

[Unit]
After=apache2.service

[Service]
Environment=ENVPATH=:/usr/local/... # ONLY IF YOU NEED TO SET SOME ENVIRONMENT VARIABLE
Type=oneshot
ExecStart=/.../execute_boot_script.sh

[Install]
WantedBy=multi-user.target

More info: https://linuxconfig.org/how-to-automatically-execute-shell-script-at-startup-boot-on-systemd-linux

This answer works in linux, but could be also easily achieved in windows with a programmed task launched at startup, though.

Anr
  • 332
  • 3
  • 6