Merge branch 'django:main' into ticket_34034
14
docs/conf.py
@@ -94,7 +94,7 @@ spelling_warning = True
|
||||
# templates_path = []
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = ".txt"
|
||||
source_suffix = {".txt": "restructuredtext"}
|
||||
|
||||
# The encoding of source files.
|
||||
# source_encoding = 'utf-8-sig'
|
||||
@@ -182,9 +182,9 @@ pygments_style = "trac"
|
||||
# Links to Python's docs should reference the most recent version of the 3.x
|
||||
# branch, which is located at this URL.
|
||||
intersphinx_mapping = {
|
||||
"python": ("https://docs.python.org/3/", None),
|
||||
"sphinx": ("https://www.sphinx-doc.org/en/master/", None),
|
||||
"psycopg": ("https://www.psycopg.org/psycopg3/docs/", None),
|
||||
"python": ("https://docs.python.org/3", None),
|
||||
"sphinx": ("https://www.sphinx-doc.org/en/master", None),
|
||||
"psycopg": ("https://www.psycopg.org/psycopg3/docs", None),
|
||||
}
|
||||
|
||||
# Python's docs don't change every week.
|
||||
@@ -292,8 +292,12 @@ latex_elements = {
|
||||
\setmainfont{Symbola}
|
||||
""",
|
||||
"preamble": r"""
|
||||
\usepackage{newunicodechar}
|
||||
\usepackage[UTF8]{ctex}
|
||||
\xeCJKDeclareCharClass{HalfLeft}{"2018, "201C}
|
||||
\xeCJKDeclareCharClass{HalfRight}{
|
||||
"00B7, "2019, "201D, "2013, "2014, "2025, "2026, "2E3A
|
||||
}
|
||||
\usepackage{newunicodechar}
|
||||
\newunicodechar{π}{\ensuremath{\pi}}
|
||||
\newunicodechar{≤}{\ensuremath{\le}}
|
||||
\newunicodechar{≥}{\ensuremath{\ge}}
|
||||
|
||||
@@ -52,7 +52,7 @@ Django version Python versions
|
||||
============== ===============
|
||||
4.2 3.8, 3.9, 3.10, 3.11, 3.12 (added in 4.2.8)
|
||||
5.0 3.10, 3.11, 3.12
|
||||
5.1 3.10, 3.11, 3.12
|
||||
5.1 3.10, 3.11, 3.12, 3.13 (added in 5.1.3)
|
||||
5.2 3.10, 3.11, 3.12, 3.13
|
||||
============== ===============
|
||||
|
||||
|
||||
@@ -645,6 +645,9 @@ delegate further handling to the parent class. This might require you to write
|
||||
a custom form field (and even a form widget). See the :doc:`forms documentation
|
||||
</topics/forms/index>` for information about this.
|
||||
|
||||
If you wish to exclude the field from the :class:`~django.forms.ModelForm`, you
|
||||
can override the :meth:`~Field.formfield` method to return ``None``.
|
||||
|
||||
Continuing our ongoing example, we can write the :meth:`~Field.formfield` method
|
||||
as::
|
||||
|
||||
@@ -652,8 +655,12 @@ as::
|
||||
# ...
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
# This is a fairly standard way to set up some defaults
|
||||
# while letting the caller override them.
|
||||
# Exclude the field from the ModelForm when some condition is met.
|
||||
some_condition = kwargs.get("some_condition", False)
|
||||
if some_condition:
|
||||
return None
|
||||
|
||||
# Set up some defaults while letting the caller override them.
|
||||
defaults = {"form_class": MyFormField}
|
||||
defaults.update(kwargs)
|
||||
return super().formfield(**defaults)
|
||||
|
||||
@@ -154,7 +154,8 @@ Origin API and 3rd-party integration
|
||||
Django templates have an :class:`~django.template.base.Origin` object available
|
||||
through the ``template.origin`` attribute. This enables debug information to be
|
||||
displayed in the :ref:`template postmortem <template-postmortem>`, as well as
|
||||
in 3rd-party libraries, like the `Django Debug Toolbar`_.
|
||||
in 3rd-party libraries, like the :pypi:`Django Debug Toolbar
|
||||
<django-debug-toolbar>`.
|
||||
|
||||
Custom engines can provide their own ``template.origin`` information by
|
||||
creating an object that specifies the following attributes:
|
||||
@@ -168,4 +169,3 @@ creating an object that specifies the following attributes:
|
||||
to load the template, e.g. ``django.template.loaders.filesystem.Loader``.
|
||||
|
||||
.. _DEP 182: https://github.com/django/deps/blob/main/final/0182-multiple-template-engines.rst
|
||||
.. _Django Debug Toolbar: https://github.com/jazzband/django-debug-toolbar/
|
||||
|
||||
@@ -47,13 +47,13 @@ To install Uvicorn and Gunicorn, use the following:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install uvicorn gunicorn
|
||||
python -m pip install uvicorn uvicorn-worker gunicorn
|
||||
|
||||
Then start Gunicorn using the Uvicorn worker class like this:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m gunicorn myproject.asgi:application -k uvicorn.workers.UvicornWorker
|
||||
python -m gunicorn myproject.asgi:application -k uvicorn_worker.UvicornWorker
|
||||
|
||||
.. _Uvicorn: https://www.uvicorn.org/
|
||||
.. _Gunicorn: https://gunicorn.org/
|
||||
|
||||
@@ -36,6 +36,14 @@ Some of the checks described below can be automated using the :option:`check
|
||||
--deploy` option. Be sure to run it against your production settings file as
|
||||
described in the option's documentation.
|
||||
|
||||
Switch away from ``manage.py runserver``
|
||||
========================================
|
||||
|
||||
The :djadmin:`runserver` command is not designed for a production setting. Be
|
||||
sure to switch to a production-ready WSGI or ASGI server. For a few common
|
||||
options, see :doc:`WSGI servers </howto/deployment/wsgi/index>` or
|
||||
:doc:`ASGI servers </howto/deployment/asgi/index>`.
|
||||
|
||||
Critical settings
|
||||
=================
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ the scope of what Django can give you as guidance.
|
||||
|
||||
Django, being a web framework, needs a web server in order to operate. And
|
||||
since most web servers don't natively speak Python, we need an interface to
|
||||
make that communication happen.
|
||||
make that communication happen. The :djadmin:`runserver` command starts a
|
||||
lightweight development server, which is not suitable for production.
|
||||
|
||||
Django currently supports two interfaces: WSGI and ASGI.
|
||||
|
||||
|
||||
@@ -282,7 +282,11 @@ following attributes and methods:
|
||||
|
||||
import re
|
||||
|
||||
re.compile(r"API|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE", flags=re.IGNORECASE)
|
||||
re.compile(r"API|AUTH|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE", flags=re.IGNORECASE)
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
The term ``AUTH`` was added.
|
||||
|
||||
.. method:: is_active(request)
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ Tell Django where to look for fixture files
|
||||
-------------------------------------------
|
||||
|
||||
By default, Django looks for fixtures in the ``fixtures`` directory inside each
|
||||
app for, so the command ``loaddata sample`` will find the file
|
||||
app, so the command ``loaddata sample`` will find the file
|
||||
``my_app/fixtures/sample.json``. This works with relative paths as well, so
|
||||
``loaddata my_app/sample`` will find the file
|
||||
``my_app/fixtures/my_app/sample.json``.
|
||||
@@ -93,7 +93,7 @@ app for, so the command ``loaddata sample`` will find the file
|
||||
Django also looks for fixtures in the list of directories provided in the
|
||||
:setting:`FIXTURE_DIRS` setting.
|
||||
|
||||
To completely prevent default search form happening, use an absolute path to
|
||||
To completely prevent default search from happening, use an absolute path to
|
||||
specify the location of your fixture file, e.g. ``loaddata /path/to/sample``.
|
||||
|
||||
.. admonition:: Namespace your fixture files
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
How to install Django on Windows
|
||||
================================
|
||||
|
||||
This document will guide you through installing Python 3.12 and Django on
|
||||
This document will guide you through installing Python 3.13 and Django on
|
||||
Windows. It also provides instructions for setting up a virtual environment,
|
||||
which makes it easier to work on Python projects. This is meant as a beginner's
|
||||
guide for users working on Django projects and does not reflect how Django
|
||||
@@ -18,7 +18,7 @@ Install Python
|
||||
==============
|
||||
|
||||
Django is a Python web framework, thus requiring Python to be installed on your
|
||||
machine. At the time of writing, Python 3.12 is the latest version.
|
||||
machine. At the time of writing, Python 3.13 is the latest version.
|
||||
|
||||
To install Python on your machine go to https://www.python.org/downloads/. The
|
||||
website should offer you a download button for the latest Python version.
|
||||
|
||||
@@ -110,13 +110,17 @@ part of that. Here are some tips on how to make a request most effectively:
|
||||
If there's a consensus agreement on the feature, then it's appropriate to
|
||||
create a ticket. Include a link to the discussion in the ticket description.
|
||||
|
||||
As with most open-source projects, code talks. If you are willing to write the
|
||||
code for the feature yourself or, even better, if you've already written it,
|
||||
it's much more likely to be accepted. Fork Django on GitHub, create a feature
|
||||
branch, and show us your work!
|
||||
|
||||
See also: :ref:`documenting-new-features`.
|
||||
|
||||
Requesting performance optimizations
|
||||
====================================
|
||||
|
||||
Reports of a performance regression, or suggested performance optimizations,
|
||||
should provide benchmarks and commands for the ticket triager to reproduce.
|
||||
|
||||
See the :ref:`django-asv-benchmarks` for more details of Django's existing
|
||||
benchmarks.
|
||||
|
||||
.. _how-we-make-decisions:
|
||||
|
||||
How we make decisions
|
||||
|
||||
@@ -35,8 +35,8 @@ with them.
|
||||
Python style
|
||||
============
|
||||
|
||||
* All files should be formatted using the `black`_ auto-formatter. This will be
|
||||
run by ``pre-commit`` if that is configured.
|
||||
* All files should be formatted using the :pypi:`black` auto-formatter. This
|
||||
will be run by ``pre-commit`` if that is configured.
|
||||
|
||||
* The project repository includes an ``.editorconfig`` file. We recommend using
|
||||
a text editor with `EditorConfig`_ support to avoid indentation and
|
||||
@@ -506,5 +506,4 @@ JavaScript style
|
||||
For details about the JavaScript code style used by Django, see
|
||||
:doc:`javascript`.
|
||||
|
||||
.. _black: https://black.readthedocs.io/en/stable/
|
||||
.. _editorconfig: https://editorconfig.org/
|
||||
|
||||
@@ -6,6 +6,8 @@ We're always grateful for contributions to Django's code. Indeed, bug reports
|
||||
with associated contributions will get fixed *far* more quickly than those
|
||||
without a solution.
|
||||
|
||||
.. _trivial-change:
|
||||
|
||||
Typo fixes and trivial documentation changes
|
||||
============================================
|
||||
|
||||
@@ -52,9 +54,10 @@ and time availability), claim it by following these steps:
|
||||
|
||||
.. note::
|
||||
The Django software foundation requests that anyone contributing more than
|
||||
a trivial change to Django sign and submit a `Contributor License
|
||||
Agreement`_, this ensures that the Django Software Foundation has clear
|
||||
license to all contributions allowing for a clear license for all users.
|
||||
a :ref:`trivial change <trivial-change>`, to Django sign and submit a
|
||||
`Contributor License Agreement`_, this ensures that the Django Software
|
||||
Foundation has clear license to all contributions allowing for a clear
|
||||
license for all users.
|
||||
|
||||
.. _Login using your GitHub account: https://code.djangoproject.com/github/login
|
||||
.. _Create an account: https://www.djangoproject.com/accounts/register/
|
||||
@@ -206,9 +209,10 @@ You should also add a test for the deprecation warning::
|
||||
|
||||
def test_foo_deprecation_warning(self):
|
||||
msg = "Expected deprecation message"
|
||||
with self.assertWarnsMessage(RemovedInDjangoXXWarning, msg):
|
||||
with self.assertWarnsMessage(RemovedInDjangoXXWarning, msg) as ctx:
|
||||
# invoke deprecated behavior
|
||||
...
|
||||
self.assertEqual(ctx.filename, __file__)
|
||||
|
||||
It's important to include a ``RemovedInDjangoXXWarning`` comment above code
|
||||
which has no warning reference, but will need to be changed or removed when the
|
||||
@@ -230,6 +234,7 @@ deprecation ends. For example::
|
||||
warnings.warn(
|
||||
"foo() is deprecated.",
|
||||
category=RemovedInDjangoXXWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
old_private_helper()
|
||||
...
|
||||
@@ -257,21 +262,45 @@ JavaScript contributions
|
||||
For information on JavaScript contributions, see the :ref:`javascript-patches`
|
||||
documentation.
|
||||
|
||||
Optimization patches
|
||||
====================
|
||||
|
||||
Patches aiming to deliver a performance improvement should provide benchmarks
|
||||
showing the before and after impact of the patch and sharing the commands for
|
||||
reviewers to reproduce.
|
||||
|
||||
.. _django-asv-benchmarks:
|
||||
|
||||
``django-asv`` benchmarks
|
||||
-------------------------
|
||||
|
||||
`django-asv`_ monitors the performance of Django code over time. These
|
||||
benchmarks can be run on a pull request by labeling the pull request with
|
||||
``benchmark``. Adding to these benchmarks is highly encouraged.
|
||||
|
||||
.. _django-asv: https://github.com/django/django-asv/
|
||||
|
||||
.. _patch-review-checklist:
|
||||
|
||||
Contribution checklist
|
||||
======================
|
||||
|
||||
Use this checklist to review a pull request. If you are reviewing a pull
|
||||
request that is not your own and it passes all the criteria below, please set
|
||||
the "Triage Stage" on the corresponding Trac ticket to "Ready for checkin".
|
||||
Use this checklist to review a pull request. If this contribution would not be
|
||||
:ref:`considered trivial <trivial-change>`, first ensure it has an accepted
|
||||
ticket before proceeding with the review.
|
||||
|
||||
If the pull request passes all the criteria below and is not your own, please
|
||||
set the "Triage Stage" on the corresponding Trac ticket to "Ready for checkin".
|
||||
If you've left comments for improvement on the pull request, please tick the
|
||||
appropriate flags on the Trac ticket based on the results of your review:
|
||||
"Patch needs improvement", "Needs documentation", and/or "Needs tests". As time
|
||||
and interest permits, mergers do final reviews of "Ready for checkin" tickets
|
||||
and will either commit the changes or bump it back to "Accepted" if further
|
||||
work needs to be done. If you're looking to become a merger, doing thorough
|
||||
reviews of contributions is a great way to earn trust.
|
||||
work needs to be done.
|
||||
|
||||
If you're looking to become a member of the `triage & review team
|
||||
<https://www.djangoproject.com/foundation/teams/#triage-review-team>`_, doing
|
||||
thorough reviews of contributions is a great way to earn trust.
|
||||
|
||||
Looking for a patch to review? Check out the "Patches needing review" section
|
||||
of the `Django Development Dashboard <https://dashboard.djangoproject.com/>`_.
|
||||
@@ -331,5 +360,7 @@ All tickets
|
||||
:ref:`commit message format <committing-guidelines>`?
|
||||
* Are you the patch author and a new contributor? Please add yourself to the
|
||||
:source:`AUTHORS` file and submit a `Contributor License Agreement`_.
|
||||
* Does this have an accepted ticket on Trac? All contributions require a ticket
|
||||
unless the :ref:`change is considered trivial <trivial-change>`.
|
||||
|
||||
.. _Contributor License Agreement: https://www.djangoproject.com/foundation/cla/
|
||||
|
||||
@@ -313,7 +313,7 @@ dependencies:
|
||||
|
||||
* :pypi:`aiosmtpd`
|
||||
* :pypi:`argon2-cffi` 19.2.0+
|
||||
* :pypi:`asgiref` 3.7.0+ (required)
|
||||
* :pypi:`asgiref` 3.8.1+ (required)
|
||||
* :pypi:`bcrypt`
|
||||
* :pypi:`colorama` 0.4.6+
|
||||
* :pypi:`docutils` 0.19+
|
||||
|
||||
@@ -169,7 +169,7 @@ The steering council is a group of experienced contributors who:
|
||||
|
||||
- provide oversight of Django's development and release process,
|
||||
- assist in setting the direction of feature development and releases,
|
||||
- take part in filling certain roles, and
|
||||
- select Mergers and Releasers, and
|
||||
- have a tie-breaking vote when other decision-making processes fail.
|
||||
|
||||
Their main concern is to maintain the quality and stability of the Django Web
|
||||
@@ -186,7 +186,6 @@ The steering council holds the following prerogatives:
|
||||
the reversion of any particular merge or commit.
|
||||
- Announcing calls for proposals and ideas for the future technical direction
|
||||
of Django.
|
||||
- Setting and adjusting the schedule of releases of Django.
|
||||
- Selecting and removing mergers and releasers.
|
||||
- Participating in the removal of members of the steering council, when deemed
|
||||
appropriate.
|
||||
@@ -211,10 +210,13 @@ who demonstrate:
|
||||
This history must begin at least 18 months prior to the individual's
|
||||
candidacy for the Steering Council, and include substantive contributions in
|
||||
at least two of these bullet points:
|
||||
- Code contributions on Django projects or major third-party packages in the Django ecosystem
|
||||
|
||||
- Code contributions to Django projects or major third-party packages in the
|
||||
Django ecosystem
|
||||
- Reviewing pull requests and/or triaging Django project tickets
|
||||
- Documentation, tutorials or blog posts
|
||||
- Discussions about Django on the django-developers mailing list or the Django Forum
|
||||
- Discussions about Django on the django-developers mailing list or the Django
|
||||
Forum
|
||||
- Running Django-related events or user groups
|
||||
|
||||
- A history of engagement with the direction and future of Django. This does
|
||||
|
||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.2 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 17 KiB |
@@ -26,7 +26,7 @@ representing your models -- so far, it's been solving many years' worth of
|
||||
database-schema problems. Here's a quick example:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: ``mysite/news/models.py``
|
||||
:caption: ``news/models.py``
|
||||
|
||||
from django.db import models
|
||||
|
||||
@@ -151,7 +151,7 @@ a website that lets authenticated users add, change and delete objects. The
|
||||
only step required is to register your model in the admin site:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: ``mysite/news/models.py``
|
||||
:caption: ``news/models.py``
|
||||
|
||||
from django.db import models
|
||||
|
||||
@@ -163,7 +163,7 @@ only step required is to register your model in the admin site:
|
||||
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
|
||||
|
||||
.. code-block:: python
|
||||
:caption: ``mysite/news/admin.py``
|
||||
:caption: ``news/admin.py``
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
@@ -195,7 +195,7 @@ Here's what a URLconf might look like for the ``Reporter``/``Article``
|
||||
example above:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: ``mysite/news/urls.py``
|
||||
:caption: ``news/urls.py``
|
||||
|
||||
from django.urls import path
|
||||
|
||||
@@ -235,7 +235,7 @@ and renders the template with the retrieved data. Here's an example view for
|
||||
``year_archive`` from above:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: ``mysite/news/views.py``
|
||||
:caption: ``news/views.py``
|
||||
|
||||
from django.shortcuts import render
|
||||
|
||||
@@ -265,7 +265,7 @@ Let's say the ``news/year_archive.html`` template was found. Here's what that
|
||||
might look like:
|
||||
|
||||
.. code-block:: html+django
|
||||
:caption: ``mysite/news/templates/news/year_archive.html``
|
||||
:caption: ``news/templates/news/year_archive.html``
|
||||
|
||||
{% extends "base.html" %}
|
||||
|
||||
@@ -306,7 +306,7 @@ Here's what the "base.html" template, including the use of :doc:`static files
|
||||
</howto/static-files/index>`, might look like:
|
||||
|
||||
.. code-block:: html+django
|
||||
:caption: ``mysite/templates/base.html``
|
||||
:caption: ``templates/base.html``
|
||||
|
||||
{% load static %}
|
||||
<html>
|
||||
|
||||
@@ -57,7 +57,7 @@ After the previous tutorials, our project should look like this:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
mysite/
|
||||
djangotutorial/
|
||||
manage.py
|
||||
mysite/
|
||||
__init__.py
|
||||
@@ -90,12 +90,12 @@ After the previous tutorials, our project should look like this:
|
||||
admin/
|
||||
base_site.html
|
||||
|
||||
You created ``mysite/templates`` in :doc:`Tutorial 7 </intro/tutorial07>`,
|
||||
and ``polls/templates`` in :doc:`Tutorial 3 </intro/tutorial03>`. Now perhaps
|
||||
it is clearer why we chose to have separate template directories for the
|
||||
project and application: everything that is part of the polls application is in
|
||||
``polls``. It makes the application self-contained and easier to drop into a
|
||||
new project.
|
||||
You created ``djangotutorial/templates`` in :doc:`Tutorial 7
|
||||
</intro/tutorial07>`, and ``polls/templates`` in
|
||||
:doc:`Tutorial 3 </intro/tutorial03>`. Now perhaps it is clearer why we chose
|
||||
to have separate template directories for the project and application:
|
||||
everything that is part of the polls application is in ``polls``. It makes the
|
||||
application self-contained and easier to drop into a new project.
|
||||
|
||||
The ``polls`` directory could now be copied into a new Django project and
|
||||
immediately reused. It's not quite ready to be published though. For that, we
|
||||
@@ -237,6 +237,7 @@ this. For a small app like polls, this process isn't too difficult.
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Topic :: Internet :: WWW/HTTP",
|
||||
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
||||
]
|
||||
|
||||
@@ -48,14 +48,21 @@ including database configuration, Django-specific options and
|
||||
application-specific settings.
|
||||
|
||||
From the command line, ``cd`` into a directory where you'd like to store your
|
||||
code, then run the following command:
|
||||
code and create a new directory named ``djangotutorial``. (This directory name
|
||||
doesn't matter to Django; you can rename it to anything you like.)
|
||||
|
||||
.. console::
|
||||
|
||||
$ django-admin startproject mysite
|
||||
$ mkdir djangotutorial
|
||||
|
||||
This will create a ``mysite`` directory in your current directory. If it didn't
|
||||
work, see :ref:`troubleshooting-django-admin`.
|
||||
Then, run the following command to bootstrap a new Django project:
|
||||
|
||||
.. console::
|
||||
|
||||
$ django-admin startproject mysite djangotutorial
|
||||
|
||||
This will create a project called ``mysite`` inside the ``djangotutorial``
|
||||
directory. If it didn't work, see :ref:`troubleshooting-django-admin`.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -68,7 +75,7 @@ Let's look at what :djadmin:`startproject` created:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
mysite/
|
||||
djangotutorial/
|
||||
manage.py
|
||||
mysite/
|
||||
__init__.py
|
||||
@@ -79,14 +86,11 @@ Let's look at what :djadmin:`startproject` created:
|
||||
|
||||
These files are:
|
||||
|
||||
* The outer :file:`mysite/` root directory is a container for your project. Its
|
||||
name doesn't matter to Django; you can rename it to anything you like.
|
||||
|
||||
* :file:`manage.py`: A command-line utility that lets you interact with this
|
||||
Django project in various ways. You can read all the details about
|
||||
:file:`manage.py` in :doc:`/ref/django-admin`.
|
||||
|
||||
* The inner :file:`mysite/` directory is the actual Python package for your
|
||||
* :file:`mysite/`: A directory that is the actual Python package for your
|
||||
project. Its name is the Python package name you'll need to use to import
|
||||
anything inside it (e.g. ``mysite.urls``).
|
||||
|
||||
@@ -111,8 +115,8 @@ These files are:
|
||||
The development server
|
||||
======================
|
||||
|
||||
Let's verify your Django project works. Change into the outer :file:`mysite` directory, if
|
||||
you haven't already, and run the following commands:
|
||||
Let's verify your Django project works. Change into the :file:`djangotutorial`
|
||||
directory, if you haven't already, and run the following commands:
|
||||
|
||||
.. console::
|
||||
|
||||
@@ -134,6 +138,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/|version|/howto/deployment/
|
||||
|
||||
.. note::
|
||||
Ignore the warning about unapplied database migrations for now; we'll deal
|
||||
with the database shortly.
|
||||
@@ -179,10 +186,8 @@ rather than creating directories.
|
||||
configuration and apps for a particular website. A project can contain
|
||||
multiple apps. An app can be in multiple projects.
|
||||
|
||||
Your apps can live anywhere on your :ref:`Python path <tut-searchpath>`. In
|
||||
this tutorial, we'll create our poll app in the same directory as your
|
||||
:file:`manage.py` file so that it can be imported as its own top-level module,
|
||||
rather than a submodule of ``mysite``.
|
||||
Your apps can live anywhere in your :ref:`Python path <tut-searchpath>`. In
|
||||
this tutorial, we'll create our poll app inside the ``djangotutorial`` folder.
|
||||
|
||||
To create your app, make sure you're in the same directory as :file:`manage.py`
|
||||
and type this command:
|
||||
@@ -272,6 +277,8 @@ include the URLconf defined in ``polls.urls``. To do this, add an import for
|
||||
path("admin/", admin.site.urls),
|
||||
]
|
||||
|
||||
The :func:`~django.urls.path` function expects at least two arguments:
|
||||
``route`` and ``view``.
|
||||
The :func:`~django.urls.include` function allows referencing other URLconfs.
|
||||
Whenever Django encounters :func:`~django.urls.include`, it chops off whatever
|
||||
part of the URL matched up to that point and sends the remaining string to the
|
||||
@@ -304,45 +311,6 @@ text "*Hello, world. You're at the polls index.*", which you defined in the
|
||||
If you get an error page here, check that you're going to
|
||||
http://localhost:8000/polls/ and not http://localhost:8000/.
|
||||
|
||||
The :func:`~django.urls.path` function is passed four arguments, two required:
|
||||
``route`` and ``view``, and two optional: ``kwargs``, and ``name``.
|
||||
At this point, it's worth reviewing what these arguments are for.
|
||||
|
||||
:func:`~django.urls.path` argument: ``route``
|
||||
---------------------------------------------
|
||||
|
||||
``route`` is a string that contains a URL pattern. When processing a request,
|
||||
Django starts at the first pattern in ``urlpatterns`` and makes its way down
|
||||
the list, comparing the requested URL against each pattern until it finds one
|
||||
that matches.
|
||||
|
||||
Patterns don't search GET and POST parameters, or the domain name. For example,
|
||||
in a request to ``https://www.example.com/myapp/``, the URLconf will look for
|
||||
``myapp/``. In a request to ``https://www.example.com/myapp/?page=3``, the
|
||||
URLconf will also look for ``myapp/``.
|
||||
|
||||
:func:`~django.urls.path` argument: ``view``
|
||||
--------------------------------------------
|
||||
|
||||
When Django finds a matching pattern, it calls the specified view function with
|
||||
an :class:`~django.http.HttpRequest` object as the first argument and any
|
||||
"captured" values from the route as keyword arguments. We'll give an example
|
||||
of this in a bit.
|
||||
|
||||
:func:`~django.urls.path` argument: ``kwargs``
|
||||
----------------------------------------------
|
||||
|
||||
Arbitrary keyword arguments can be passed in a dictionary to the target view. We
|
||||
aren't going to use this feature of Django in the tutorial.
|
||||
|
||||
:func:`~django.urls.path` argument: ``name``
|
||||
--------------------------------------------
|
||||
|
||||
Naming your URL lets you refer to it unambiguously from elsewhere in Django,
|
||||
especially from within templates. This powerful feature allows you to make
|
||||
global changes to the URL patterns of your project while only touching a single
|
||||
file.
|
||||
|
||||
When you're comfortable with the basic request and response flow, read
|
||||
:doc:`part 2 of this tutorial </intro/tutorial02>` to start working with the
|
||||
database.
|
||||
|
||||
@@ -216,7 +216,7 @@ and you'll see something like:
|
||||
FAIL: test_was_published_recently_with_future_question (polls.tests.QuestionModelTests)
|
||||
----------------------------------------------------------------------
|
||||
Traceback (most recent call last):
|
||||
File "/path/to/mysite/polls/tests.py", line 16, in test_was_published_recently_with_future_question
|
||||
File "/path/to/djangotutorial/polls/tests.py", line 16, in test_was_published_recently_with_future_question
|
||||
self.assertIs(future_question.was_published_recently(), False)
|
||||
AssertionError: True is not False
|
||||
|
||||
|
||||
@@ -232,7 +232,8 @@ underscores replaced with spaces), and that each line contains the string
|
||||
representation of the output.
|
||||
|
||||
You can improve that by using the :func:`~django.contrib.admin.display`
|
||||
decorator on that method (in :file:`polls/models.py`), as follows:
|
||||
decorator on that method (extending the :file:`polls/models.py` file that was
|
||||
created in :doc:`Tutorial 2 </intro/tutorial02>`), as follows:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: ``polls/models.py``
|
||||
@@ -305,10 +306,10 @@ powered by Django itself, and its interfaces use Django's own template system.
|
||||
Customizing your *project's* templates
|
||||
--------------------------------------
|
||||
|
||||
Create a ``templates`` directory in your project directory (the one that
|
||||
contains ``manage.py``). Templates can live anywhere on your filesystem that
|
||||
Django can access. (Django runs as whatever user your server runs.) However,
|
||||
keeping your templates within the project is a good convention to follow.
|
||||
Create a ``templates`` directory in your ``djangotutorial`` directory.
|
||||
Templates can live anywhere on your filesystem that Django can access. (Django
|
||||
runs as whatever user your server runs.) However, keeping your templates within
|
||||
the project is a good convention to follow.
|
||||
|
||||
Open your settings file (:file:`mysite/settings.py`, remember) and add a
|
||||
:setting:`DIRS <TEMPLATES-DIRS>` option in the :setting:`TEMPLATES` setting:
|
||||
@@ -323,7 +324,6 @@ Open your settings file (:file:`mysite/settings.py`, remember) and add a
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
|
||||
@@ -8,10 +8,10 @@ Django's strengths is the rich ecosystem of third-party packages. They're
|
||||
community developed packages that can be used to quickly improve the feature set
|
||||
of an application.
|
||||
|
||||
This tutorial will show how to add `Django Debug Toolbar
|
||||
<https://django-debug-toolbar.readthedocs.io>`_, a commonly used third-party
|
||||
package. The Django Debug Toolbar has ranked in the top three most used
|
||||
third-party packages in the Django Developers Survey in recent years.
|
||||
This tutorial will show how to add :pypi:`Django Debug Toolbar
|
||||
<django-debug-toolbar>`, a commonly used third-party package. The Django Debug
|
||||
Toolbar has ranked in the top three most used third-party packages in the
|
||||
Django Developers Survey in recent years.
|
||||
|
||||
.. admonition:: Where to get help:
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 997 B |
@@ -41,7 +41,8 @@ If you're not using the default project template, here are the requirements:
|
||||
<TEMPLATES-OPTIONS>`.
|
||||
|
||||
#. If you've customized the :setting:`MIDDLEWARE` setting,
|
||||
:class:`django.contrib.auth.middleware.AuthenticationMiddleware` and
|
||||
:class:`django.contrib.sessions.middleware.SessionMiddleware`,
|
||||
:class:`django.contrib.auth.middleware.AuthenticationMiddleware`, and
|
||||
:class:`django.contrib.messages.middleware.MessageMiddleware` must be
|
||||
included.
|
||||
|
||||
|
||||
@@ -197,13 +197,23 @@ Methods
|
||||
been called for this user.
|
||||
|
||||
.. method:: get_user_permissions(obj=None)
|
||||
.. method:: aget_user_permissions(obj=None)
|
||||
|
||||
*Asynchronous version*: ``aget_user_permissions()``
|
||||
|
||||
Returns a set of permission strings that the user has directly.
|
||||
|
||||
If ``obj`` is passed in, only returns the user permissions for this
|
||||
specific object.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aget_user_permissions()`` method was added.
|
||||
|
||||
.. method:: get_group_permissions(obj=None)
|
||||
.. method:: aget_group_permissions(obj=None)
|
||||
|
||||
*Asynchronous version*: ``aget_group_permissions()``
|
||||
|
||||
Returns a set of permission strings that the user has, through their
|
||||
groups.
|
||||
@@ -211,7 +221,14 @@ Methods
|
||||
If ``obj`` is passed in, only returns the group permissions for
|
||||
this specific object.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aget_group_permissions()`` method was added.
|
||||
|
||||
.. method:: get_all_permissions(obj=None)
|
||||
.. method:: aget_all_permissions(obj=None)
|
||||
|
||||
*Asynchronous version*: ``aget_all_permissions()``
|
||||
|
||||
Returns a set of permission strings that the user has, both through
|
||||
group and user permissions.
|
||||
@@ -219,7 +236,14 @@ Methods
|
||||
If ``obj`` is passed in, only returns the permissions for this
|
||||
specific object.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aget_all_permissions()`` method was added.
|
||||
|
||||
.. method:: has_perm(perm, obj=None)
|
||||
.. method:: ahas_perm(perm, obj=None)
|
||||
|
||||
*Asynchronous version*: ``ahas_perm()``
|
||||
|
||||
Returns ``True`` if the user has the specified permission, where perm
|
||||
is in the format ``"<app label>.<permission codename>"``. (see
|
||||
@@ -230,7 +254,14 @@ Methods
|
||||
If ``obj`` is passed in, this method won't check for a permission for
|
||||
the model, but for this specific object.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``ahas_perm()`` method was added.
|
||||
|
||||
.. method:: has_perms(perm_list, obj=None)
|
||||
.. method:: ahas_perms(perm_list, obj=None)
|
||||
|
||||
*Asynchronous version*: ``ahas_perms()``
|
||||
|
||||
Returns ``True`` if the user has each of the specified permissions,
|
||||
where each perm is in the format
|
||||
@@ -241,13 +272,24 @@ Methods
|
||||
If ``obj`` is passed in, this method won't check for permissions for
|
||||
the model, but for the specific object.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``ahas_perms()`` method was added.
|
||||
|
||||
.. method:: has_module_perms(package_name)
|
||||
.. method:: ahas_module_perms(package_name)
|
||||
|
||||
*Asynchronous version*: ``ahas_module_perms()``
|
||||
|
||||
Returns ``True`` if the user has any permissions in the given package
|
||||
(the Django app label). If the user is inactive, this method will
|
||||
always return ``False``. For an active superuser, this method will
|
||||
always return ``True``.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``ahas_module_perms()`` method was added.
|
||||
|
||||
.. method:: email_user(subject, message, from_email=None, **kwargs)
|
||||
|
||||
Sends an email to the user. If ``from_email`` is ``None``, Django uses
|
||||
@@ -264,6 +306,9 @@ Manager methods
|
||||
by :class:`~django.contrib.auth.models.BaseUserManager`):
|
||||
|
||||
.. method:: create_user(username, email=None, password=None, **extra_fields)
|
||||
.. method:: acreate_user(username, email=None, password=None, **extra_fields)
|
||||
|
||||
*Asynchronous version*: ``acreate_user()``
|
||||
|
||||
Creates, saves and returns a :class:`~django.contrib.auth.models.User`.
|
||||
|
||||
@@ -285,11 +330,22 @@ Manager methods
|
||||
|
||||
See :ref:`Creating users <topics-auth-creating-users>` for example usage.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``acreate_user()`` method was added.
|
||||
|
||||
.. method:: create_superuser(username, email=None, password=None, **extra_fields)
|
||||
.. method:: acreate_superuser(username, email=None, password=None, **extra_fields)
|
||||
|
||||
*Asynchronous version*: ``acreate_superuser()``
|
||||
|
||||
Same as :meth:`create_user`, but sets :attr:`~models.User.is_staff` and
|
||||
:attr:`~models.User.is_superuser` to ``True``.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``acreate_superuser()`` method was added.
|
||||
|
||||
.. method:: with_perm(perm, is_active=True, include_superusers=True, backend=None, obj=None)
|
||||
|
||||
Returns users that have the given permission ``perm`` either in the
|
||||
@@ -499,23 +555,51 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
|
||||
methods. By default, it will reject any user and provide no permissions.
|
||||
|
||||
.. method:: get_user_permissions(user_obj, obj=None)
|
||||
.. method:: aget_user_permissions(user_obj, obj=None)
|
||||
|
||||
*Asynchronous version*: ``aget_user_permissions()``
|
||||
|
||||
Returns an empty set.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aget_user_permissions()`` function was added.
|
||||
|
||||
.. method:: get_group_permissions(user_obj, obj=None)
|
||||
.. method:: aget_group_permissions(user_obj, obj=None)
|
||||
|
||||
*Asynchronous version*: ``aget_group_permissions()``
|
||||
|
||||
Returns an empty set.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aget_group_permissions()`` function was added.
|
||||
|
||||
.. method:: get_all_permissions(user_obj, obj=None)
|
||||
.. method:: aget_all_permissions(user_obj, obj=None)
|
||||
|
||||
*Asynchronous version*: ``aget_all_permissions()``
|
||||
|
||||
Uses :meth:`get_user_permissions` and :meth:`get_group_permissions` to
|
||||
get the set of permission strings the ``user_obj`` has.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aget_all_permissions()`` function was added.
|
||||
|
||||
.. method:: has_perm(user_obj, perm, obj=None)
|
||||
.. method:: ahas_perm(user_obj, perm, obj=None)
|
||||
|
||||
*Asynchronous version*: ``ahas_perm()``
|
||||
|
||||
Uses :meth:`get_all_permissions` to check if ``user_obj`` has the
|
||||
permission string ``perm``.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``ahas_perm()`` function was added.
|
||||
|
||||
.. class:: ModelBackend
|
||||
|
||||
This is the default authentication backend used by Django. It
|
||||
@@ -539,6 +623,9 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
|
||||
unlike others methods it returns an empty queryset if ``obj is not None``.
|
||||
|
||||
.. method:: authenticate(request, username=None, password=None, **kwargs)
|
||||
.. method:: aauthenticate(request, username=None, password=None, **kwargs)
|
||||
|
||||
*Asynchronous version*: ``aauthenticate()``
|
||||
|
||||
Tries to authenticate ``username`` with ``password`` by calling
|
||||
:meth:`User.check_password
|
||||
@@ -552,38 +639,77 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
|
||||
if it wasn't provided to :func:`~django.contrib.auth.authenticate`
|
||||
(which passes it on to the backend).
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aauthenticate()`` function was added.
|
||||
|
||||
.. method:: get_user_permissions(user_obj, obj=None)
|
||||
.. method:: aget_user_permissions(user_obj, obj=None)
|
||||
|
||||
*Asynchronous version*: ``aget_user_permissions()``
|
||||
|
||||
Returns the set of permission strings the ``user_obj`` has from their
|
||||
own user permissions. Returns an empty set if
|
||||
:attr:`~django.contrib.auth.models.AbstractBaseUser.is_anonymous` or
|
||||
:attr:`~django.contrib.auth.models.CustomUser.is_active` is ``False``.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aget_user_permissions()`` function was added.
|
||||
|
||||
.. method:: get_group_permissions(user_obj, obj=None)
|
||||
.. method:: aget_group_permissions(user_obj, obj=None)
|
||||
|
||||
*Asynchronous version*: ``aget_group_permissions()``
|
||||
|
||||
Returns the set of permission strings the ``user_obj`` has from the
|
||||
permissions of the groups they belong. Returns an empty set if
|
||||
:attr:`~django.contrib.auth.models.AbstractBaseUser.is_anonymous` or
|
||||
:attr:`~django.contrib.auth.models.CustomUser.is_active` is ``False``.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aget_group_permissions()`` function was added.
|
||||
|
||||
.. method:: get_all_permissions(user_obj, obj=None)
|
||||
.. method:: aget_all_permissions(user_obj, obj=None)
|
||||
|
||||
*Asynchronous version*: ``aget_all_permissions()``
|
||||
|
||||
Returns the set of permission strings the ``user_obj`` has, including both
|
||||
user permissions and group permissions. Returns an empty set if
|
||||
:attr:`~django.contrib.auth.models.AbstractBaseUser.is_anonymous` or
|
||||
:attr:`~django.contrib.auth.models.CustomUser.is_active` is ``False``.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aget_all_permissions()`` function was added.
|
||||
|
||||
.. method:: has_perm(user_obj, perm, obj=None)
|
||||
.. method:: ahas_perm(user_obj, perm, obj=None)
|
||||
|
||||
*Asynchronous version*: ``ahas_perm()``
|
||||
|
||||
Uses :meth:`get_all_permissions` to check if ``user_obj`` has the
|
||||
permission string ``perm``. Returns ``False`` if the user is not
|
||||
:attr:`~django.contrib.auth.models.CustomUser.is_active`.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``ahas_perm()`` function was added.
|
||||
|
||||
.. method:: has_module_perms(user_obj, app_label)
|
||||
.. method:: ahas_module_perms(user_obj, app_label)
|
||||
|
||||
*Asynchronous version*: ``ahas_module_perms()``
|
||||
|
||||
Returns whether the ``user_obj`` has any permissions on the app
|
||||
``app_label``.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``ahas_module_perms()`` function was added.
|
||||
|
||||
.. method:: user_can_authenticate()
|
||||
|
||||
Returns whether the user is allowed to authenticate. To match the
|
||||
@@ -637,6 +763,9 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
|
||||
created if not already in the database Defaults to ``True``.
|
||||
|
||||
.. method:: authenticate(request, remote_user)
|
||||
.. method:: aauthenticate(request, remote_user)
|
||||
|
||||
*Asynchronous version*: ``aauthenticate()``
|
||||
|
||||
The username passed as ``remote_user`` is considered trusted. This
|
||||
method returns the user object with the given username, creating a new
|
||||
@@ -651,6 +780,10 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
|
||||
if it wasn't provided to :func:`~django.contrib.auth.authenticate`
|
||||
(which passes it on to the backend).
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aauthenticate()`` function was added.
|
||||
|
||||
.. method:: clean_username(username)
|
||||
|
||||
Performs any cleaning on the ``username`` (e.g. stripping LDAP DN
|
||||
@@ -658,12 +791,17 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
|
||||
the cleaned username.
|
||||
|
||||
.. method:: configure_user(request, user, created=True)
|
||||
.. method:: aconfigure_user(request, user, created=True)
|
||||
|
||||
*Asynchronous version*: ``aconfigure_user()``
|
||||
|
||||
Configures the user on each authentication attempt. This method is
|
||||
called immediately after fetching or creating the user being
|
||||
authenticated, and can be used to perform custom setup actions, such as
|
||||
setting the user's groups based on attributes in an LDAP directory.
|
||||
Returns the user object.
|
||||
Returns the user object. When fetching or creating an user is called
|
||||
from a synchronous context, ``configure_user`` is called,
|
||||
``aconfigure_user`` is called from async contexts.
|
||||
|
||||
The setup can be performed either once when the user is created
|
||||
(``created`` is ``True``) or on existing users (``created`` is
|
||||
@@ -674,6 +812,10 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
|
||||
if it wasn't provided to :func:`~django.contrib.auth.authenticate`
|
||||
(which passes it on to the backend).
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aconfigure_user()`` function was added.
|
||||
|
||||
.. method:: user_can_authenticate()
|
||||
|
||||
Returns whether the user is allowed to authenticate. This method
|
||||
|
||||
@@ -5,8 +5,8 @@ Geolocation with GeoIP2
|
||||
.. module:: django.contrib.gis.geoip2
|
||||
:synopsis: Python interface for MaxMind's GeoIP2 databases.
|
||||
|
||||
The :class:`GeoIP2` object is a wrapper for the `MaxMind geoip2 Python
|
||||
library`__. [#]_
|
||||
The :class:`GeoIP2` object is a wrapper for the :pypi:`MaxMind geoip2 Python
|
||||
library <geoip2>`. [#]_
|
||||
|
||||
In order to perform IP-based geolocation, the :class:`GeoIP2` object requires
|
||||
the :pypi:`geoip2` Python package and the GeoIP ``Country`` and/or ``City``
|
||||
@@ -18,7 +18,6 @@ the :setting:`GEOIP_PATH` setting.
|
||||
Additionally, it is recommended to install the `libmaxminddb C library`__, so
|
||||
that ``geoip2`` can leverage the C library's faster speed.
|
||||
|
||||
__ https://geoip2.readthedocs.io/
|
||||
__ https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
|
||||
__ https://db-ip.com/db/lite.php
|
||||
__ https://github.com/maxmind/libmaxminddb/
|
||||
@@ -196,8 +195,9 @@ Exceptions
|
||||
|
||||
.. exception:: GeoIP2Exception
|
||||
|
||||
The exception raised when an error occurs in a call to the underlying
|
||||
``geoip2`` library.
|
||||
The exception raised when an error occurs in the :class:`GeoIP2` wrapper.
|
||||
Exceptions from the underlying ``geoip2`` library are passed through
|
||||
unchanged.
|
||||
|
||||
.. rubric:: Footnotes
|
||||
.. [#] GeoIP(R) is a registered trademark of MaxMind, Inc.
|
||||
|
||||
@@ -5,16 +5,16 @@ Installing Geospatial libraries
|
||||
GeoDjango uses and/or provides interfaces for the following open source
|
||||
geospatial libraries:
|
||||
|
||||
======================== ==================================== ================================ ===========================================
|
||||
======================== ==================================== ================================ ======================================
|
||||
Program Description Required Supported Versions
|
||||
======================== ==================================== ================================ ===========================================
|
||||
======================== ==================================== ================================ ======================================
|
||||
:doc:`GEOS <../geos>` Geometry Engine Open Source Yes 3.12, 3.11, 3.10, 3.9, 3.8
|
||||
`PROJ`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 9.x, 8.x, 7.x, 6.x
|
||||
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 3.8, 3.7, 3.6, 3.5, 3.4, 3.3, 3.2, 3.1, 3.0
|
||||
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 3.8, 3.7, 3.6, 3.5, 3.4, 3.3, 3.2, 3.1
|
||||
:doc:`GeoIP <../geoip2>` IP-based geolocation library No 2
|
||||
`PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 3.4, 3.3, 3.2, 3.1
|
||||
`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 5.1, 5.0, 4.3
|
||||
======================== ==================================== ================================ ===========================================
|
||||
======================== ==================================== ================================ ======================================
|
||||
|
||||
Note that older or more recent versions of these libraries *may* also work
|
||||
totally fine with GeoDjango. Your mileage may vary.
|
||||
@@ -26,7 +26,6 @@ totally fine with GeoDjango. Your mileage may vary.
|
||||
GEOS 3.10.0 2021-10-20
|
||||
GEOS 3.11.0 2022-07-01
|
||||
GEOS 3.12.0 2023-06-27
|
||||
GDAL 3.0.0 2019-05
|
||||
GDAL 3.1.0 2020-05-07
|
||||
GDAL 3.2.0 2020-11-02
|
||||
GDAL 3.3.0 2021-05-03
|
||||
|
||||
@@ -479,8 +479,6 @@ MySQL has a couple drivers that implement the Python Database API described in
|
||||
|
||||
.. _MySQL Connector/Python: https://dev.mysql.com/downloads/connector/python/
|
||||
|
||||
These drivers are thread-safe and provide connection pooling.
|
||||
|
||||
In addition to a DB API driver, Django needs an adapter to access the database
|
||||
drivers from its ORM. Django provides an adapter for mysqlclient while MySQL
|
||||
Connector/Python includes `its own`_.
|
||||
|
||||
@@ -870,11 +870,11 @@ are reserved for the superuser (root).
|
||||
This server uses the WSGI application object specified by the
|
||||
:setting:`WSGI_APPLICATION` setting.
|
||||
|
||||
DO NOT USE THIS SERVER IN A PRODUCTION SETTING. It has not gone through
|
||||
security audits or performance tests. (And that's how it's gonna stay. We're in
|
||||
the business of making web frameworks, not web servers, so improving this
|
||||
server to be able to handle a production environment is outside the scope of
|
||||
Django.)
|
||||
.. warning:: DO NOT USE THIS SERVER IN A PRODUCTION SETTING.
|
||||
|
||||
This lightweight development server has not gone through security audits or
|
||||
performance tests, hence is unsuitable for production. Making this server
|
||||
able to handle a production environment is outside the scope of Django.
|
||||
|
||||
The development server automatically reloads Python code for each request, as
|
||||
needed. You don't need to restart the server for code changes to take effect.
|
||||
@@ -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/|version|/howto/deployment/
|
||||
|
||||
Set this environment variable to ``"true"`` to hide this warning.
|
||||
|
||||
Examples of using different ports and addresses
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -1078,7 +1092,7 @@ Python interpreter, use ``python`` as the interface name, like so:
|
||||
.. _IPython: https://ipython.org/
|
||||
.. _bpython: https://bpython-interpreter.org/
|
||||
|
||||
.. django-admin-option:: --nostartup
|
||||
.. django-admin-option:: --no-startup
|
||||
|
||||
Disables reading the startup script for the "plain" Python interpreter. By
|
||||
default, the script pointed to by the :envvar:`PYTHONSTARTUP` environment
|
||||
|
||||
@@ -129,8 +129,7 @@ The ``Storage`` class
|
||||
.. method:: exists(name)
|
||||
|
||||
Returns ``True`` if a file referenced by the given name already exists
|
||||
in the storage system, or ``False`` if the name is available for a new
|
||||
file.
|
||||
in the storage system.
|
||||
|
||||
.. method:: get_accessed_time(name)
|
||||
|
||||
|
||||
@@ -801,11 +801,11 @@ For each field, we describe the default widget used if you don't specify
|
||||
* Error message keys: ``required``, ``invalid``, ``missing``, ``empty``,
|
||||
``invalid_image``
|
||||
|
||||
Using an ``ImageField`` requires that `Pillow`_ is installed with support
|
||||
for the image formats you use. If you encounter a ``corrupt image`` error
|
||||
when you upload an image, it usually means that Pillow doesn't understand
|
||||
its format. To fix this, install the appropriate library and reinstall
|
||||
Pillow.
|
||||
Using an ``ImageField`` requires that :pypi:`pillow` is installed with
|
||||
support for the image formats you use. If you encounter a ``corrupt image``
|
||||
error when you upload an image, it usually means that Pillow doesn't
|
||||
understand its format. To fix this, install the appropriate library and
|
||||
reinstall Pillow.
|
||||
|
||||
When you use an ``ImageField`` on a form, you must also remember to
|
||||
:ref:`bind the file data to the form <binding-uploaded-files>`.
|
||||
@@ -851,7 +851,6 @@ For each field, we describe the default widget used if you don't specify
|
||||
image's content type if Pillow can determine it, otherwise it will be set
|
||||
to ``None``.
|
||||
|
||||
.. _Pillow: https://pillow.readthedocs.io/en/latest/
|
||||
.. _Image: https://pillow.readthedocs.io/en/latest/reference/Image.html
|
||||
|
||||
``IntegerField``
|
||||
|
||||
@@ -570,6 +570,48 @@ These widgets make use of the HTML elements ``input`` and ``textarea``.
|
||||
* ``template_name``: ``'django/forms/widgets/url.html'``
|
||||
* Renders as: ``<input type="url" ...>``
|
||||
|
||||
``ColorInput``
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
.. class:: ColorInput
|
||||
|
||||
* ``input_type``: ``'color'``
|
||||
* ``template_name``:``'django/forms/widgets/color.html'``
|
||||
* Renders as: ``<input type="color" ...>``
|
||||
|
||||
``SearchInput``
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
.. class:: SearchInput
|
||||
|
||||
* ``input_type``: ``'search'``
|
||||
* ``template_name``: ``'django/forms/widgets/search.html'``
|
||||
* Renders as: ``<input type="search" ...>``
|
||||
|
||||
``TelInput``
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
.. class:: TelInput
|
||||
|
||||
* ``input_type``: ``'tel'``
|
||||
* ``template_name``: ``'django/forms/widgets/tel.html'``
|
||||
* Renders as: ``<input type="tel" ...>``
|
||||
|
||||
Browsers perform no client-side validation by default because telephone
|
||||
number formats vary so much around the world. You can add some by setting
|
||||
``pattern``, ``minlength``, or ``maxlength`` in the :attr:`Widget.attrs`
|
||||
argument.
|
||||
|
||||
Additionally, you can add server-side validation to your form field with a
|
||||
validator like :class:`~django.core.validators.RegexValidator` or via
|
||||
third-party packages, such as :pypi:`django-phonenumber-field`.
|
||||
|
||||
``PasswordInput``
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -209,6 +209,18 @@ Django development server. This logger generates an ``INFO`` message upon
|
||||
detecting a modification in a source code file and may produce ``WARNING``
|
||||
messages during filesystem inspection and event subscription processes.
|
||||
|
||||
.. _django-contrib-auth-logger:
|
||||
|
||||
``django.contrib.auth``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 4.2.16
|
||||
|
||||
Log messages related to :doc:`contrib/auth`, particularly ``ERROR`` messages
|
||||
are generated when a :class:`~django.contrib.auth.forms.PasswordResetForm` is
|
||||
successfully submitted but the password reset email cannot be delivered due to
|
||||
a mail sending exception.
|
||||
|
||||
.. _django-contrib-gis-logger:
|
||||
|
||||
``django.contrib.gis``
|
||||
|
||||
@@ -34,6 +34,12 @@ defines. See the :doc:`cache documentation </topics/cache>`.
|
||||
|
||||
.. class:: CommonMiddleware
|
||||
|
||||
.. attribute:: response_redirect_class
|
||||
|
||||
Defaults to :class:`~django.http.HttpResponsePermanentRedirect`. Subclass
|
||||
``CommonMiddleware`` and override the attribute to customize the redirects
|
||||
issued by the middleware.
|
||||
|
||||
Adds a few conveniences for perfectionists:
|
||||
|
||||
* Forbids access to user agents in the :setting:`DISALLOWED_USER_AGENTS`
|
||||
@@ -75,12 +81,6 @@ Adds a few conveniences for perfectionists:
|
||||
|
||||
* Sets the ``Content-Length`` header for non-streaming responses.
|
||||
|
||||
.. attribute:: CommonMiddleware.response_redirect_class
|
||||
|
||||
Defaults to :class:`~django.http.HttpResponsePermanentRedirect`. Subclass
|
||||
``CommonMiddleware`` and override the attribute to customize the redirects
|
||||
issued by the middleware.
|
||||
|
||||
.. class:: BrokenLinkEmailsMiddleware
|
||||
|
||||
* Sends broken link notification emails to :setting:`MANAGERS` (see
|
||||
@@ -164,16 +164,16 @@ Locale middleware
|
||||
|
||||
.. class:: LocaleMiddleware
|
||||
|
||||
.. attribute:: LocaleMiddleware.response_redirect_class
|
||||
|
||||
Defaults to :class:`~django.http.HttpResponseRedirect`. Subclass
|
||||
``LocaleMiddleware`` and override the attribute to customize the
|
||||
redirects issued by the middleware.
|
||||
|
||||
Enables language selection based on data from the request. It customizes
|
||||
content for each user. See the :doc:`internationalization documentation
|
||||
</topics/i18n/translation>`.
|
||||
|
||||
.. attribute:: LocaleMiddleware.response_redirect_class
|
||||
|
||||
Defaults to :class:`~django.http.HttpResponseRedirect`. Subclass
|
||||
``LocaleMiddleware`` and override the attribute to customize the redirects
|
||||
issued by the middleware.
|
||||
|
||||
Message middleware
|
||||
------------------
|
||||
|
||||
@@ -500,56 +500,81 @@ every incoming ``HttpRequest`` object. See :ref:`Authentication in web requests
|
||||
|
||||
.. class:: LoginRequiredMiddleware
|
||||
|
||||
Subclass the middleware and override the following attributes and methods
|
||||
to customize behavior for unauthenticated requests.
|
||||
|
||||
.. attribute:: redirect_field_name
|
||||
|
||||
Defaults to ``"next"``.
|
||||
|
||||
.. method:: get_login_url()
|
||||
|
||||
Returns the URL that unauthenticated requests will be redirected to. This
|
||||
result is either the ``login_url`` set on the
|
||||
:func:`~django.contrib.auth.decorators.login_required` decorator (if not
|
||||
``None``), or :setting:`settings.LOGIN_URL <LOGIN_URL>`.
|
||||
|
||||
.. method:: get_redirect_field_name()
|
||||
|
||||
Returns the name of the query parameter that contains the URL the user
|
||||
should be redirected to after a successful login. This result is either
|
||||
the ``redirect_field_name`` set on the
|
||||
:func:`~.django.contrib.auth.decorators.login_required` decorator (if not
|
||||
``None``), or :attr:`redirect_field_name`. If ``None`` is returned, a query
|
||||
parameter won't be added.
|
||||
|
||||
.. versionadded:: 5.1
|
||||
|
||||
Redirects all unauthenticated requests to a login page. For admin views, this
|
||||
redirects to the admin login. For all other views, this will redirect to
|
||||
:setting:`settings.LOGIN_URL <LOGIN_URL>`. This can be customized by using the
|
||||
:func:`~.django.contrib.auth.decorators.login_required` decorator and setting
|
||||
``login_url`` or ``redirect_field_name`` for the view. For example::
|
||||
Redirects all unauthenticated requests to a login page, except for views
|
||||
excluded with :func:`~.django.contrib.auth.decorators.login_not_required`. The
|
||||
login page defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>`, but can be
|
||||
customized.
|
||||
|
||||
Enable this middleware by adding it to the :setting:`MIDDLEWARE` setting
|
||||
**after** :class:`~django.contrib.auth.middleware.AuthenticationMiddleware`::
|
||||
|
||||
MIDDLEWARE = [
|
||||
"...",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.auth.middleware.LoginRequiredMiddleware",
|
||||
"...",
|
||||
]
|
||||
|
||||
Make a view public, allowing unauthenticated requests, with
|
||||
:func:`~.django.contrib.auth.decorators.login_not_required`. For example::
|
||||
|
||||
from django.contrib.auth.decorators import login_not_required
|
||||
|
||||
|
||||
@login_not_required
|
||||
def contact_us(request): ...
|
||||
|
||||
Customize the login URL or field name for authenticated views with the
|
||||
:func:`~.django.contrib.auth.decorators.login_required` decorator to set
|
||||
``login_url`` or ``redirect_field_name`` respectively. For example::
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.views.generic import View
|
||||
|
||||
|
||||
@login_required(login_url="/books/login/", redirect_field_name="redirect_to")
|
||||
def book_dashboard(request): ...
|
||||
|
||||
|
||||
@method_decorator(
|
||||
login_required(login_url="/login/", redirect_field_name="redirect_to"),
|
||||
login_required(login_url="/books/login/", redirect_field_name="redirect_to"),
|
||||
name="dispatch",
|
||||
)
|
||||
class MyView(View):
|
||||
class BookMetrics(View):
|
||||
pass
|
||||
|
||||
|
||||
@login_required(login_url="/login/", redirect_field_name="redirect_to")
|
||||
def my_view(request): ...
|
||||
|
||||
Views using the :func:`~django.contrib.auth.decorators.login_not_required`
|
||||
decorator are exempt from this requirement.
|
||||
|
||||
.. admonition:: Ensure that your login view does not require a login.
|
||||
|
||||
To prevent infinite redirects, ensure you have
|
||||
:ref:`enabled unauthenticated requests
|
||||
<disable-login-required-middleware-for-views>` to your login view.
|
||||
|
||||
**Methods and Attributes**
|
||||
|
||||
.. attribute:: redirect_field_name
|
||||
|
||||
Defaults to ``"next"``.
|
||||
|
||||
.. method:: get_login_url()
|
||||
|
||||
Returns the URL that unauthenticated requests will be redirected to. If
|
||||
defined, this returns the ``login_url`` set on the
|
||||
:func:`~.django.contrib.auth.decorators.login_required` decorator. Defaults
|
||||
to :setting:`settings.LOGIN_URL <LOGIN_URL>`.
|
||||
|
||||
.. method:: get_redirect_field_name()
|
||||
|
||||
Returns the name of the query parameter that contains the URL the user
|
||||
should be redirected to after a successful login. If defined, this returns
|
||||
the ``redirect_field_name`` set on the
|
||||
:func:`~.django.contrib.auth.decorators.login_required` decorator. Defaults
|
||||
to :attr:`redirect_field_name`. If ``None`` is returned, a query parameter
|
||||
won't be added.
|
||||
|
||||
.. class:: RemoteUserMiddleware
|
||||
|
||||
Middleware for utilizing web server provided authentication. See
|
||||
|
||||
@@ -975,9 +975,9 @@ frame includes all rows from the partition to the last row in the set.
|
||||
The accepted values for the ``start`` and ``end`` arguments are ``None``, an
|
||||
integer, or zero. A negative integer for ``start`` results in ``N PRECEDING``,
|
||||
while ``None`` yields ``UNBOUNDED PRECEDING``. In ``ROWS`` mode, a positive
|
||||
integer can be used for ```start`` resulting in ``N FOLLOWING``. Positive
|
||||
integer can be used for ``start`` resulting in ``N FOLLOWING``. Positive
|
||||
integers are accepted for ``end`` and results in ``N FOLLOWING``. In ``ROWS``
|
||||
mode, a negative integer can be used for ```end`` resulting in ``N PRECEDING``.
|
||||
mode, a negative integer can be used for ``end`` resulting in ``N PRECEDING``.
|
||||
For both ``start`` and ``end``, zero will return ``CURRENT ROW``.
|
||||
|
||||
There's a difference in what ``CURRENT ROW`` includes. When specified in
|
||||
@@ -1095,6 +1095,16 @@ calling the appropriate methods on the wrapped expression.
|
||||
:py:data:`NotImplemented` which forces the expression to be computed on
|
||||
the database.
|
||||
|
||||
.. attribute:: set_returning
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
Tells Django that this expression contains a set-returning function,
|
||||
enforcing subquery evaluation. It's used, for example, to allow some
|
||||
Postgres set-returning functions (e.g. ``JSONB_PATH_QUERY``,
|
||||
``UNNEST``, etc.) to skip optimization and be properly evaluated when
|
||||
annotations spawn rows themselves. Defaults to ``False``.
|
||||
|
||||
.. method:: resolve_expression(query=None, allow_joins=True, reuse=None, summarize=False, for_save=False)
|
||||
|
||||
Provides the chance to do any preprocessing or validation of
|
||||
|
||||
@@ -12,8 +12,8 @@ This document contains all the API references of :class:`Field` including the
|
||||
|
||||
.. seealso::
|
||||
|
||||
If the built-in fields don't do the trick, you can try `django-localflavor
|
||||
<https://github.com/django/django-localflavor>`_ (`documentation
|
||||
If the built-in fields don't do the trick, you can try
|
||||
:pypi:`django-localflavor` (`documentation
|
||||
<https://django-localflavor.readthedocs.io/>`_), which contains assorted
|
||||
pieces of code that are useful for particular countries and cultures.
|
||||
|
||||
@@ -43,13 +43,15 @@ If ``True``, Django will store empty values as ``NULL`` in the database. Default
|
||||
is ``False``.
|
||||
|
||||
Avoid using :attr:`~Field.null` on string-based fields such as
|
||||
:class:`CharField` and :class:`TextField`. If a string-based field has
|
||||
``null=True``, that means it has two possible values for "no data": ``NULL``,
|
||||
and the empty string. In most cases, it's redundant to have two possible values
|
||||
for "no data;" the Django convention is to use the empty string, not
|
||||
``NULL``. One exception is when a :class:`CharField` has both ``unique=True``
|
||||
and ``blank=True`` set. In this situation, ``null=True`` is required to avoid
|
||||
unique constraint violations when saving multiple objects with blank values.
|
||||
:class:`CharField` and :class:`TextField`. The Django convention is to use an
|
||||
empty string, not ``NULL``, as the "no data" state for string-based fields. If a
|
||||
string-based field has ``null=False``, empty strings can still be saved for "no
|
||||
data". If a string-based field has ``null=True``, that means it has two possible
|
||||
values for "no data": ``NULL``, and the empty string. In most cases, it's
|
||||
redundant to have two possible values for "no data". One exception is when a
|
||||
:class:`CharField` has both ``unique=True`` and ``blank=True`` set. In this
|
||||
situation, ``null=True`` is required to avoid unique constraint violations when
|
||||
saving multiple objects with blank values.
|
||||
|
||||
For both string-based and non-string-based fields, you will also need to
|
||||
set ``blank=True`` if you wish to permit empty values in forms, as the
|
||||
@@ -718,8 +720,8 @@ The default form widget for this field is a :class:`~django.forms.TextInput`.
|
||||
The maximum length (in characters) of the field. The ``max_length``
|
||||
is enforced at the database level and in Django's validation using
|
||||
:class:`~django.core.validators.MaxLengthValidator`. It's required for all
|
||||
database backends included with Django except PostgreSQL, which supports
|
||||
unlimited ``VARCHAR`` columns.
|
||||
database backends included with Django except PostgreSQL and SQLite, which
|
||||
supports unlimited ``VARCHAR`` columns.
|
||||
|
||||
.. note::
|
||||
|
||||
@@ -728,6 +730,10 @@ The default form widget for this field is a :class:`~django.forms.TextInput`.
|
||||
``max_length`` for some backends. Refer to the :doc:`database backend
|
||||
notes </ref/databases>` for details.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
Support for unlimited ``VARCHAR`` columns was added on SQLite.
|
||||
|
||||
.. attribute:: CharField.db_collation
|
||||
|
||||
Optional. The database collation name of the field.
|
||||
@@ -1357,9 +1363,7 @@ following optional arguments:
|
||||
Name of a model field which is auto-populated with the width of the image
|
||||
each time an image object is set.
|
||||
|
||||
Requires the `Pillow`_ library.
|
||||
|
||||
.. _Pillow: https://pillow.readthedocs.io/en/latest/
|
||||
Requires the :pypi:`pillow` library.
|
||||
|
||||
:class:`ImageField` instances are created in your database as ``varchar``
|
||||
columns with a default max length of 100 characters. As with other fields, you
|
||||
@@ -2441,6 +2445,9 @@ Field API reference
|
||||
Returns the default :class:`django.forms.Field` of this field for
|
||||
:class:`~django.forms.ModelForm`.
|
||||
|
||||
If :meth:`~Field.formfield` is overridden to return ``None``, this field
|
||||
is excluded from the :class:`~django.forms.ModelForm`.
|
||||
|
||||
By default, if both ``form_class`` and ``choices_form_class`` are
|
||||
``None``, it uses :class:`~django.forms.CharField`. If the field has
|
||||
:attr:`~django.db.models.Field.choices` and ``choices_form_class``
|
||||
|
||||
@@ -973,3 +973,14 @@ Other attributes
|
||||
since they are yet to be saved. Instances fetched from a ``QuerySet``
|
||||
will have ``adding=False`` and ``db`` set to the alias of the associated
|
||||
database.
|
||||
|
||||
``_is_pk_set()``
|
||||
----------------
|
||||
|
||||
.. method:: Model._is_pk_set()
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
The ``_is_pk_set()`` method returns whether the model instance's ``pk`` is set.
|
||||
It abstracts the model's primary key definition, ensuring consistent behavior
|
||||
regardless of the specific ``pk`` configuration.
|
||||
|
||||
@@ -1599,9 +1599,7 @@ of the arguments is required, but you should use at least one of them.
|
||||
FROM blog_blog;
|
||||
|
||||
Note that the parentheses required by most database engines around
|
||||
subqueries are not required in Django's ``select`` clauses. Also note
|
||||
that some database backends, such as some MySQL versions, don't support
|
||||
subqueries.
|
||||
subqueries are not required in Django's ``select`` clauses.
|
||||
|
||||
In some rare cases, you might wish to pass parameters to the SQL
|
||||
fragments in ``extra(select=...)``. For this purpose, use the
|
||||
|
||||
@@ -425,10 +425,48 @@ Methods
|
||||
Returns ``True`` if the request is secure; that is, if it was made with
|
||||
HTTPS.
|
||||
|
||||
.. method:: HttpRequest.get_preferred_type(media_types)
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
Returns the preferred mime type from ``media_types``, based on the
|
||||
``Accept`` header, or ``None`` if the client does not accept any of the
|
||||
provided types.
|
||||
|
||||
Assuming the client sends an ``Accept`` header of
|
||||
``text/html,application/json;q=0.8``:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> request.get_preferred_type(["text/html", "application/json"])
|
||||
"text/html"
|
||||
>>> request.get_preferred_type(["application/json", "text/plain"])
|
||||
"application/json"
|
||||
>>> request.get_preferred_type(["application/xml", "text/plain"])
|
||||
None
|
||||
|
||||
Most browsers send ``Accept: */*`` by default, meaning they don't have a
|
||||
preference, in which case the first item in ``media_types`` would be
|
||||
returned.
|
||||
|
||||
Setting an explicit ``Accept`` header in API requests can be useful for
|
||||
returning a different content type for those consumers only. See
|
||||
:ref:`content-negotiation-example` for an example of returning
|
||||
different content based on the ``Accept`` header.
|
||||
|
||||
.. note::
|
||||
|
||||
If a response varies depending on the content of the ``Accept`` header
|
||||
and you are using some form of caching like Django's
|
||||
:mod:`cache middleware <django.middleware.cache>`, you should decorate
|
||||
the view with :func:`vary_on_headers('Accept')
|
||||
<django.views.decorators.vary.vary_on_headers>` so that the responses
|
||||
are properly cached.
|
||||
|
||||
.. method:: HttpRequest.accepts(mime_type)
|
||||
|
||||
Returns ``True`` if the request ``Accept`` header matches the ``mime_type``
|
||||
argument:
|
||||
Returns ``True`` if the request's ``Accept`` header matches the
|
||||
``mime_type`` argument:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
@@ -436,17 +474,10 @@ Methods
|
||||
True
|
||||
|
||||
Most browsers send ``Accept: */*`` by default, so this would return
|
||||
``True`` for all content types. Setting an explicit ``Accept`` header in
|
||||
API requests can be useful for returning a different content type for those
|
||||
consumers only. See :ref:`content-negotiation-example` of using
|
||||
``accepts()`` to return different content to API consumers.
|
||||
``True`` for all content types.
|
||||
|
||||
If a response varies depending on the content of the ``Accept`` header and
|
||||
you are using some form of caching like Django's :mod:`cache middleware
|
||||
<django.middleware.cache>`, you should decorate the view with
|
||||
:func:`vary_on_headers('Accept')
|
||||
<django.views.decorators.vary.vary_on_headers>` so that the responses are
|
||||
properly cached.
|
||||
See :ref:`content-negotiation-example` for an example of using
|
||||
``accepts()`` to return different content based on the ``Accept`` header.
|
||||
|
||||
.. method:: HttpRequest.read(size=None)
|
||||
.. method:: HttpRequest.readline()
|
||||
|
||||
@@ -3636,6 +3636,7 @@ Email
|
||||
* :setting:`EMAIL_SUBJECT_PREFIX`
|
||||
* :setting:`EMAIL_TIMEOUT`
|
||||
* :setting:`EMAIL_USE_LOCALTIME`
|
||||
* :setting:`EMAIL_USE_SSL`
|
||||
* :setting:`EMAIL_USE_TLS`
|
||||
* :setting:`MANAGERS`
|
||||
* :setting:`SERVER_EMAIL`
|
||||
|
||||
@@ -660,7 +660,6 @@ settings file, the default template engine contains the following context
|
||||
processors::
|
||||
|
||||
[
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
|
||||
@@ -2883,8 +2883,8 @@ If ``value`` is ``"https://www.example.org/"``, the output will be
|
||||
Converts URLs and email addresses in text into clickable links.
|
||||
|
||||
This template tag works on links prefixed with ``http://``, ``https://``, or
|
||||
``www.``. For example, ``https://goo.gl/aia1t`` will get converted but
|
||||
``goo.gl/aia1t`` won't.
|
||||
``www.``. For example, ``https://djangocon.eu`` will get converted but
|
||||
``djangocon.eu`` won't.
|
||||
|
||||
It also supports domain-only links ending in one of the original top level
|
||||
domains (``.com``, ``.edu``, ``.gov``, ``.int``, ``.mil``, ``.net``, and
|
||||
@@ -2922,6 +2922,17 @@ Django's built-in :tfilter:`escape` filter. The default value for
|
||||
email addresses that contain single quotes (``'``), things won't work as
|
||||
expected. Apply this filter only to plain text.
|
||||
|
||||
.. warning::
|
||||
|
||||
Using ``urlize`` or ``urlizetrunc`` can incur a performance penalty, which
|
||||
can become severe when applied to user controlled values such as content
|
||||
stored in a :class:`~django.db.models.TextField`. You can use
|
||||
:tfilter:`truncatechars` to add a limit to such inputs:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{{ value|truncatechars:500|urlize }}
|
||||
|
||||
.. templatefilter:: urlizetrunc
|
||||
|
||||
``urlizetrunc``
|
||||
|
||||
@@ -25,6 +25,9 @@ Returns an element for inclusion in ``urlpatterns``. For example::
|
||||
...,
|
||||
]
|
||||
|
||||
``route``
|
||||
---------
|
||||
|
||||
The ``route`` argument should be a string or
|
||||
:func:`~django.utils.translation.gettext_lazy()` (see
|
||||
:ref:`translating-urlpatterns`) that contains a URL pattern. The string
|
||||
@@ -33,16 +36,43 @@ URL and send it as a keyword argument to the view. The angle brackets may
|
||||
include a converter specification (like the ``int`` part of ``<int:section>``)
|
||||
which limits the characters matched and may also change the type of the
|
||||
variable passed to the view. For example, ``<int:section>`` matches a string
|
||||
of decimal digits and converts the value to an ``int``. See
|
||||
of decimal digits and converts the value to an ``int``.
|
||||
|
||||
When processing a request, Django starts at the first pattern in
|
||||
``urlpatterns`` and makes its way down the list, comparing the requested URL
|
||||
against each pattern until it finds one that matches. See
|
||||
:ref:`how-django-processes-a-request` for more details.
|
||||
|
||||
Patterns don't match GET and POST parameters, or the domain name. For example,
|
||||
in a request to ``https://www.example.com/myapp/``, the URLconf will look for
|
||||
``myapp/``. In a request to ``https://www.example.com/myapp/?page=3``, the
|
||||
URLconf will also look for ``myapp/``.
|
||||
|
||||
``view``
|
||||
--------
|
||||
|
||||
The ``view`` argument is a view function or the result of
|
||||
:meth:`~django.views.generic.base.View.as_view` for class-based views. It can
|
||||
also be an :func:`django.urls.include`.
|
||||
also be a :func:`django.urls.include`.
|
||||
|
||||
When Django finds a matching pattern, it calls the specified view function with
|
||||
an :class:`~django.http.HttpRequest` object as the first argument and any
|
||||
"captured" values from the route as keyword arguments.
|
||||
|
||||
``kwargs``
|
||||
----------
|
||||
|
||||
The ``kwargs`` argument allows you to pass additional arguments to the view
|
||||
function or method. See :ref:`views-extra-options` for an example.
|
||||
|
||||
``name``
|
||||
--------
|
||||
|
||||
Naming your URL lets you refer to it unambiguously from elsewhere in Django,
|
||||
especially from within templates. This powerful feature allows you to make
|
||||
global changes to the URL patterns of your project while only touching a single
|
||||
file.
|
||||
|
||||
See :ref:`Naming URL patterns <naming-url-patterns>` for why the ``name``
|
||||
argument is useful.
|
||||
|
||||
|
||||
@@ -699,10 +699,29 @@ escaping HTML.
|
||||
joined using ``sep``. ``sep`` is also passed through
|
||||
:func:`conditional_escape`.
|
||||
|
||||
``args_generator`` should be an iterator that returns the sequence of
|
||||
``args`` that will be passed to :func:`format_html`. For example::
|
||||
``args_generator`` should be an iterator that yields arguments to pass to
|
||||
:func:`format_html`, either sequences of positional arguments or mappings of
|
||||
keyword arguments.
|
||||
|
||||
format_html_join("\n", "<li>{} {}</li>", ((u.first_name, u.last_name) for u in users))
|
||||
For example, tuples can be used for positional arguments::
|
||||
|
||||
format_html_join(
|
||||
"\n",
|
||||
"<li>{} {}</li>",
|
||||
((u.first_name, u.last_name) for u in users),
|
||||
)
|
||||
|
||||
Or dictionaries can be used for keyword arguments::
|
||||
|
||||
format_html_join(
|
||||
"\n",
|
||||
'<li data-id="{id}">{id} {title}</li>',
|
||||
({"id": b.id, "title": b.title} for b in books),
|
||||
)
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
Support for mappings in ``args_generator`` was added.
|
||||
|
||||
.. function:: json_script(value, element_id=None, encoder=None)
|
||||
|
||||
@@ -1148,7 +1167,7 @@ For a complete discussion on the usage of the following see the
|
||||
``'es-ar'`` isn't.
|
||||
|
||||
``lang_code`` has a maximum accepted length of 500 characters. A
|
||||
:exc:`ValueError` is raised if ``lang_code`` exceeds this limit and
|
||||
:exc:`LookupError` is raised if ``lang_code`` exceeds this limit and
|
||||
``strict`` is ``True``, or if there is no generic variant and ``strict``
|
||||
is ``False``.
|
||||
|
||||
@@ -1160,10 +1179,10 @@ For a complete discussion on the usage of the following see the
|
||||
|
||||
Raises :exc:`LookupError` if nothing is found.
|
||||
|
||||
.. versionchanged:: 4.2.14
|
||||
.. versionchanged:: 4.2.15
|
||||
|
||||
In older versions, ``lang_code`` values over 500 characters were
|
||||
processed without raising a :exc:`ValueError`.
|
||||
processed without raising a :exc:`LookupError`.
|
||||
|
||||
.. function:: to_locale(language)
|
||||
|
||||
|
||||
45
docs/releases/4.2.15.txt
Normal file
@@ -0,0 +1,45 @@
|
||||
===========================
|
||||
Django 4.2.15 release notes
|
||||
===========================
|
||||
|
||||
*August 6, 2024*
|
||||
|
||||
Django 4.2.15 fixes three security issues with severity "moderate", one
|
||||
security issue with severity "high", and a regression in 4.2.14.
|
||||
|
||||
CVE-2024-41989: Memory exhaustion in ``django.utils.numberformat.floatformat()``
|
||||
================================================================================
|
||||
|
||||
If :tfilter:`floatformat` received a string representation of a number in
|
||||
scientific notation with a large exponent, it could lead to significant memory
|
||||
consumption.
|
||||
|
||||
To avoid this, decimals with more than 200 digits are now returned as is.
|
||||
|
||||
CVE-2024-41990: Potential denial-of-service vulnerability in ``django.utils.html.urlize()``
|
||||
===========================================================================================
|
||||
|
||||
:tfilter:`urlize` and :tfilter:`urlizetrunc` were subject to a potential
|
||||
denial-of-service attack via very large inputs with a specific sequence of
|
||||
characters.
|
||||
|
||||
CVE-2024-41991: Potential denial-of-service vulnerability in ``django.utils.html.urlize()`` and ``AdminURLFieldWidget``
|
||||
=======================================================================================================================
|
||||
|
||||
:tfilter:`urlize`, :tfilter:`urlizetrunc`, and ``AdminURLFieldWidget`` were
|
||||
subject to a potential denial-of-service attack via certain inputs with a very
|
||||
large number of Unicode characters.
|
||||
|
||||
CVE-2024-42005: Potential SQL injection in ``QuerySet.values()`` and ``values_list()``
|
||||
======================================================================================
|
||||
|
||||
:meth:`.QuerySet.values` and :meth:`~.QuerySet.values_list` methods on models
|
||||
with a ``JSONField`` were subject to SQL injection in column aliases, via a
|
||||
crafted JSON object key as a passed ``*arg``.
|
||||
|
||||
Bugfixes
|
||||
========
|
||||
|
||||
* Fixed a regression in Django 4.2.14 that caused a crash in
|
||||
``LocaleMiddleware`` when processing a language code over 500 characters
|
||||
(:ticket:`35627`).
|
||||
26
docs/releases/4.2.16.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
===========================
|
||||
Django 4.2.16 release notes
|
||||
===========================
|
||||
|
||||
*September 3, 2024*
|
||||
|
||||
Django 4.2.16 fixes one security issue with severity "moderate" and one
|
||||
security issue with severity "low" in 4.2.15.
|
||||
|
||||
CVE-2024-45230: Potential denial-of-service vulnerability in ``django.utils.html.urlize()``
|
||||
===========================================================================================
|
||||
|
||||
:tfilter:`urlize` and :tfilter:`urlizetrunc` were subject to a potential
|
||||
denial-of-service attack via very large inputs with a specific sequence of
|
||||
characters.
|
||||
|
||||
CVE-2024-45231: Potential user email enumeration via response status on password reset
|
||||
======================================================================================
|
||||
|
||||
Due to unhandled email sending failures, the
|
||||
:class:`~django.contrib.auth.forms.PasswordResetForm` class allowed remote
|
||||
attackers to enumerate user emails by issuing password reset requests and
|
||||
observing the outcomes.
|
||||
|
||||
To mitigate this risk, exceptions occurring during password reset email sending
|
||||
are now handled and logged using the :ref:`django-contrib-auth-logger` logger.
|
||||
@@ -2,9 +2,40 @@
|
||||
Django 5.0.8 release notes
|
||||
==========================
|
||||
|
||||
*Expected August 6, 2024*
|
||||
*August 6, 2024*
|
||||
|
||||
Django 5.0.8 fixes several bugs in 5.0.7.
|
||||
Django 5.0.8 fixes three security issues with severity "moderate", one security
|
||||
issue with severity "high", and several bugs in 5.0.7.
|
||||
|
||||
CVE-2024-41989: Memory exhaustion in ``django.utils.numberformat.floatformat()``
|
||||
================================================================================
|
||||
|
||||
If :tfilter:`floatformat` received a string representation of a number in
|
||||
scientific notation with a large exponent, it could lead to significant memory
|
||||
consumption.
|
||||
|
||||
To avoid this, decimals with more than 200 digits are now returned as is.
|
||||
|
||||
CVE-2024-41990: Potential denial-of-service vulnerability in ``django.utils.html.urlize()``
|
||||
===========================================================================================
|
||||
|
||||
:tfilter:`urlize` and :tfilter:`urlizetrunc` were subject to a potential
|
||||
denial-of-service attack via very large inputs with a specific sequence of
|
||||
characters.
|
||||
|
||||
CVE-2024-41991: Potential denial-of-service vulnerability in ``django.utils.html.urlize()`` and ``AdminURLFieldWidget``
|
||||
=======================================================================================================================
|
||||
|
||||
:tfilter:`urlize`, :tfilter:`urlizetrunc`, and ``AdminURLFieldWidget`` were
|
||||
subject to a potential denial-of-service attack via certain inputs with a very
|
||||
large number of Unicode characters.
|
||||
|
||||
CVE-2024-42005: Potential SQL injection in ``QuerySet.values()`` and ``values_list()``
|
||||
======================================================================================
|
||||
|
||||
:meth:`.QuerySet.values` and :meth:`~.QuerySet.values_list` methods on models
|
||||
with a ``JSONField`` were subject to SQL injection in column aliases, via a
|
||||
crafted JSON object key as a passed ``*arg``.
|
||||
|
||||
Bugfixes
|
||||
========
|
||||
@@ -15,3 +46,22 @@ Bugfixes
|
||||
* Fixed a regression in Django 5.0 where ``ModelAdmin.action_checkbox`` could
|
||||
break the admin changelist HTML page when rendering a model instance with a
|
||||
``__html__`` method (:ticket:`35606`).
|
||||
|
||||
* Fixed a crash when creating a model with a ``Field.db_default`` and a
|
||||
``Meta.constraints`` constraint composed of ``__endswith``, ``__startswith``,
|
||||
or ``__contains`` lookups (:ticket:`35625`).
|
||||
|
||||
* Fixed a regression in Django 5.0.7 that caused a crash in
|
||||
``LocaleMiddleware`` when processing a language code over 500 characters
|
||||
(:ticket:`35627`).
|
||||
|
||||
* Fixed a bug in Django 5.0 that caused a system check crash when
|
||||
``ModelAdmin.date_hierarchy`` was a ``GeneratedField`` with an
|
||||
``output_field`` of ``DateField`` or ``DateTimeField`` (:ticket:`35628`).
|
||||
|
||||
* Fixed a bug in Django 5.0 which caused constraint validation to either crash
|
||||
or incorrectly raise validation errors for constraints referring to fields
|
||||
using ``Field.db_default`` (:ticket:`35638`).
|
||||
|
||||
* Fixed a crash in Django 5.0 when saving a model containing a ``FileField``
|
||||
with a ``db_default`` set (:ticket:`35657`).
|
||||
|
||||
26
docs/releases/5.0.9.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
===========================
|
||||
Django 5.0.9 release notes
|
||||
===========================
|
||||
|
||||
*September 3, 2024*
|
||||
|
||||
Django 5.0.9 fixes one security issue with severity "moderate" and one security
|
||||
issue with severity "low" in 5.0.8.
|
||||
|
||||
CVE-2024-45230: Potential denial-of-service vulnerability in ``django.utils.html.urlize()``
|
||||
===========================================================================================
|
||||
|
||||
:tfilter:`urlize` and :tfilter:`urlizetrunc` were subject to a potential
|
||||
denial-of-service attack via very large inputs with a specific sequence of
|
||||
characters.
|
||||
|
||||
CVE-2024-45231: Potential user email enumeration via response status on password reset
|
||||
======================================================================================
|
||||
|
||||
Due to unhandled email sending failures, the
|
||||
:class:`~django.contrib.auth.forms.PasswordResetForm` class allowed remote
|
||||
attackers to enumerate user emails by issuing password reset requests and
|
||||
observing the outcomes.
|
||||
|
||||
To mitigate this risk, exceptions occurring during password reset email sending
|
||||
are now handled and logged using the :ref:`django-contrib-auth-logger` logger.
|
||||
58
docs/releases/5.1.1.txt
Normal file
@@ -0,0 +1,58 @@
|
||||
==========================
|
||||
Django 5.1.1 release notes
|
||||
==========================
|
||||
|
||||
*September 3, 2024*
|
||||
|
||||
Django 5.1.1 fixes one security issue with severity "moderate", one security
|
||||
issue with severity "low", and several bugs in 5.1.
|
||||
|
||||
CVE-2024-45230: Potential denial-of-service vulnerability in ``django.utils.html.urlize()``
|
||||
===========================================================================================
|
||||
|
||||
:tfilter:`urlize` and :tfilter:`urlizetrunc` were subject to a potential
|
||||
denial-of-service attack via very large inputs with a specific sequence of
|
||||
characters.
|
||||
|
||||
CVE-2024-45231: Potential user email enumeration via response status on password reset
|
||||
======================================================================================
|
||||
|
||||
Due to unhandled email sending failures, the
|
||||
:class:`~django.contrib.auth.forms.PasswordResetForm` class allowed remote
|
||||
attackers to enumerate user emails by issuing password reset requests and
|
||||
observing the outcomes.
|
||||
|
||||
To mitigate this risk, exceptions occurring during password reset email sending
|
||||
are now handled and logged using the :ref:`django-contrib-auth-logger` logger.
|
||||
|
||||
Bugfixes
|
||||
========
|
||||
|
||||
* Fixed a regression in Django 5.1 that caused a crash of ``Window()`` when
|
||||
passing an empty sequence to the ``order_by`` parameter, and a crash of
|
||||
``Prefetch()`` for a sliced queryset without ordering (:ticket:`35665`).
|
||||
|
||||
* Fixed a regression in Django 5.1 where a new ``usable_password`` field was
|
||||
included in :class:`~django.contrib.auth.forms.BaseUserCreationForm` (and
|
||||
children). A new :class:`~django.contrib.auth.forms.AdminUserCreationForm`
|
||||
including this field was added, isolating the feature to the admin where it
|
||||
was intended (:ticket:`35678`).
|
||||
|
||||
* Adjusted the deprecation warning ``stacklevel`` in :meth:`.Model.save` and
|
||||
:meth:`.Model.asave` to correctly point to the offending call site
|
||||
(:ticket:`35060`).
|
||||
|
||||
* Adjusted the deprecation warning ``stacklevel`` when using ``OS_OPEN_FLAGS``
|
||||
in :class:`~django.core.files.storage.FileSystemStorage` to correctly point
|
||||
to the offending call site (:ticket:`35326`).
|
||||
|
||||
* Adjusted the deprecation warning ``stacklevel`` in
|
||||
``FieldCacheMixin.get_cache_name()`` to correctly point to the offending call
|
||||
site (:ticket:`35405`).
|
||||
|
||||
* Restored, following a regression in Django 5.1, the ability to override the
|
||||
timezone and role setting behavior used within the ``init_connection_state``
|
||||
method of the PostgreSQL backend (:ticket:`35688`).
|
||||
|
||||
* Fixed a bug in Django 5.1 where variable lookup errors were logged when
|
||||
rendering admin fieldsets (:ticket:`35716`).
|
||||
22
docs/releases/5.1.2.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
==========================
|
||||
Django 5.1.2 release notes
|
||||
==========================
|
||||
|
||||
*October 8, 2024*
|
||||
|
||||
Django 5.1.2 fixes several bugs in 5.1.1. Also, the latest string translations
|
||||
from Transifex are incorporated.
|
||||
|
||||
Bugfixes
|
||||
========
|
||||
|
||||
* Fixed a regression in Django 5.1 that caused a crash when using the
|
||||
PostgreSQL lookup :lookup:`trigram_similar` on output fields from ``Concat``
|
||||
(:ticket:`35732`).
|
||||
|
||||
* Fixed a regression in Django 5.1 that caused a crash of ``JSONObject()``
|
||||
when using server-side binding with PostgreSQL 16+ (:ticket:`35734`).
|
||||
|
||||
* Fixed a regression in Django 5.1 that made selected items in multi-select
|
||||
widgets indistinguishable from non-selected items in the admin dark theme
|
||||
(:ticket:`35809`).
|
||||
13
docs/releases/5.1.3.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
==========================
|
||||
Django 5.1.3 release notes
|
||||
==========================
|
||||
|
||||
*Expected November 5, 2024*
|
||||
|
||||
Django 5.1.3 fixes several bugs in 5.1.2 and adds compatibility with Python
|
||||
3.13.
|
||||
|
||||
Bugfixes
|
||||
========
|
||||
|
||||
* ...
|
||||
@@ -1,8 +1,8 @@
|
||||
============================================
|
||||
Django 5.1 release notes - UNDER DEVELOPMENT
|
||||
============================================
|
||||
========================
|
||||
Django 5.1 release notes
|
||||
========================
|
||||
|
||||
*Expected August 2024*
|
||||
*August 7, 2024*
|
||||
|
||||
Welcome to Django 5.1!
|
||||
|
||||
@@ -18,8 +18,9 @@ project.
|
||||
Python compatibility
|
||||
====================
|
||||
|
||||
Django 5.1 supports Python 3.10, 3.11, and 3.12. We **highly recommend** and
|
||||
only officially support the latest release of each series.
|
||||
Django 5.1 supports Python 3.10, 3.11, 3.12, and 3.13 (as of 5.1.3). We
|
||||
**highly recommend** and only officially support the latest release of each
|
||||
series.
|
||||
|
||||
.. _whats-new-5.1:
|
||||
|
||||
@@ -91,12 +92,15 @@ redirects all unauthenticated requests to a login page. Views can allow
|
||||
unauthenticated requests by using the new
|
||||
:func:`~django.contrib.auth.decorators.login_not_required` decorator.
|
||||
|
||||
The :class:`~django.contrib.auth.middleware.LoginRequiredMiddleware` respects
|
||||
the ``login_url`` and ``redirect_field_name`` values set via the
|
||||
``LoginRequiredMiddleware`` respects the ``login_url`` and
|
||||
``redirect_field_name`` values set via the
|
||||
:func:`~.django.contrib.auth.decorators.login_required` decorator, but does not
|
||||
support setting ``login_url`` or ``redirect_field_name`` via the
|
||||
:class:`~django.contrib.auth.mixins.LoginRequiredMixin`.
|
||||
|
||||
To enable this, add ``"django.contrib.auth.middleware.LoginRequiredMiddleware"``
|
||||
to your :setting:`MIDDLEWARE` setting.
|
||||
|
||||
Minor features
|
||||
--------------
|
||||
|
||||
@@ -115,11 +119,11 @@ Minor features
|
||||
* The default ``parallelism`` of the ``ScryptPasswordHasher`` is
|
||||
increased from 1 to 5, to follow OWASP recommendations.
|
||||
|
||||
* :class:`~django.contrib.auth.forms.BaseUserCreationForm` and
|
||||
:class:`~django.contrib.auth.forms.AdminPasswordChangeForm` now support
|
||||
disabling password-based authentication by setting an unusable password on
|
||||
form save. This is now available in the admin when visiting the user creation
|
||||
and password change pages.
|
||||
* The new :class:`~django.contrib.auth.forms.AdminUserCreationForm` and
|
||||
the existing :class:`~django.contrib.auth.forms.AdminPasswordChangeForm` now
|
||||
support disabling password-based authentication by setting an unusable
|
||||
password on form save. This is now available in the admin when visiting the
|
||||
user creation and password change pages.
|
||||
|
||||
* :func:`~.django.contrib.auth.decorators.login_required`,
|
||||
:func:`~.django.contrib.auth.decorators.permission_required`, and
|
||||
@@ -394,6 +398,9 @@ Miscellaneous
|
||||
``width_field`` and ``height_field`` will not match the width and height of
|
||||
the image.
|
||||
|
||||
* The minimum supported version of ``asgiref`` is increased from 3.7.0 to
|
||||
3.8.1.
|
||||
|
||||
.. _deprecated-features-5.1:
|
||||
|
||||
Features deprecated in 5.1
|
||||
|
||||
@@ -52,6 +52,36 @@ Minor features
|
||||
* The default iteration count for the PBKDF2 password hasher is increased from
|
||||
870,000 to 1,000,000.
|
||||
|
||||
* The following new asynchronous methods on are now provided, using an ``a``
|
||||
prefix:
|
||||
|
||||
* :meth:`.UserManager.acreate_user`
|
||||
* :meth:`.UserManager.acreate_superuser`
|
||||
* :meth:`.BaseUserManager.aget_by_natural_key`
|
||||
* :meth:`.User.aget_user_permissions()`
|
||||
* :meth:`.User.aget_all_permissions()`
|
||||
* :meth:`.User.aget_group_permissions()`
|
||||
* :meth:`.User.ahas_perm()`
|
||||
* :meth:`.User.ahas_perms()`
|
||||
* :meth:`.User.ahas_module_perms()`
|
||||
* :meth:`.User.aget_user_permissions()`
|
||||
* :meth:`.User.aget_group_permissions()`
|
||||
* :meth:`.User.ahas_perm()`
|
||||
* :meth:`.ModelBackend.aauthenticate()`
|
||||
* :meth:`.ModelBackend.aget_user_permissions()`
|
||||
* :meth:`.ModelBackend.aget_group_permissions()`
|
||||
* :meth:`.ModelBackend.aget_all_permissions()`
|
||||
* :meth:`.ModelBackend.ahas_perm()`
|
||||
* :meth:`.ModelBackend.ahas_module_perms()`
|
||||
* :meth:`.RemoteUserBackend.aauthenticate()`
|
||||
* :meth:`.RemoteUserBackend.aconfigure_user()`
|
||||
|
||||
* Auth backends can now provide async implementations which are used when
|
||||
calling async auth functions (e.g.
|
||||
:func:`~.django.contrib.auth.aauthenticate`) to reduce context-switching which
|
||||
improves performance. See :ref:`adding an async interface
|
||||
<writing-authentication-backends-async-interface>` for more details.
|
||||
|
||||
:mod:`django.contrib.contenttypes`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -128,7 +158,8 @@ Database backends
|
||||
Decorators
|
||||
~~~~~~~~~~
|
||||
|
||||
* ...
|
||||
* :func:`~django.utils.decorators.method_decorator` now supports wrapping
|
||||
asynchronous view methods.
|
||||
|
||||
Email
|
||||
~~~~~
|
||||
@@ -150,7 +181,8 @@ Email
|
||||
Error Reporting
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
* ...
|
||||
* The attribute :attr:`.SafeExceptionReporterFilter.hidden_settings` now
|
||||
treats values as sensitive if their name includes ``AUTH``.
|
||||
|
||||
File Storage
|
||||
~~~~~~~~~~~~
|
||||
@@ -165,7 +197,15 @@ File Uploads
|
||||
Forms
|
||||
~~~~~
|
||||
|
||||
* ...
|
||||
* The new :class:`~django.forms.ColorInput` form widget is for entering a color
|
||||
in ``rrggbb`` hexadecimal format and renders as ``<input type="color" ...>``.
|
||||
Some browsers support a visual color picker interface for this input type.
|
||||
|
||||
* The new :class:`~django.forms.SearchInput` form widget is for entering search
|
||||
queries and renders as ``<input type="search" ...>``.
|
||||
|
||||
* The new :class:`~django.forms.TelInput` form widget is for entering telephone
|
||||
numbers and renders as ``<input type="tel" ...>``.
|
||||
|
||||
Generic Views
|
||||
~~~~~~~~~~~~~
|
||||
@@ -185,7 +225,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
|
||||
~~~~~~~~~~
|
||||
@@ -203,10 +246,22 @@ Models
|
||||
methods such as
|
||||
:meth:`QuerySet.union()<django.db.models.query.QuerySet.union>` unpredictable.
|
||||
|
||||
* Added support for validation of model constraints which use a
|
||||
:class:`~django.db.models.GeneratedField`.
|
||||
|
||||
* The new :attr:`.Expression.set_returning` attribute specifies that the
|
||||
expression contains a set-returning function, enforcing subquery evaluation.
|
||||
This is necessary for many Postgres set-returning functions.
|
||||
|
||||
* :attr:`CharField.max_length <django.db.models.CharField.max_length>` is no
|
||||
longer required to be set on SQLite, which supports unlimited ``VARCHAR``
|
||||
columns.
|
||||
|
||||
Requests and Responses
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* ...
|
||||
* The new :meth:`.HttpRequest.get_preferred_type` method can be used to query
|
||||
the preferred media type the client accepts.
|
||||
|
||||
Security
|
||||
~~~~~~~~
|
||||
@@ -216,7 +271,9 @@ Security
|
||||
Serialization
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
* ...
|
||||
* Each serialization format now defines a ``Deserializer`` class, rather than a
|
||||
function, to improve extensibility when defining a
|
||||
:ref:`custom serialization format <custom-serialization-formats>`.
|
||||
|
||||
Signals
|
||||
~~~~~~~
|
||||
@@ -231,7 +288,14 @@ Templates
|
||||
Tests
|
||||
~~~~~
|
||||
|
||||
* ...
|
||||
* Stack frames from Django's custom assertions are now hidden. This makes test
|
||||
failures easier to read and enables :option:`test --pdb` to directly enter
|
||||
into the failing test method.
|
||||
|
||||
* Data loaded from :attr:`~django.test.TransactionTestCase.fixtures` and from
|
||||
migrations enabled with :ref:`serialized_rollback=True
|
||||
<test-case-serialized-rollback>` are now available during
|
||||
``TransactionTestCase.setUpClass()``.
|
||||
|
||||
URLs
|
||||
~~~~
|
||||
@@ -241,7 +305,14 @@ URLs
|
||||
Utilities
|
||||
~~~~~~~~~
|
||||
|
||||
* ...
|
||||
* :class:`~django.utils.safestring.SafeString` now returns
|
||||
:py:data:`NotImplemented` in ``__add__`` for non-string right-hand side
|
||||
values. This aligns with the :py:class:`str` addition behavior and allows
|
||||
``__radd__`` to be used if available.
|
||||
|
||||
* :func:`~django.utils.html.format_html_join` now supports taking an iterable
|
||||
of mappings, passing their contents as keyword arguments to
|
||||
:func:`~django.utils.html.format_html`.
|
||||
|
||||
Validators
|
||||
~~~~~~~~~~
|
||||
@@ -259,13 +330,17 @@ Database backend API
|
||||
This section describes changes that may be needed in third-party database
|
||||
backends.
|
||||
|
||||
* ...
|
||||
* The new :meth:`Model._is_pk_set() <django.db.models.Model._is_pk_set>` method
|
||||
allows checking if a Model instance's primary key is defined.
|
||||
|
||||
|
||||
:mod:`django.contrib.gis`
|
||||
-------------------------
|
||||
|
||||
* Support for PostGIS 3.0 is removed.
|
||||
|
||||
* Support for GDAL 3.0 is removed.
|
||||
|
||||
Dropped support for PostgreSQL 13
|
||||
---------------------------------
|
||||
|
||||
@@ -275,7 +350,16 @@ PostgreSQL 14 and higher.
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
* ...
|
||||
* Adding :attr:`.EmailMultiAlternatives.alternatives` is now only supported via
|
||||
the :meth:`~.EmailMultiAlternatives.attach_alternative` method.
|
||||
|
||||
* The minimum supported version of ``gettext`` is increased from 0.15 to 0.19.
|
||||
|
||||
* ``HttpRequest.accepted_types`` is now sorted by the client's preference, based
|
||||
on the request's ``Accept`` header.
|
||||
|
||||
* The :func:`~django.template.context_processors.debug` context processor is no
|
||||
longer included in the default project template.
|
||||
|
||||
.. _deprecated-features-5.2:
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@ versions of the documentation contain the release notes for any later releases.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
5.1.3
|
||||
5.1.2
|
||||
5.1.1
|
||||
5.1
|
||||
|
||||
5.0 release
|
||||
@@ -39,6 +42,7 @@ versions of the documentation contain the release notes for any later releases.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
5.0.9
|
||||
5.0.8
|
||||
5.0.7
|
||||
5.0.6
|
||||
@@ -55,6 +59,8 @@ versions of the documentation contain the release notes for any later releases.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
4.2.16
|
||||
4.2.15
|
||||
4.2.14
|
||||
4.2.13
|
||||
4.2.12
|
||||
|
||||
@@ -36,6 +36,68 @@ Issues under Django's security process
|
||||
All security issues have been handled under versions of Django's security
|
||||
process. These are listed below.
|
||||
|
||||
September 3, 2024 - :cve:`2024-45231`
|
||||
-------------------------------------
|
||||
|
||||
Potential user email enumeration via response status on password reset.
|
||||
`Full description
|
||||
<https://www.djangoproject.com/weblog/2024/sep/03/security-releases/>`__
|
||||
|
||||
* Django 5.1 :commit:`(patch) <3c733c78d6f8e50296d6e248968b6516c92a53ca>`
|
||||
* Django 5.0 :commit:`(patch) <96d84047715ea1715b4bd1594e46122b8a77b9e2>`
|
||||
* Django 4.2 :commit:`(patch) <bf4888d317ba4506d091eeac6e8b4f1fcc731199>`
|
||||
|
||||
September 3, 2024 - :cve:`2024-45230`
|
||||
-------------------------------------
|
||||
|
||||
Potential denial-of-service vulnerability in ``django.utils.html.urlize()``.
|
||||
`Full description
|
||||
<https://www.djangoproject.com/weblog/2024/sep/03/security-releases/>`__
|
||||
|
||||
* Django 5.1 :commit:`(patch) <022ab0a75c76ab2ea31dfcc5f2cf5501e378d397>`
|
||||
* Django 5.0 :commit:`(patch) <813de2672bd7361e9a453ab62cd6e52f96b6525b>`
|
||||
* Django 4.2 :commit:`(patch) <d147a8ebbdf28c17cafbbe2884f0bc57e2bf82e2>`
|
||||
|
||||
August 6, 2024 - :cve:`2024-42005`
|
||||
----------------------------------
|
||||
|
||||
Potential SQL injection in ``QuerySet.values()`` and ``values_list()``.
|
||||
`Full description
|
||||
<https://www.djangoproject.com/weblog/2024/aug/06/security-releases/>`__
|
||||
|
||||
* Django 5.0 :commit:`(patch) <32ebcbf2e1fe3e5ba79a6554a167efce81f7422d>`
|
||||
* Django 4.2 :commit:`(patch) <f4af67b9b41e0f4c117a8741da3abbd1c869ab28>`
|
||||
|
||||
August 6, 2024 - :cve:`2024-41991`
|
||||
----------------------------------
|
||||
|
||||
Potential denial-of-service vulnerability in ``django.utils.html.urlize()`` and
|
||||
``AdminURLFieldWidget``. `Full description
|
||||
<https://www.djangoproject.com/weblog/2024/aug/06/security-releases/>`__
|
||||
|
||||
* Django 5.0 :commit:`(patch) <523da8771bce321023f490f70d71a9e973ddc927>`
|
||||
* Django 4.2 :commit:`(patch) <efea1ef7e2190e3f77ca0651b5458297bc0f6a9f>`
|
||||
|
||||
August 6, 2024 - :cve:`2024-41990`
|
||||
----------------------------------
|
||||
|
||||
Potential denial-of-service vulnerability in ``django.utils.html.urlize()``.
|
||||
`Full description
|
||||
<https://www.djangoproject.com/weblog/2024/aug/06/security-releases/>`__
|
||||
|
||||
* Django 5.0 :commit:`(patch) <7b7b909579c8311c140c89b8a9431bf537febf93>`
|
||||
* Django 4.2 :commit:`(patch) <d0a82e26a74940bf0c78204933c3bdd6a283eb88>`
|
||||
|
||||
August 6, 2024 - :cve:`2024-41989`
|
||||
----------------------------------
|
||||
|
||||
Potential memory exhaustion in ``django.utils.numberformat.floatformat()``.
|
||||
`Full description
|
||||
<https://www.djangoproject.com/weblog/2024/aug/06/security-releases/>`__
|
||||
|
||||
* Django 5.0 :commit:`(patch) <27900fe56f3d3cabb4aeb6ccb82f92bab29073a8>`
|
||||
* Django 4.2 :commit:`(patch) <fc76660f589ac07e45e9cd34ccb8087aeb11904b>`
|
||||
|
||||
July 9, 2024 - :cve:`2024-39614`
|
||||
--------------------------------
|
||||
|
||||
|
||||
@@ -141,6 +141,7 @@ Disqus
|
||||
distro
|
||||
django
|
||||
djangoproject
|
||||
djangotutorial
|
||||
dm
|
||||
docstring
|
||||
docstrings
|
||||
|
||||
@@ -400,10 +400,9 @@ the Django model that you wish to use as your user model.
|
||||
Using a custom user model when starting a project
|
||||
-------------------------------------------------
|
||||
|
||||
If you're starting a new project, it's highly recommended to set up a custom
|
||||
user model, even if the default :class:`~django.contrib.auth.models.User` model
|
||||
is sufficient for you. This model behaves identically to the default user
|
||||
model, but you'll be able to customize it in the future if the need arises::
|
||||
If you're starting a new project, you can set up a custom user model that
|
||||
behaves identically to the default user model by subclassing
|
||||
:class:`~django.contrib.auth.models.AbstractUser`::
|
||||
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
|
||||
@@ -426,7 +425,7 @@ Changing to a custom user model mid-project
|
||||
-------------------------------------------
|
||||
|
||||
Changing :setting:`AUTH_USER_MODEL` after you've created database tables is
|
||||
significantly more difficult since it affects foreign keys and many-to-many
|
||||
possible, but can be complex, since it affects foreign keys and many-to-many
|
||||
relationships, for example.
|
||||
|
||||
This change can't be done automatically and requires manually fixing your
|
||||
@@ -791,10 +790,17 @@ utility methods:
|
||||
email address.
|
||||
|
||||
.. method:: models.BaseUserManager.get_by_natural_key(username)
|
||||
.. method:: models.BaseUserManager.aget_by_natural_key(username)
|
||||
|
||||
*Asynchronous version*: ``aget_by_natural_key()``
|
||||
|
||||
Retrieves a user instance using the contents of the field
|
||||
nominated by ``USERNAME_FIELD``.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
``aget_by_natural_key()`` method was added.
|
||||
|
||||
Extending Django's default ``User``
|
||||
-----------------------------------
|
||||
|
||||
@@ -1187,3 +1193,25 @@ Finally, specify the custom model as the default user model for your project
|
||||
using the :setting:`AUTH_USER_MODEL` setting in your ``settings.py``::
|
||||
|
||||
AUTH_USER_MODEL = "customauth.MyUser"
|
||||
|
||||
.. _writing-authentication-backends-async-interface:
|
||||
|
||||
Adding an async interface
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
To optimize performance when called from an async context authentication,
|
||||
backends can implement async versions of each function - ``aget_user(user_id)``
|
||||
and ``aauthenticate(request, **credentials)``. When an authentication backend
|
||||
extends ``BaseBackend`` and async versions of these functions are not provided,
|
||||
they will be automatically synthesized with ``sync_to_async``. This has
|
||||
:ref:`performance penalties <async_performance>`.
|
||||
|
||||
While an async interface is optional, a synchronous interface is always
|
||||
required. There is no automatic synthesis for a synchronous interface if an
|
||||
async interface is implemented.
|
||||
|
||||
Django's out-of-the-box authentication backends have native async support. If
|
||||
these native backends are extended take special care to make sure the async
|
||||
versions of modified functions are modified as well.
|
||||
|
||||
@@ -655,7 +655,7 @@ login view, may need to disable this behavior.
|
||||
|
||||
.. function:: login_not_required()
|
||||
|
||||
Allows unauthenticated requests without redirecting to the login page when
|
||||
Allows unauthenticated requests to this view when
|
||||
:class:`~django.contrib.auth.middleware.LoginRequiredMiddleware` is
|
||||
installed.
|
||||
|
||||
@@ -1645,6 +1645,23 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`:
|
||||
Option to disable (or reenable) password-based authentication was
|
||||
added.
|
||||
|
||||
.. class:: AdminUserCreationForm
|
||||
|
||||
.. versionadded:: 5.1.1
|
||||
|
||||
A form used in the admin interface to create a new user. Inherits from
|
||||
:class:`UserCreationForm`.
|
||||
|
||||
It includes an additional ``usable_password`` field, enabled by default. If
|
||||
``usable_password`` is enabled, it verifies that ``password1`` and
|
||||
``password2`` are non empty and match, validates the password using
|
||||
:func:`~django.contrib.auth.password_validation.validate_password`, and
|
||||
sets the user's password using
|
||||
:meth:`~django.contrib.auth.models.User.set_password()`.
|
||||
If ``usable_password`` is disabled, no password validation is done, and
|
||||
password-based authentication is disabled for the user by calling
|
||||
:meth:`~django.contrib.auth.models.User.set_unusable_password()`.
|
||||
|
||||
.. class:: AuthenticationForm
|
||||
|
||||
A form for logging a user in.
|
||||
@@ -1691,6 +1708,18 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`:
|
||||
code="no_b_users",
|
||||
)
|
||||
|
||||
.. class:: BaseUserCreationForm
|
||||
|
||||
A :class:`~django.forms.ModelForm` for creating a new user. This is the
|
||||
recommended base class if you need to customize the user creation form.
|
||||
|
||||
It has three fields: ``username`` (from the user model), ``password1``,
|
||||
and ``password2``. It verifies that ``password1`` and ``password2`` match,
|
||||
validates the password using
|
||||
:func:`~django.contrib.auth.password_validation.validate_password`, and
|
||||
sets the user's password using
|
||||
:meth:`~django.contrib.auth.models.User.set_password()`.
|
||||
|
||||
.. class:: PasswordChangeForm
|
||||
|
||||
A form for allowing a user to change their password.
|
||||
@@ -1703,7 +1732,9 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`:
|
||||
.. method:: send_mail(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None)
|
||||
|
||||
Uses the arguments to send an ``EmailMultiAlternatives``.
|
||||
Can be overridden to customize how the email is sent to the user.
|
||||
Can be overridden to customize how the email is sent to the user. If
|
||||
you choose to override this method, be mindful of handling potential
|
||||
exceptions raised due to email sending failures.
|
||||
|
||||
:param subject_template_name: the template for the subject.
|
||||
:param email_template_name: the template for the email body.
|
||||
@@ -1730,27 +1761,6 @@ provides several built-in forms located in :mod:`django.contrib.auth.forms`:
|
||||
A form used in the admin interface to change a user's information and
|
||||
permissions.
|
||||
|
||||
.. class:: BaseUserCreationForm
|
||||
|
||||
A :class:`~django.forms.ModelForm` for creating a new user. This is the
|
||||
recommended base class if you need to customize the user creation form.
|
||||
|
||||
It has four fields: ``username`` (from the user model), ``password1``,
|
||||
``password2``, and ``usable_password`` (the latter is enabled by default).
|
||||
If ``usable_password`` is enabled, it verifies that ``password1`` and
|
||||
``password2`` are non empty and match, validates the password using
|
||||
:func:`~django.contrib.auth.password_validation.validate_password`, and
|
||||
sets the user's password using
|
||||
:meth:`~django.contrib.auth.models.User.set_password()`.
|
||||
If ``usable_password`` is disabled, no password validation is done, and
|
||||
password-based authentication is disabled for the user by calling
|
||||
:meth:`~django.contrib.auth.models.User.set_unusable_password()`.
|
||||
|
||||
.. versionchanged:: 5.1
|
||||
|
||||
Option to create users with disabled password-based authentication was
|
||||
added.
|
||||
|
||||
.. class:: UserCreationForm
|
||||
|
||||
Inherits from :class:`BaseUserCreationForm`. To help prevent confusion with
|
||||
|
||||
@@ -273,3 +273,56 @@ works with an API-based workflow as well as 'normal' form POSTs::
|
||||
class AuthorCreateView(JsonableResponseMixin, CreateView):
|
||||
model = Author
|
||||
fields = ["name"]
|
||||
|
||||
The above example assumes that if the client supports ``text/html``, that they
|
||||
would prefer it. However, this may not always be true. When requesting a
|
||||
``.css`` file, many browsers will send the header
|
||||
``Accept: text/css,*/*;q=0.1``, indicating that they would prefer CSS, but
|
||||
anything else is fine. This means ``request.accepts("text/html") will be
|
||||
``True``.
|
||||
|
||||
To determine the correct format, taking into consideration the client's
|
||||
preference, use :func:`django.http.HttpRequest.get_preferred_type`::
|
||||
|
||||
class JsonableResponseMixin:
|
||||
"""
|
||||
Mixin to add JSON support to a form.
|
||||
Must be used with an object-based FormView (e.g. CreateView).
|
||||
"""
|
||||
|
||||
accepted_media_types = ["text/html", "application/json"]
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if request.get_preferred_type(self.accepted_media_types) is None:
|
||||
# No format in common.
|
||||
return HttpResponse(
|
||||
status_code=406, headers={"Accept": ",".join(self.accepted_media_types)}
|
||||
)
|
||||
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def form_invalid(self, form):
|
||||
response = super().form_invalid(form)
|
||||
accepted_type = request.get_preferred_type(self.accepted_media_types)
|
||||
if accepted_type == "text/html":
|
||||
return response
|
||||
elif accepted_type == "application/json":
|
||||
return JsonResponse(form.errors, status=400)
|
||||
|
||||
def form_valid(self, form):
|
||||
# We make sure to call the parent's form_valid() method because
|
||||
# it might do some processing (in the case of CreateView, it will
|
||||
# call form.save() for example).
|
||||
response = super().form_valid(form)
|
||||
accepted_type = request.get_preferred_type(self.accepted_media_types)
|
||||
if accepted_type == "text/html":
|
||||
return response
|
||||
elif accepted_type == "application/json":
|
||||
data = {
|
||||
"pk": self.object.pk,
|
||||
}
|
||||
return JsonResponse(data)
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
The :meth:`.HttpRequest.get_preferred_type` method was added.
|
||||
|
||||
@@ -720,6 +720,9 @@ Django places some restrictions on model field names:
|
||||
|
||||
#. A field name cannot end with an underscore, for similar reasons.
|
||||
|
||||
#. A field name cannot be ``check``, as this would override the check
|
||||
framework's ``Model.check()`` method.
|
||||
|
||||
These limitations can be worked around, though, because your field name doesn't
|
||||
necessarily have to match your database column name. See the
|
||||
:attr:`~Field.db_column` option.
|
||||
@@ -914,7 +917,7 @@ example::
|
||||
if (
|
||||
update_fields := kwargs.get("update_fields")
|
||||
) is not None and "name" in update_fields:
|
||||
update_fields = {"slug"}.union(update_fields)
|
||||
kwargs["update_fields"] = {"slug"}.union(update_fields)
|
||||
super().save(**kwargs)
|
||||
|
||||
See :ref:`ref-models-update-fields` for more details.
|
||||
|
||||
@@ -14,7 +14,7 @@ As general programming practice, this goes without saying. Find out :ref:`what
|
||||
queries you are doing and what they are costing you <faq-see-raw-sql-queries>`.
|
||||
Use :meth:`.QuerySet.explain` to understand how specific ``QuerySet``\s are
|
||||
executed by your database. You may also want to use an external project like
|
||||
django-debug-toolbar_, or a tool that monitors your database directly.
|
||||
:pypi:`django-debug-toolbar`, or a tool that monitors your database directly.
|
||||
|
||||
Remember that you may be optimizing for speed or memory or both, depending on
|
||||
your requirements. Sometimes optimizing for one will be detrimental to the
|
||||
@@ -30,8 +30,6 @@ readability of your code. **All** of the suggestions below come with the caveat
|
||||
that in your circumstances the general principle might not apply, or might even
|
||||
be reversed.
|
||||
|
||||
.. _django-debug-toolbar: https://github.com/jazzband/django-debug-toolbar/
|
||||
|
||||
Use standard DB optimization techniques
|
||||
=======================================
|
||||
|
||||
|
||||
@@ -62,7 +62,8 @@ class represents a particular record in the database table.
|
||||
To create an object, instantiate it using keyword arguments to the model class,
|
||||
then call :meth:`~django.db.models.Model.save` to save it to the database.
|
||||
|
||||
Assuming models live in a file ``mysite/blog/models.py``, here's an example:
|
||||
Assuming models live in a ``models.py`` file inside a ``blog`` Django app, here
|
||||
is an example:
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
|
||||
@@ -12,10 +12,11 @@ development, and to provide support for platforms that can't use SMTP.
|
||||
|
||||
The code lives in the ``django.core.mail`` module.
|
||||
|
||||
Quick example
|
||||
=============
|
||||
Quick examples
|
||||
==============
|
||||
|
||||
In two lines::
|
||||
Use :func:`send_mail` for straightforward email sending. For example, to send a
|
||||
plain text message::
|
||||
|
||||
from django.core.mail import send_mail
|
||||
|
||||
@@ -27,6 +28,39 @@ In two lines::
|
||||
fail_silently=False,
|
||||
)
|
||||
|
||||
When additional email sending functionality is needed, use
|
||||
:class:`EmailMessage` or :class:`EmailMultiAlternatives`. For example, to send
|
||||
a multipart email that includes both HTML and plain text versions with a
|
||||
specific template and custom headers, you can use the following approach::
|
||||
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
# First, render the plain text content.
|
||||
text_content = render_to_string(
|
||||
"templates/emails/my_email.txt",
|
||||
context={"my_variable": 42},
|
||||
)
|
||||
|
||||
# Secondly, render the HTML content.
|
||||
html_content = render_to_string(
|
||||
"templates/emails/my_email.html",
|
||||
context={"my_variable": 42},
|
||||
)
|
||||
|
||||
# Then, create a multipart email instance.
|
||||
msg = EmailMultiAlternatives(
|
||||
"Subject here",
|
||||
text_content,
|
||||
"from@example.com",
|
||||
["to@example.com"],
|
||||
headers={"List-Unsubscribe": "<mailto:unsub@example.com>"},
|
||||
)
|
||||
|
||||
# Lastly, attach the HTML content to the email instance and send.
|
||||
msg.attach_alternative(html_content, "text/html")
|
||||
msg.send()
|
||||
|
||||
Mail is sent using the SMTP host and port specified in the
|
||||
:setting:`EMAIL_HOST` and :setting:`EMAIL_PORT` settings. The
|
||||
:setting:`EMAIL_HOST_USER` and :setting:`EMAIL_HOST_PASSWORD` settings, if
|
||||
@@ -282,13 +316,14 @@ All parameters are optional and can be set at any time prior to calling the
|
||||
new connection is created when ``send()`` is called.
|
||||
|
||||
* ``attachments``: A list of attachments to put on the message. These can
|
||||
be either :class:`~email.mime.base.MIMEBase` instances, or a named tuple
|
||||
with attributes ``(filename, content, mimetype)``.
|
||||
be instances of :class:`~email.mime.base.MIMEBase` or
|
||||
:class:`~django.core.mail.EmailAttachment`, or a tuple with attributes
|
||||
``(filename, content, mimetype)``.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
In older versions, tuple items of ``attachments`` were regular tuples,
|
||||
as opposed to named tuples.
|
||||
Support for :class:`~django.core.mail.EmailAttachment` items of
|
||||
``attachments`` were added.
|
||||
|
||||
* ``headers``: A dictionary of extra headers to put on the message. The
|
||||
keys are the header name, values are the header values. It's up to the
|
||||
@@ -384,6 +419,18 @@ The class has the following methods:
|
||||
For MIME types starting with :mimetype:`text/`, binary data is handled as in
|
||||
``attach()``.
|
||||
|
||||
.. class:: EmailAttachment
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
A named tuple to store attachments to an email.
|
||||
|
||||
The named tuple has the following indexes:
|
||||
|
||||
* ``filename``
|
||||
* ``content``
|
||||
* ``mimetype``
|
||||
|
||||
Sending alternative content types
|
||||
---------------------------------
|
||||
|
||||
@@ -404,20 +451,21 @@ Django's email library, you can do this using the
|
||||
|
||||
.. attribute:: alternatives
|
||||
|
||||
A list of named tuples with attributes ``(content, mimetype)``. This is
|
||||
particularly useful in tests::
|
||||
A list of :class:`~django.core.mail.EmailAlternative` named tuples. This
|
||||
is particularly useful in tests::
|
||||
|
||||
self.assertEqual(len(msg.alternatives), 1)
|
||||
self.assertEqual(msg.alternatives[0].content, html_content)
|
||||
self.assertEqual(msg.alternatives[0].mimetype, "text/html")
|
||||
|
||||
Alternatives should only be added using the :meth:`attach_alternative`
|
||||
method.
|
||||
method, or passed to the constructor.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
In older versions, ``alternatives`` was a list of regular tuples,
|
||||
as opposed to named tuples.
|
||||
as opposed to :class:`~django.core.mail.EmailAlternative` named
|
||||
tuples.
|
||||
|
||||
.. method:: attach_alternative(content, mimetype)
|
||||
|
||||
@@ -456,6 +504,17 @@ Django's email library, you can do this using the
|
||||
self.assertIs(msg.body_contains("I am content"), True)
|
||||
self.assertIs(msg.body_contains("<p>I am content.</p>"), False)
|
||||
|
||||
.. class:: EmailAlternative
|
||||
|
||||
.. versionadded:: 5.2
|
||||
|
||||
A named tuple to store alternative versions of email content.
|
||||
|
||||
The named tuple has the following indexes:
|
||||
|
||||
* ``content``
|
||||
* ``mimetype``
|
||||
|
||||
Updating the default content type
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -749,7 +808,7 @@ to a file that can be inspected at your leisure.
|
||||
|
||||
Another approach is to use a "dumb" SMTP server that receives the emails
|
||||
locally and displays them to the terminal, but does not actually send
|
||||
anything. The `aiosmtpd`_ package provides a way to accomplish this:
|
||||
anything. The :pypi:`aiosmtpd` package provides a way to accomplish this:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
|
||||
@@ -1335,9 +1335,7 @@ whenever you restart your application server::
|
||||
|
||||
You can even pre-generate the JavaScript catalog as part of your deployment
|
||||
procedure and serve it as a static file. This radical technique is implemented
|
||||
in django-statici18n_.
|
||||
|
||||
.. _django-statici18n: https://django-statici18n.readthedocs.io/
|
||||
in :pypi:`django-statici18n`.
|
||||
|
||||
.. _url-internationalization:
|
||||
|
||||
@@ -1553,7 +1551,7 @@ Django comes with a tool, :djadmin:`django-admin makemessages
|
||||
commands from the GNU gettext toolset: ``xgettext``, ``msgfmt``,
|
||||
``msgmerge`` and ``msguniq``.
|
||||
|
||||
The minimum version of the ``gettext`` utilities supported is 0.15.
|
||||
The minimum version of the ``gettext`` utilities supported is 0.19.
|
||||
|
||||
To create or update a message file, run this command:
|
||||
|
||||
|
||||
@@ -55,11 +55,10 @@ code.
|
||||
Django tools
|
||||
~~~~~~~~~~~~
|
||||
|
||||
`django-debug-toolbar
|
||||
<https://github.com/jazzband/django-debug-toolbar/>`_ is a very handy tool that
|
||||
provides insights into what your code is doing and how much time it spends
|
||||
doing it. In particular it can show you all the SQL queries your page is
|
||||
generating, and how long each one has taken.
|
||||
:pypi:`django-debug-toolbar` is a very handy tool that provides insights into
|
||||
what your code is doing and how much time it spends doing it. In particular it
|
||||
can show you all the SQL queries your page is generating, and how long each one
|
||||
has taken.
|
||||
|
||||
Third-party panels are also available for the toolbar, that can (for example)
|
||||
report on cache performance and template rendering times.
|
||||
|
||||
@@ -347,6 +347,86 @@ again a mapping with the key being name of the field and the value the value:
|
||||
|
||||
Referential fields are again represented by the PK or sequence of PKs.
|
||||
|
||||
.. _custom-serialization-formats:
|
||||
|
||||
Custom serialization formats
|
||||
----------------------------
|
||||
|
||||
In addition to the default formats, you can create a custom serialization
|
||||
format.
|
||||
|
||||
For example, let’s consider a csv serializer and deserializer. First, define a
|
||||
``Serializer`` and a ``Deserializer`` class. These can override existing
|
||||
serialization format classes:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: ``path/to/custom_csv_serializer.py``
|
||||
|
||||
import csv
|
||||
|
||||
from django.apps import apps
|
||||
from django.core import serializers
|
||||
from django.core.serializers.base import DeserializationError
|
||||
|
||||
|
||||
class Serializer(serializers.python.Serializer):
|
||||
def get_dump_object(self, obj):
|
||||
dumped_object = super().get_dump_object(obj)
|
||||
row = [dumped_object["model"], str(dumped_object["pk"])]
|
||||
row += [str(value) for value in dumped_object["fields"].values()]
|
||||
return ",".join(row), dumped_object["model"]
|
||||
|
||||
def end_object(self, obj):
|
||||
dumped_object_str, model = self.get_dump_object(obj)
|
||||
if self.first:
|
||||
fields = [field.name for field in apps.get_model(model)._meta.fields]
|
||||
header = ",".join(fields)
|
||||
self.stream.write(f"model,{header}\n")
|
||||
self.stream.write(f"{dumped_object_str}\n")
|
||||
|
||||
def getvalue(self):
|
||||
return super(serializers.python.Serializer, self).getvalue()
|
||||
|
||||
|
||||
class Deserializer(serializers.python.Deserializer):
|
||||
def __init__(self, stream_or_string, **options):
|
||||
if isinstance(stream_or_string, bytes):
|
||||
stream_or_string = stream_or_string.decode()
|
||||
if isinstance(stream_or_string, str):
|
||||
stream_or_string = stream_or_string.splitlines()
|
||||
try:
|
||||
objects = csv.DictReader(stream_or_string)
|
||||
except Exception as exc:
|
||||
raise DeserializationError() from exc
|
||||
super().__init__(objects, **options)
|
||||
|
||||
def _handle_object(self, obj):
|
||||
try:
|
||||
model_fields = apps.get_model(obj["model"])._meta.fields
|
||||
obj["fields"] = {
|
||||
field.name: obj[field.name]
|
||||
for field in model_fields
|
||||
if field.name in obj
|
||||
}
|
||||
yield from super()._handle_object(obj)
|
||||
except (GeneratorExit, DeserializationError):
|
||||
raise
|
||||
except Exception as exc:
|
||||
raise DeserializationError(f"Error deserializing object: {exc}") from exc
|
||||
|
||||
Then add the module containing the serializer definitions to your
|
||||
:setting:`SERIALIZATION_MODULES` setting::
|
||||
|
||||
SERIALIZATION_MODULES = {
|
||||
"csv": "path.to.custom_csv_serializer",
|
||||
"json": "django.core.serializers.json",
|
||||
}
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
A ``Deserializer`` class definition was added to each of the provided
|
||||
serialization formats.
|
||||
|
||||
.. _topics-serialization-natural-keys:
|
||||
|
||||
Natural keys
|
||||
|
||||
@@ -50,7 +50,7 @@ To sign a value, first instantiate a ``Signer`` instance:
|
||||
>>> signer = Signer()
|
||||
>>> value = signer.sign("My string")
|
||||
>>> value
|
||||
'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w'
|
||||
'My string:v9G-nxfz3iQGTXrePqYPlGvH79WTcIgj1QIQSUODTW0'
|
||||
|
||||
The signature is appended to the end of the string, following the colon.
|
||||
You can retrieve the original value using the ``unsign`` method:
|
||||
@@ -79,7 +79,7 @@ If you wish to protect a list, tuple, or dictionary you can do so using the
|
||||
|
||||
>>> signed_obj = signer.sign_object({"message": "Hello!"})
|
||||
>>> signed_obj
|
||||
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:Xdc-mOFDjs22KsQAqfVfi8PQSPdo3ckWJxPWwQOFhR4'
|
||||
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:bzb48DBkB-bwLaCnUVB75r5VAPUEpzWJPrTb80JMIXM'
|
||||
>>> obj = signer.unsign_object(signed_obj)
|
||||
>>> obj
|
||||
{'message': 'Hello!'}
|
||||
@@ -108,7 +108,7 @@ generate signatures. You can use a different secret by passing it to the
|
||||
>>> signer = Signer(key="my-other-secret")
|
||||
>>> value = signer.sign("My string")
|
||||
>>> value
|
||||
'My string:EkfQJafvGyiofrdGnuthdxImIJw'
|
||||
'My string:o3DrrsT6JRB73t-HDymfDNbTSxfMlom2d8TiUlb1hWY'
|
||||
|
||||
.. class:: Signer(*, key=None, sep=':', salt=None, algorithm=None, fallback_keys=None)
|
||||
|
||||
@@ -132,13 +132,13 @@ your :setting:`SECRET_KEY`:
|
||||
|
||||
>>> signer = Signer()
|
||||
>>> signer.sign("My string")
|
||||
'My string:GdMGD6HNQ_qdgxYP8yBZAdAIV1w'
|
||||
'My string:v9G-nxfz3iQGTXrePqYPlGvH79WTcIgj1QIQSUODTW0'
|
||||
>>> signer.sign_object({"message": "Hello!"})
|
||||
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:Xdc-mOFDjs22KsQAqfVfi8PQSPdo3ckWJxPWwQOFhR4'
|
||||
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:bzb48DBkB-bwLaCnUVB75r5VAPUEpzWJPrTb80JMIXM'
|
||||
>>> signer = Signer(salt="extra")
|
||||
>>> signer.sign("My string")
|
||||
'My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw'
|
||||
>>> signer.unsign("My string:Ee7vGi-ING6n02gkcJ-QLHg6vFw")
|
||||
'My string:YMD-FR6rof3heDkFRffdmG4pXbAZSOtb-aQxg3vmmfc'
|
||||
>>> signer.unsign("My string:YMD-FR6rof3heDkFRffdmG4pXbAZSOtb-aQxg3vmmfc")
|
||||
'My string'
|
||||
>>> signer.sign_object({"message": "Hello!"})
|
||||
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:-UWSLCE-oUAHzhkHviYz3SOZYBjFKllEOyVZNuUtM-I'
|
||||
@@ -172,7 +172,7 @@ created within a specified period of time:
|
||||
>>> signer = TimestampSigner()
|
||||
>>> value = signer.sign("hello")
|
||||
>>> value
|
||||
'hello:1NMg5H:oPVuCqlJWmChm1rA2lyTUtelC-c'
|
||||
'hello:1stLqR:_rvr4oXCgT4HyfwjXaU39QvTnuNuUthFRCzNOy4Hqt0'
|
||||
>>> signer.unsign(value)
|
||||
'hello'
|
||||
>>> signer.unsign(value, max_age=10)
|
||||
@@ -224,12 +224,12 @@ arbitrary commands by exploiting the pickle format:
|
||||
>>> signer = signing.TimestampSigner()
|
||||
>>> value = signer.sign_object({"foo": "bar"})
|
||||
>>> value
|
||||
'eyJmb28iOiJiYXIifQ:1kx6R3:D4qGKiptAqo5QW9iv4eNLc6xl4RwiFfes6oOcYhkYnc'
|
||||
'eyJmb28iOiJiYXIifQ:1stLrZ:_QiOBHafwucBF9FyAr54qEs84ZO1UdsO1XiTJCvvdno'
|
||||
>>> signer.unsign_object(value)
|
||||
{'foo': 'bar'}
|
||||
>>> value = signing.dumps({"foo": "bar"})
|
||||
>>> value
|
||||
'eyJmb28iOiJiYXIifQ:1kx6Rf:LBB39RQmME-SRvilheUe5EmPYRbuDBgQp2tCAi7KGLk'
|
||||
'eyJmb28iOiJiYXIifQ:1stLsC:JItq2ZVjmAK6ivrWI-v1Gk1QVf2hOF52oaEqhZHca7I'
|
||||
>>> signing.loads(value)
|
||||
{'foo': 'bar'}
|
||||
|
||||
|
||||
@@ -280,6 +280,11 @@ To prevent serialized data from being loaded twice, setting
|
||||
:data:`~django.db.models.signals.post_migrate` signal when flushing the test
|
||||
database.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
For :class:`TransactionTestCase`, serialized migration data is made
|
||||
available during ``setUpClass()``.
|
||||
|
||||
Other test conditions
|
||||
---------------------
|
||||
|
||||
|
||||
@@ -1262,25 +1262,35 @@ subclass::
|
||||
|
||||
Here's specifically what will happen:
|
||||
|
||||
* At the start of each test, before ``setUp()`` is run, Django will flush the
|
||||
database, returning the database to the state it was in directly after
|
||||
:djadmin:`migrate` was called.
|
||||
* During ``setUpClass()``, all the named fixtures are installed. In this
|
||||
example, Django will install any JSON fixture named ``mammals``, followed by
|
||||
any fixture named ``birds``. See the :ref:`fixtures-explanation` topic for
|
||||
more details on defining and installing fixtures.
|
||||
|
||||
* Then, all the named fixtures are installed. In this example, Django will
|
||||
install any JSON fixture named ``mammals``, followed by any fixture named
|
||||
``birds``. See the :ref:`fixtures-explanation` topic for more details on
|
||||
defining and installing fixtures.
|
||||
For most unit tests using :class:`TestCase`, Django doesn't need to do
|
||||
anything else, because transactions are used to clean the database after each
|
||||
test for performance reasons. But for :class:`TransactionTestCase`, the
|
||||
following actions will take place:
|
||||
|
||||
For performance reasons, :class:`TestCase` loads fixtures once for the entire
|
||||
test class, before :meth:`~TestCase.setUpTestData`, instead of before each
|
||||
test, and it uses transactions to clean the database before each test. In any case,
|
||||
you can be certain that the outcome of a test will not be affected by another
|
||||
test or by the order of test execution.
|
||||
* At the end of each test Django will flush the database, returning the
|
||||
database to the state it was in directly after :djadmin:`migrate` was
|
||||
called.
|
||||
|
||||
* For each subsequent test, the fixtures will be reloaded before ``setUp()``
|
||||
is run.
|
||||
|
||||
In any case, you can be certain that the outcome of a test will not be
|
||||
affected by another test or by the order of test execution.
|
||||
|
||||
By default, fixtures are only loaded into the ``default`` database. If you are
|
||||
using multiple databases and set :attr:`TransactionTestCase.databases`,
|
||||
fixtures will be loaded into all specified databases.
|
||||
|
||||
.. versionchanged:: 5.2
|
||||
|
||||
For :class:`TransactionTestCase`, fixtures were made available during
|
||||
``setUpClass()``.
|
||||
|
||||
URLconf configuration
|
||||
---------------------
|
||||
|
||||
|
||||