[Django] 원본 해석 Django 시작 및 접근 프로세스 (1)
44808 단어 Django는 입문부터 정통까지.
전언
‘python manage.py runserver ip:port’ django , manage.py , django 。
manage.py
#
os.makedirs('../logs')
#
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "jumpserver.settings")
# manage.py ,
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
optional arguments:
-h, --help show this help message and exit
--ipv6, -6 Tells Django to use an IPv6 address. # IPV6,
--nothreading Tells Django to NOT use threading. # ,
--noreload Tells Django to NOT use the auto-reloader. # ,
--noasgi Run the old WSGI-based runserver rather than the ASGI-based one
--http_timeout HTTP_TIMEOUT
Specify the daphne http_timeout interval in seconds (default: no timeout)
--websocket_handshake_timeout WEBSOCKET_HANDSHAKE_TIMEOUT
Specify the daphne websocket_handshake_timeout interval in seconds (default: 5)
--version show program's version number and exit
-v {0,1,2,3}, --verbosity {0,1,2,3}
Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output
--settings SETTINGS The Python path to a settings module, e.g. "myproject.settings.main". If this isn't provided, the DJANGO_SETTINGS_MODULE environment variable will be used.
--pythonpath PYTHONPATH
A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".
--traceback Raise on CommandError exceptions
--no-color Don't colorize the command output.
--force-color Force colorization of the command output.
위 코드에서 알 수 있듯이 시작 파라미터는'django.'에 건네졌다.core.management.init.execute_from_command_라인 처리.
django.core.management.init.execute_from_command_line
def execute_from_command_line(argv=None):
"""Run a ManagementUtility."""
# ManagementUtility
utility = ManagementUtility(argv)
# , [‘manage.py’, 'runserver','0.0.0.0:8000',...] ,
utility.execute()
위에서 알 수 있듯이 접근 매개 변수는'django'에 계속 전달되었다.core.management.init.ManagementUtility 인스턴스의 "execute"메서드를 처리합니다.
django.core.management.init.ManagementUtility.execute
#
...
# ,runserver
subcommand = self.argv[1]
...
# , --settings --pythonpath
options, args = parser.parse_known_args(self.argv[2:])
#
handle_default_options(options)
....
# INSTALLED_APPS,
try:
settings.INSTALLED_APPS
except ImproperlyConfigured as exc:
self.settings_exception = exc
except ImportError as exc:
self.settings_exception = exc
#
if settings.configured:
# Start the auto-reloading dev server even if the code is broken.
# The hardcoded condition is a code smell but we can't rely on a
# flag on the command class because we haven't located it yet.
#
if subcommand == 'runserver' and '--noreload' not in self.argv:
try:
# --noreload,
autoreload.check_errors(django.setup)()
except Exception:
...
# In all other cases, django.setup() is required to succeed.
else:
django.setup()
...
# self.fetch_command(subcommand) get_command argv[1]
# ‘if isinstance(app_name, BaseCommand):klass = app_name;’ BaseCommand
# BaseCommand run_from_argv , django.contrib.staticfiles.management.commands.runserver.Command
self.fetch_command(subcommand).run_from_argv(self.argv)
위 코드에서'fetch 'command'통과'django.core.management.init.ManagementUtility.get_commands () '는 실행하는 구체적인 명령을 해석한 다음 명령을 통과하는runfrom_argv 시작 서비스.
django.core.management.init.ManagementUtility.get_commands()
# , get_commands
@functools.lru_cache(maxsize=None)
def get_commands():
"""
Return a dictionary mapping command names to their callback applications.
Look for a management.commands package in django.core, and in each
installed application -- if a commands package exists, register all
commands in that package.
Core commands are always included. If a settings module has been
specified, also include user-defined commands.
The dictionary is in the format {command_name: app_name}. Key-value
pairs from this dictionary can then be used in calls to
load_command_class(app_name, command_name)
If a specific version of a command must be loaded (e.g., with the
startapp command), the instantiated module can be placed in the
dictionary in place of the application name.
The dictionary is cached on the first call and reused on subsequent
calls.
"""
# find_commands commands
# django.core.management.commands
commands = {
name: 'django.core' for name in find_commands(__path__[0])}
# , commands
if not settings.configured:
return commands
# INSTALLED_APPS, APP management.commands
# App ,
# 'django.contrib.staticfiles' management.commands runserver.py
# django.core.management.commands runserver.py
for app_config in reversed(list(apps.get_app_configs())):
path = os.path.join(app_config.path, 'management')
commands.update({
name: app_config.name for name in find_commands(path)})
return commands
위 코드에서 알 수 있듯이 django는 먼저'django'로 간다.core.management.commands는 명령 모듈을 가져와 등록된 app 아래의 관리를 통해 가져옵니다.commands 디렉터리 아래에서 명령 모듈을 가져오고 앞에서 가져온 같은 이름의 모듈을 덮어씁니다.실제로runserver가 실행하는 것은 등록된staticfiles라는 응용 프로그램 아래의 runserer 모듈입니다. 다음은 이 모듈을 해석합니다.
django.contrib.staticfiles.management.commands.runserver.py
from django.conf import settings
from django.contrib.staticfiles.handlers import StaticFilesHandler
from django.core.management.commands.runserver import (
Command as RunserverCommand,
)
class Command(RunserverCommand):
help = "Starts a lightweight Web server for development and also serves static files."
def add_arguments(self, parser):
super().add_arguments(parser)
parser.add_argument(
'--nostatic', action="store_false", dest='use_static_handler',
help='Tells Django to NOT automatically serve static files at STATIC_URL.',
)
parser.add_argument(
'--insecure', action="store_true", dest='insecure_serving',
help='Allows serving static files even if DEBUG is False.',
)
def get_handler(self, *args, **options):
"""
Return the static files serving handler wrapping the default handler,
if static files should be served. Otherwise return the default handler.
"""
handler = super().get_handler(*args, **options)
use_static_handler = options['use_static_handler']
insecure_serving = options['insecure_serving']
if use_static_handler and (settings.DEBUG or insecure_serving):
return StaticFilesHandler(handler)
return handler
이 명령은'django'에서 상속됩니다.core.management.commands.runserver.Command', run 없음from_argv 방법, 계속 아래로 해석.
django.core.management.commands.runserver.Command
from django.core.management.base import BaseCommand, CommandError
class Command(BaseCommand):
help = "Starts a lightweight Web server for development."
# Validation is called explicitly each time the server is reloaded.
requires_system_checks = False
stealth_options = ('shutdown_message',)
default_addr = '127.0.0.1'
default_addr_ipv6 = '::1'
default_port = '8000'
protocol = 'http'
server_cls = WSGIServer
def add_arguments(self, parser):
# django.contrib.staticfiles.management.commands.runserver.Command.add_arguments
...
def execute(self, *args, **options):
if options['no_color']:
# We rely on the environment because it's currently the only
# way to reach WSGIRequestHandler. This seems an acceptable
# compromise considering `runserver` runs indefinitely.
os.environ["DJANGO_COLORS"] = "nocolor"
super().execute(*args, **options)
def get_handler(self, *args, **options):
# django.contrib.staticfiles.management.commands.runserver.Command.get_handler
...
def handle(self, *args, **options):
if not settings.DEBUG and not settings.ALLOWED_HOSTS:
raise CommandError('You must set settings.ALLOWED_HOSTS if DEBUG is False.')
self.use_ipv6 = options['use_ipv6']
if self.use_ipv6 and not socket.has_ipv6:
raise CommandError('Your Python does not support IPv6.')
self._raw_ipv6 = False
if not options['addrport']:
self.addr = ''
self.port = self.default_port
else:
m = re.match(naiveip_re, options['addrport'])
if m is None:
raise CommandError('"%s" is not a valid port number '
'or address:port pair.' % options['addrport'])
self.addr, _ipv4, _ipv6, _fqdn, self.port = m.groups()
if not self.port.isdigit():
raise CommandError("%r is not a valid port number." % self.port)
if self.addr:
if _ipv6:
self.addr = self.addr[1:-1]
self.use_ipv6 = True
self._raw_ipv6 = True
elif self.use_ipv6 and not _fqdn:
raise CommandError('"%s" is not a valid IPv6 address.' % self.addr)
if not self.addr:
self.addr = self.default_addr_ipv6 if self.use_ipv6 else self.default_addr
self._raw_ipv6 = self.use_ipv6
self.run(**options)
def run(self, **options):
"""Run the server, using the autoreloader if needed."""
use_reloader = options['use_reloader']
if use_reloader:
autoreload.run_with_reloader(self.inner_run, **options)
else:
self.inner_run(None, **options)
def inner_run(self, *args, **options):
# If an exception was silenced in ManagementUtility.execute in order
# to be raised in the child process, raise it now.
autoreload.raise_last_exception()
threading = options['use_threading']
# 'shutdown_message' is a stealth option.
shutdown_message = options.get('shutdown_message', '')
quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'
self.stdout.write("Performing system checks...
")
self.check(display_num_errors=True)
# Need to check migrations here, so can't use the
# requires_migrations_check attribute.
self.check_migrations()
now = datetime.now().strftime('%B %d, %Y - %X')
self.stdout.write(now)
self.stdout.write((
"Django version %(version)s, using settings %(settings)r
"
"Starting development server at %(protocol)s://%(addr)s:%(port)s/
"
"Quit the server with %(quit_command)s.
"
) % {
"version": self.get_version(),
"settings": settings.SETTINGS_MODULE,
"protocol": self.protocol,
"addr": '[%s]' % self.addr if self._raw_ipv6 else self.addr,
"port": self.port,
"quit_command": quit_command,
})
try:
handler = self.get_handler(*args, **options)
run(self.addr, int(self.port), handler,
ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
except socket.error as e:
# Use helpful error messages instead of ugly tracebacks.
ERRORS = {
errno.EACCES: "You don't have permission to access that port.",
errno.EADDRINUSE: "That port is already in use.",
errno.EADDRNOTAVAIL: "That IP address can't be assigned to.",
}
try:
error_text = ERRORS[e.errno]
except KeyError:
error_text = e
self.stderr.write("Error: %s" % error_text)
# Need to use an OS exit because sys.exit doesn't work in a thread
os._exit(1)
except KeyboardInterrupt:
if shutdown_message:
self.stdout.write(shutdown_message)
sys.exit(0)
django.contrib.staticfiles.management.commands.runserver는django에서 계승합니다.core.management.commands.runserver django.core.management.commands.runserver는django에서 계승합니다.core.management.base.BaseCommand 아래에서 runfrom_argv 방법은 남은 시작 과정을 계속 분석합니다
django.core.management.base.BaseCommand.run_from_argv
...
# ,
# django.core.management.commands.runserver.Command.execute, ‘DJANGO_COLORS’
# execute
self.execute(*args, **cmd_options)
#
connections.close_all()
'django'에 부팅 매개 변수가 전달되었습니다.core.management.base.BaseCommand.execute '가 계속 처리됩니다.
django.core.management.base.BaseCommand.execute
...
#
# django.core.management.commands.runserver.Command.requires_system_checks=False,
if self.requires_system_checks and not options.get('skip_checks'):
self.check()
# ,
if self.requires_migrations_checks:
self.check_migrations()
# , django.core.management.commands.runserver.Command.handle
output = self.handle(*args, **options)
...
'django'에 부팅 매개 변수가 전달되었습니다.core.management.commands.runserver.Command.handle'계속 처리.다음 편, 우리는'django'에서core.management.commands.runserver.Command.handle'django의 시작 원본 계속 분석
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[Django] 원본 해석 Django 시작 및 접근 프로세스 (4)Django 액세스 프로세스(둘) Django 방문 과정 (1) 에서 우리는 요청 내용이 django에 들어갔다는 것을 알게 되었다.core.handlers.wsgi.WSGIHandler.__call__처리를 진행하...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.