Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why is __init__ module in django project loaded twice

Tags:

python

django

I put

print 'Hello world!'

into __init__.py in my django project. When I run ./manage.py runserver now, I get

gruszczy@gruszczy-laptop:~/Programy/project$ ./manage.py runserver
Hello world!
Hello world!
Validating models...
0 errors found

Why is __init__.py run twice? It should be loaded only once.

like image 893
gruszczy Avatar asked Jan 21 '10 15:01

gruszczy


2 Answers

It should be loaded only once... per process. I'm guessing that manage.py forks, and that two separate processes are launched. Could you print the result of os.getpid()?

like image 179
Thomas Avatar answered Oct 20 '22 00:10

Thomas


After learning the --noreload option from the above answer, I found that both

% django-admin help runserver
% manage.py help runserver

map to the below code in django/core/management/commands/runserver.py

parser.add_argument(
    '--noreload', action='store_false', dest='use_reloader',
    help='Tells Django to NOT use the auto-reloader.',
)

Both django-admin.py and manage.py call

django.core.management.execute_from_command_line(sys.argv) 

I then started to trace the Django code to better understand why the two PIDs when --noreload is not given.

In below, we have

class BaseCommand defined in management/base.py and 
class Command(BaseCommand) defined in management/commands/runserver.py

    execute_from_command_line(sys.argv) ==>> utility.execute() ==>>
    self.fetch_command(subcommand).run_from_argv(self.argv) ==>>
    self.execute(*args, **cmd_options) in management/base.py ==>>
        super().execute(*args, **options) in commands/runserver.py ==>>
    output = self.handle(*args, **options) in base.py ==>>
        self.run(**options) in commands/runserver.py  ==>>
    if use_reloader:
        autoreload.run_with_reloader(self.inner_run, **options)
    else:
        self.inner_run(None, **options)  // --noreload


    ParentPID run_with_reloader() ==>> DJANGO_AUTORELOAD_ENV = None ==>> 
    restart_with_reloader() only runs the 1st time by PPID ==>>
    ==>> subprocess.call(DJANGO_AUTORELOAD_ENV = true) ==>> child process cPID
    cPID run_with_reloader() ==>> "Watching for file changes with StatReloader"
    ==>> start_django(StatReloader, Command.inner_run) ==>>
    django_main_thread = threading.Thread(target=inner_run) and
    StatReloader.run(django_main_thread)
    ==>> Performing system checks... Starting development server at
    http://127.0.0.1:8080/

    The StatReloader(BaseReloader) will check file changes once per second.
    If there is a a file write => notify_file_changed(timestamp delta) =>
    trigger_reload() and PPID will spawn a new cPID and the old cPID is gone 
    so that we don't have to restart the runserver whenever there is a code change.

With the --noreload option, PPID executes inner_run() directly and skips the cPID subprocess for auto-reloading. If you kill either PPID or cPID, the whole process dies.

like image 4
Leon Chang Avatar answered Oct 19 '22 23:10

Leon Chang