diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py index 132ee4c0795..3795809a122 100644 --- a/django/core/management/commands/runserver.py +++ b/django/core/management/commands/runserver.py @@ -188,3 +188,12 @@ class Command(BaseCommand): f"Quit the server with {quit_command}.", file=self.stdout, ) + if os.environ.get("HIDE_PRODUCTION_WARNING") != "true": + self.stdout.write( + self.style.WARNING( + "WARNING: This is a development server. Do not use it in a " + "production setting. Use a production WSGI or ASGI server " + "instead.\nFor more information on production servers see: " + "https://docs.djangoproject.com/en/stable/howto/deployment/" + ) + ) diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt index db59ca49df7..0536eca2f77 100644 --- a/docs/intro/tutorial01.txt +++ b/docs/intro/tutorial01.txt @@ -134,6 +134,9 @@ You'll see the following output on the command line: Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. + WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. + For more information on production servers see: https://docs.djangoproject.com/en/stable/howto/deployment/ + .. note:: Ignore the warning about unapplied database migrations for now; we'll deal with the database shortly. diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt index 8173224e4ce..52eaaa331b6 100644 --- a/docs/ref/django-admin.txt +++ b/docs/ref/django-admin.txt @@ -947,6 +947,20 @@ multithreaded by default. Uses IPv6 for the development server. This changes the default IP address from ``127.0.0.1`` to ``::1``. +.. envvar:: HIDE_PRODUCTION_WARNING + +.. versionadded:: 5.2 + +By default, a warning is printed to the console that ``runserver`` is not +suitable for production: + +.. code-block:: text + + WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. + For more information on production servers see: https://docs.djangoproject.com/en/stable/howto/deployment/ + +Set this environment variable to ``"true"`` to hide this warning. + Examples of using different ports and addresses ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/releases/5.2.txt b/docs/releases/5.2.txt index 5732a5473c7..7ae44cfd971 100644 --- a/docs/releases/5.2.txt +++ b/docs/releases/5.2.txt @@ -194,7 +194,10 @@ Logging Management Commands ~~~~~~~~~~~~~~~~~~~ -* ... +* A new warning is printed to the console when running :djadmin:`runserver` that + ``runserver`` is unsuitable for production. This warning can be hidden by + setting the :envvar:`HIDE_PRODUCTION_WARNING` environment variable to + ``"true"``. Migrations ~~~~~~~~~~ diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py index 2e77f2c97a6..67362460a99 100644 --- a/tests/admin_scripts/tests.py +++ b/tests/admin_scripts/tests.py @@ -1597,6 +1597,13 @@ class ManageRunserver(SimpleTestCase): "Starting development server at http://0.0.0.0:8000/", self.output.getvalue(), ) + self.assertIn( + "WARNING: This is a development server. Do not use it in a " + "production setting. Use a production WSGI or ASGI server instead." + "\nFor more information on production servers see: " + "https://docs.djangoproject.com/en/stable/howto/deployment/", + self.output.getvalue(), + ) def test_on_bind(self): self.cmd.addr = "127.0.0.1" @@ -1606,6 +1613,30 @@ class ManageRunserver(SimpleTestCase): "Starting development server at http://127.0.0.1:14437/", self.output.getvalue(), ) + self.assertIn( + "WARNING: This is a development server. Do not use it in a " + "production setting. Use a production WSGI or ASGI server instead." + "\nFor more information on production servers see: " + "https://docs.djangoproject.com/en/stable/howto/deployment/", + self.output.getvalue(), + ) + + @mock.patch.dict(os.environ, {"HIDE_PRODUCTION_WARNING": "true"}) + def test_hide_production_warning_with_environment_variable(self): + self.cmd.addr = "0" + self.cmd._raw_ipv6 = False + self.cmd.on_bind("8000") + self.assertIn( + "Starting development server at http://0.0.0.0:8000/", + self.output.getvalue(), + ) + self.assertNotIn( + "WARNING: This is a development server. Do not use it in a " + "production setting. Use a production WSGI or ASGI server instead." + "\nFor more information on production servers see: " + "https://docs.djangoproject.com/en/stable/howto/deployment/", + self.output.getvalue(), + ) @unittest.skipUnless(socket.has_ipv6, "platform doesn't support IPv6") def test_runner_addrport_ipv6(self):