You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

runserver.py 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import errno
  2. import os
  3. import re
  4. import socket
  5. import sys
  6. from datetime import datetime
  7. from django.conf import settings
  8. from django.core.management.base import BaseCommand, CommandError
  9. from django.core.servers.basehttp import (
  10. WSGIServer, get_internal_wsgi_application, run,
  11. )
  12. from django.utils import autoreload
  13. naiveip_re = re.compile(r"""^(?:
  14. (?P<addr>
  15. (?P<ipv4>\d{1,3}(?:\.\d{1,3}){3}) | # IPv4 address
  16. (?P<ipv6>\[[a-fA-F0-9:]+\]) | # IPv6 address
  17. (?P<fqdn>[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*) # FQDN
  18. ):)?(?P<port>\d+)$""", re.X)
  19. class Command(BaseCommand):
  20. help = "Starts a lightweight Web server for development."
  21. # Validation is called explicitly each time the server is reloaded.
  22. requires_system_checks = False
  23. stealth_options = ('shutdown_message',)
  24. default_addr = '127.0.0.1'
  25. default_addr_ipv6 = '::1'
  26. default_port = '8000'
  27. protocol = 'http'
  28. server_cls = WSGIServer
  29. def add_arguments(self, parser):
  30. parser.add_argument(
  31. 'addrport', nargs='?',
  32. help='Optional port number, or ipaddr:port'
  33. )
  34. parser.add_argument(
  35. '--ipv6', '-6', action='store_true', dest='use_ipv6',
  36. help='Tells Django to use an IPv6 address.',
  37. )
  38. parser.add_argument(
  39. '--nothreading', action='store_false', dest='use_threading',
  40. help='Tells Django to NOT use threading.',
  41. )
  42. parser.add_argument(
  43. '--noreload', action='store_false', dest='use_reloader',
  44. help='Tells Django to NOT use the auto-reloader.',
  45. )
  46. def execute(self, *args, **options):
  47. if options['no_color']:
  48. # We rely on the environment because it's currently the only
  49. # way to reach WSGIRequestHandler. This seems an acceptable
  50. # compromise considering `runserver` runs indefinitely.
  51. os.environ["DJANGO_COLORS"] = "nocolor"
  52. super().execute(*args, **options)
  53. def get_handler(self, *args, **options):
  54. """Return the default WSGI handler for the runner."""
  55. return get_internal_wsgi_application()
  56. def handle(self, *args, **options):
  57. if not settings.DEBUG and not settings.ALLOWED_HOSTS:
  58. raise CommandError('You must set settings.ALLOWED_HOSTS if DEBUG is False.')
  59. self.use_ipv6 = options['use_ipv6']
  60. if self.use_ipv6 and not socket.has_ipv6:
  61. raise CommandError('Your Python does not support IPv6.')
  62. self._raw_ipv6 = False
  63. if not options['addrport']:
  64. self.addr = ''
  65. self.port = self.default_port
  66. else:
  67. m = re.match(naiveip_re, options['addrport'])
  68. if m is None:
  69. raise CommandError('"%s" is not a valid port number '
  70. 'or address:port pair.' % options['addrport'])
  71. self.addr, _ipv4, _ipv6, _fqdn, self.port = m.groups()
  72. if not self.port.isdigit():
  73. raise CommandError("%r is not a valid port number." % self.port)
  74. if self.addr:
  75. if _ipv6:
  76. self.addr = self.addr[1:-1]
  77. self.use_ipv6 = True
  78. self._raw_ipv6 = True
  79. elif self.use_ipv6 and not _fqdn:
  80. raise CommandError('"%s" is not a valid IPv6 address.' % self.addr)
  81. if not self.addr:
  82. self.addr = self.default_addr_ipv6 if self.use_ipv6 else self.default_addr
  83. self._raw_ipv6 = self.use_ipv6
  84. self.run(**options)
  85. def run(self, **options):
  86. """Run the server, using the autoreloader if needed."""
  87. use_reloader = options['use_reloader']
  88. if use_reloader:
  89. autoreload.run_with_reloader(self.inner_run, **options)
  90. else:
  91. self.inner_run(None, **options)
  92. def inner_run(self, *args, **options):
  93. # If an exception was silenced in ManagementUtility.execute in order
  94. # to be raised in the child process, raise it now.
  95. autoreload.raise_last_exception()
  96. threading = options['use_threading']
  97. # 'shutdown_message' is a stealth option.
  98. shutdown_message = options.get('shutdown_message', '')
  99. quit_command = 'CTRL-BREAK' if sys.platform == 'win32' else 'CONTROL-C'
  100. self.stdout.write("Performing system checks...\n\n")
  101. self.check(display_num_errors=True)
  102. # Need to check migrations here, so can't use the
  103. # requires_migrations_check attribute.
  104. self.check_migrations()
  105. now = datetime.now().strftime('%B %d, %Y - %X')
  106. self.stdout.write(now)
  107. self.stdout.write((
  108. "Django version %(version)s, using settings %(settings)r\n"
  109. "Starting development server at %(protocol)s://%(addr)s:%(port)s/\n"
  110. "Quit the server with %(quit_command)s.\n"
  111. ) % {
  112. "version": self.get_version(),
  113. "settings": settings.SETTINGS_MODULE,
  114. "protocol": self.protocol,
  115. "addr": '[%s]' % self.addr if self._raw_ipv6 else self.addr,
  116. "port": self.port,
  117. "quit_command": quit_command,
  118. })
  119. try:
  120. handler = self.get_handler(*args, **options)
  121. run(self.addr, int(self.port), handler,
  122. ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
  123. except socket.error as e:
  124. # Use helpful error messages instead of ugly tracebacks.
  125. ERRORS = {
  126. errno.EACCES: "You don't have permission to access that port.",
  127. errno.EADDRINUSE: "That port is already in use.",
  128. errno.EADDRNOTAVAIL: "That IP address can't be assigned to.",
  129. }
  130. try:
  131. error_text = ERRORS[e.errno]
  132. except KeyError:
  133. error_text = e
  134. self.stderr.write("Error: %s" % error_text)
  135. # Need to use an OS exit because sys.exit doesn't work in a thread
  136. os._exit(1)
  137. except KeyboardInterrupt:
  138. if shutdown_message:
  139. self.stdout.write(shutdown_message)
  140. sys.exit(0)
  141. # Kept for backward compatibility
  142. BaseRunserverCommand = Command