23.1 What changed in settings, startup and the commands
The changes from Django 5.0 to this commit in the settings object, the project template and the management commands: deprecated settings beside MAILERS, the shell’s automatic imports, BaseCommand, BaseCommand, the checks’ databases, and listurls.
A deprecated setting in the settings object
Since 6.1 the settings object (The settings object) watches a few names: the email settings that MAILERS replaces, listed in DEPRECATED_EMAIL_SETTINGS, and the transitional settings USE_BLANK_CHOICE_DASH and SIGNED_COOKIE_LEGACY_SALT_FALLBACK. Setting one warns with RemovedInDjango2028Warning. Settings warns for each that the settings module defines, attributed to the first frame outside Django. LazySettings, override_settings and an assignment to settings set values through UserSettingsHolder or LazySettings, which warn only when the code that set the value is outside Django.
The email settings are watched when read, too. LazySettings warns when the code reading one is outside Django, and keeps the value on the proxy: later reads do not reach it, so none warns, even where Django’s own code made the first. Where the project defines MAILERS, the read raises AttributeError instead, and LazySettings leaves their defaults out of dir(settings). Defining both is refused with ImproperlyConfigured in the settings module or in one call of configure; override_settings does not check, and an email setting it sets beside MAILERS is refused when read.
# deprecated_settings.py at this commit, every warning recorded; settings modules
# with EMAIL_HOST, with it and MAILERS, with MAILERS; then an override
EMAIL_HOST: the first read of any setting, SECRET_KEY
-> 'harbour-office-not-a-secret'
warns RemovedInDjango2028Warning: The EMAIL_HOST setting is deprecated. Migrate to MAILERS before Django 2028.
settings.EMAIL_HOST
-> 'smtp.harbour.example'
warns RemovedInDjango2028Warning: The EMAIL_HOST setting is deprecated. Migrate to MAILERS before Django 2028.
settings.EMAIL_HOST, again
-> 'smtp.harbour.example'
EMAIL_HOST and MAILERS: the first read
raises ImproperlyConfigured: Deprecated email settings are not allowed when MAILERS is defined: EMAIL_HOST.
MAILERS: settings.EMAIL_BACKEND
raises AttributeError: The EMAIL_BACKEND setting is not available when MAILERS is defined.
override_settings(MAILERS={...}, EMAIL_PORT=587), entered
warns RemovedInDjango2028Warning: The EMAIL_PORT setting is deprecated. Migrate to MAILERS before Django 2028.
settings.EMAIL_PORT
raises AttributeError: The EMAIL_PORT setting is not available when MAILERS is defined.
What changed in mail and tasks tells what MAILERS configures; What still warns: the deprecations and the releases that end them lists every deprecation.
What startproject and startapp write
Since 5.2 the TEMPLATES of the settings module that startproject writes omits the debug context processor, which still exists. Since 6.0 that module sets no DEFAULT_AUTO_FIELD, and the AppConfig that startapp writes no AppConfig: both named BigAutoField, which 6.0 made the setting’s default (What changed in models and fields). Since 6.1 the module defines MAILERS, with the console backend as the default mailer.
Before a command’s handle
ManagementUtility reads the settings before it loads the command, and keeps the ImproperlyConfigured of a failed read: no settings named, a module not found (an ImportError that Settings turns into that exception), a list setting that is not a list, email settings beside MAILERS. Since 6.2 ManagementUtility then refuses, with that message and status 1, a command whose BaseCommand is true, the default. Before, the notes say, an ImportError from the settings module was suppressed for every command. At this commit an ImportError raised inside the settings module is not caught, and ends every command with a traceback (Finding the command).
Since 5.2 BaseCommand asks BaseCommand for the arguments of its call of BaseCommand, a method a command may override. migrate overrides it to add its database, whose checks then run before it migrates; runserver returns an empty collection of tags, which selects nothing, and runs them itself in the serving process (The development server).
Since 6.1 CheckRegistry gives the check functions every configured alias when its caller leaves the databases argument at None, where it used to give none. It holds for every command whose checks leave it at None, not only the check command the notes name. The checks tagged database are still left out unless asked for. The change reaches the checks that work per database, among them the model checks of long column names, indexes, constraints and table comments and the fields’ checks that ask the backend: they now run against the connection of each alias the router lets the model migrate to, and where a backend learns its features from the server, as MySQL’s does, the first read of one connects. Callers, the notes say, “should be prepared for databases to be accessed” (docs/; The system checks).
The shell
Since 5.2 the shell fills its namespace before it starts. Command returns dotted paths to import, among them every model that Apps.get_models returns, which leaves out the automatic through models of many-to-many relations and swapped models. Since 6.0 the list begins with common utilities: at this commit the settings object, the default connection, django.db.models, django, reset_queries and django. Code given with --command or on standard input gets the namespace too, and --no-imports empties it (The commands Django ships).
Other changes
| what | what changed | release | where now |
|---|---|---|---|
| a query before the app registry is ready | what changed warns with RuntimeWarning, unless a test has the installed applications overridden, and still runs (Cursors: executing a statement, the query log and execute wrappers) |
release 5.0 | where now Cursor django/ |
| runserver’s banner | what changed ends with a warning that the server is for development, unless the environment sets "DJANGO_ to "true" |
release 5.2 | where now Command.on_bind django/ |
| startproject and startapp given a directory | what changed make it, and its missing parents, if it does not exist | release 6.0 | where now Template django/ |
| a mistyped choice or subcommand | what changed on Python 3.14 argparse suggests the nearest, the parser being made with suggest_; on later versions Django leaves argparse’s own default |
release 6.1 | where now Command django/ |
| listurls | what changed new: prints the root URLconf’s patterns, views and names | release 6.2 | where now The URL checks, and listing the patterns |