142
Update from Pykler’s answer below: Django 1.7 now has a hook for this
Don’t do it this way.
You don’t want “middleware” for a one-time startup thing.
You want to execute code in the top-level urls.py
. That module is imported and executed once.
urls.py
from django.confs.urls.defaults import *
from my_app import one_time_startup
urlpatterns = ...
one_time_startup()
348
Update: Django 1.7 now has a hook for this
file: myapp/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'myapp'
verbose_name = "My Application"
def ready(self):
pass # startup code here
file: myapp/__init__.py
default_app_config = 'myapp.apps.MyAppConfig'
For Django < 1.7
The number one answer does not seem to work anymore, urls.py is loaded upon first request.
What has worked lately is to put the startup code in any one of your INSTALLED_APPS init.py e.g. myapp/__init__.py
def startup():
pass # load a big thing
startup()
When using ./manage.py runserver
… this gets executed twice, but that is because runserver has some tricks to validate the models first etc … normal deployments or even when runserver auto reloads, this is only executed once.
- [Django]-Convert Django Model object to dict with all of the fields intact
- [Django]-Data Mining in a Django/Postgres application
- [Django]-Django models: mutual references between two classes and impossibility to use forward declaration in python
47
This question is well-answered in the blog post Entry point hook for Django projects, which will work for Django >= 1.4.
Basically, you can use <project>/wsgi.py
to do that, and it will be run only once, when the server starts, but not when you run commands or import a particular module.
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings")
# Run startup code!
....
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
- [Django]-DRF: custom ordering on related serializers
- [Django]-How to add a cancel button to DeleteView in django
- [Django]-Django REST Framework: how to substitute null with empty string?
27
As suggested by @Pykler, in Django 1.7+ you should use the hook explained in his answer, but if you want that your function is called only when run server is called (and not when making migrations, migrate, shell, etc. are called), and you want to avoid AppRegistryNotReady exceptions you have to do as follows:
file: myapp/apps.py
import sys
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'my_app'
def ready(self):
if 'runserver' not in sys.argv:
return True
# you must import your modules here
# to avoid AppRegistryNotReady exception
from .models import MyModel
# startup code here
- [Django]-When saving, how can you check if a field has changed?
- [Django]-Django create userprofile if does not exist
- [Django]-Default value for user ForeignKey with Django admin
21
If it helps someone, in addition to pykler’s answer, “–noreload” option prevents runserver from executing command on startup twice:
python manage.py runserver --noreload
But that command won’t reload runserver after other code’s changes as well.
- [Django]-Django simple_tag and setting context variables
- [Django]-Function decorators with parameters on a class based view in Django
- [Django]-Django models: default value for column
17
Standard solution
With Django 3.1+ you can write this code to execute only once a method at startup. The difference from the other questions is that the main starting process is checked (runserver by default starts 2 processes, one as an observer for quick code reload):
import os
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'app_name'
def ready(self):
if os.environ.get('RUN_MAIN'):
print("STARTUP AND EXECUTE HERE ONCE.")
# call here your code
Another solution is avoiding the environ check but call –noreload to force only one process.
Alternative method
The first question to answer is why we need to execute code once: usually we need to initialize some services, data in the database or something one-shot. The 90% of the time it is some database initialization or job queue.
The approach to use the AppConfig.ready() method is not reliable, not always reproducible in production and it cannot guarantee to be executed exactly once (but at least once that is not the same). To have something quite predictable and executed exactly one time the best approach is developing a Django BaseCommand and call it from a startup script.
So for example, we can code in your "myapp", in the file "app/management/commands/init_tasks.py":
from django.core.management.base import BaseCommand
from project.apps.myapp.tasks import scheduler
from project import logger, initialize_database_data
class Command(BaseCommand):
help = "Init scheduler or do some staff in the database."
def handle(self, *args, **options):
scheduler.reload_jobs()
initialize_database_data()
logger.info("Inited")
And finally we can have a start script "Start.bat" (in the example a windows batch) to setup the full application start:
start /b python manage.py qcluster
start /b python manage.py runserver 0.0.0.0:8000
start /b python manage.py init_tasks
- [Django]-Itertools.groupby in a django template
- [Django]-Django limit_choices_to for multiple fields with "or" condition
- [Django]-Whats the difference between using {{STATIC_URL}} and {% static %}
13
Note that you cannot reliability connect to the database or interact with models inside the AppConfig.ready
function (see the warning in the docs).
If you need to interact with the database in your start-up code, one possibility is to use the connection_created
signal to execute initialization code upon connection to the database.
from django.dispatch import receiver
from django.db.backends.signals import connection_created
@receiver(connection_created)
def my_receiver(connection, **kwargs):
with connection.cursor() as cursor:
# do something to the database
Obviously, this solution is for running code once per database connection, not once per project start. So you’ll want a sensible value for the CONN_MAX_AGE
setting so you aren’t re-running the initialization code on every request. Also note that the development server ignores CONN_MAX_AGE
, so you WILL run the code once per request in development.
99% of the time this is a bad idea – database initialization code should go in migrations – but there are some use cases where you can’t avoid late initialization and the caveats above are acceptable.
- [Django]-Inline in ModelForm
- [Django]-Django Queryset with year(date) = '2010'
- [Django]-Suddenly when running tests I get "TypeError: 'NoneType' object is not iterable
2
if you want print “hello world” once time when you run server, put print (“hello world”) out of class StartupMiddleware
from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings
class StartupMiddleware(object):
def __init__(self):
#print "Hello world"
raise MiddlewareNotUsed('Startup complete')
print "Hello world"
- [Django]-Having Django serve downloadable files
- [Django]-How to convert JSON data into a Python object?
- [Django]-Custom django admin templates not working
0
In my case, I use Django to host a site, and using Heroku. I use 1 dyno (just like 1 container) at Heroku, and this dyno creates two workers.
I want to run a discord bot on it. I tried all methods on this page and all of them are invalid.
Because it is a deployment, so it should not use manage.py. Instead, it uses gunicorn, which I don’t know how to add --noreload
parameter.
Each worker runs wsgi.py once, so every code will be run twice. And the local env of two workers are the same.
But I notice one thing, every time Heroku deploys, it uses the same pid worker. So I just
if not sys.argv[1] in ["makemigrations", "migrate"]: # Prevent execute in some manage command
if os.getpid() == 1: # You should check which pid Heroku will use and choose one.
code_I_want_excute_once_only()
I’m not sure if the pid will change in the future, hope it will be the same forever. If you have a better method to check which worker is it, please tell me.
- [Django]-Allowing only super user login
- [Django]-Creating email templates with Django
- [Django]-Difference between User.objects.create_user() vs User.objects.create() vs User().save() in django
0
I used the accepted solution from here which checks if it was run as a server, and not when executing other managy.py
commands such as migrate
apps.py:
from .tasks import tasks
class myAppConfig(AppConfig):
...
def ready(self, *args, **kwargs):
is_manage_py = any(arg.casefold().endswith("manage.py") for arg in sys.argv)
is_runserver = any(arg.casefold() == "runserver" for arg in sys.argv)
if (is_manage_py and is_runserver) or (not is_manage_py):
tasks.is_running_as_server = True
And since that will still get executed twice when in development mode, without using the parameter --noreload
, I added a flag to be triggered when it is running as a server and put my start up code in urls.py
which is only called once.
tasks.py:
class tasks():
is_running_as_server = False
def runtask(msg):
print(msg)
urls.py:
from . import tasks
task1 = tasks.tasks()
if task1.is_running_as_server:
task1.runtask('This should print once and only when running as a server')
So to summarize, I am utilizing the read() function in AppConfig to read the arguments and know how the code was executed. But since in the development mode the ready() function is run twice, one for the server and one for the reloading of the server when the code changes, while urls.py
is only executed once for the server. So in my solution i combined the two to run my task once and only when the code is executed as a server.
- [Django]-TransactionManagementError "You can't execute queries until the end of the 'atomic' block" while using signals, but only during Unit Testing
- [Django]-How to test "render to template" functions in django? (TDD)
- [Django]-Row level permissions in django