Compare commits

...

58 Commits

Author SHA1 Message Date
Claude Paroz
b8edb1816c
Merge 73b904c5e0 into a627194567 2025-08-30 11:38:44 -04:00
Jacob Walls
a627194567
Refs #36485 -- Corrected docs linter to detect too-long lines at file end. 2025-08-29 17:35:50 -04:00
SaJH
bb7a7701b1 Fixed #36431 -- Returned tuples for multi-column ForeignObject in values()/values_list().
Thanks Jacob Walls and Simon Charette for tests.

Signed-off-by: SaJH <wogur981208@gmail.com>
2025-08-29 15:33:44 -04:00
Jacob Walls
2d453a2a68 Refs #36152 -- Suppressed duplicate warning when using "%" in alias via values(). 2025-08-29 13:45:08 -04:00
Mustafa Pirbhai
183fcebf88 Fixed #35831 -- Documented the model form meta API in model form reference docs.
Co-authored-by: Jonathan <3218047+jernwerber@users.noreply.github.com>
Co-authored-by: Mustafa <117516335+mspirbhai@users.noreply.github.com>
2025-08-29 08:58:58 +02:00
SaJH
eaaf01c96a Refs #34624 -- Changed RedirectAdmin to use a Select widget for the site field.
Signed-off-by: SaJH <wogur981208@gmail.com>
2025-08-29 08:38:12 +02:00
SaJH
0be1c4575b Fixed #34624 -- Removed change, delete, and view buttons for non-Select widgets in RelatedFieldWidgetWrapper.
Signed-off-by: SaJH <wogur981208@gmail.com>
2025-08-29 08:38:12 +02:00
Rob Hudson
550822bcee Fixed #36532 -- Added Content Security Policy view decorators to override or disable policies.
Co-authored-by: Natalia <124304+nessita@users.noreply.github.com>
2025-08-28 17:23:48 -03:00
Simon Charette
292b9e6fe8 Refs #27222 -- Adapted RETURNING handling to be usable for UPDATE queries.
Renamed existing methods and abstractions used for INSERT … RETURNING
to be generic enough to be used in the context of UPDATEs as well.

This also consolidates SQL compliant implementations on
BaseDatabaseOperations.
2025-08-28 20:44:21 +02:00
Simon Charette
dc4ee99152 Refs #27222 -- Implemented BaseDatabaseOperations.return_insert_columns()/fetch_returned_insert_rows(). 2025-08-28 20:44:21 +02:00
Jake Howard
41ff30f6f9 Refs #36520 -- Ensured only the header value is passed to parse_header_parameters for multipart requests.
Header parsing should apply only to the header value. The previous
implementation happened to work but relied on unintended behavior.
2025-08-28 14:25:36 -03:00
David Smith
c93dddf659 Added sphinxlint checker to flag relative targets in :doc: roles.
Co-authored-by: Adam Johnson <me@adamj.eu>
2025-08-28 13:48:32 -03:00
Adam Johnson
56955636e6 Ensured :doc: role uses absolute targets in docs. 2025-08-28 13:48:32 -03:00
Natalia
ae03f81ffa Replaced :doc: role usage with :ref: when appropriate in docs. 2025-08-28 13:48:32 -03:00
SaJH
a9fe98d5bd Fixed #35533 -- Prevented urlize creating broken links given a markdown link input.
Signed-off-by: SaJH <wogur981208@gmail.com>
2025-08-28 08:54:56 +02:00
David Smith
05bac8c420 Refs #36570 -- Added sphinxlint checker to flag unnecessary :py domain in documentation roles. 2025-08-28 08:52:43 +02:00
SaJH
3c0c54351b Fixed #36570 -- Removed unnecessary :py domain from documentation roles.
Signed-off-by: SaJH <wogur981208@gmail.com>
2025-08-28 08:52:43 +02:00
Tim Graham
1285de557b Fixed incorrect IDs in test_in_bulk_preserve_ordering. 2025-08-27 18:23:42 -04:00
Adam Johnson
d8426f64a7 Fixed #36577 -- Removed obsolete try-except for GIS layermapping imports. 2025-08-27 13:16:28 -03:00
Natalia
4f07767106 Added matrix with newer image versions to the "postgis" GitHub Action.
This work allows to test three types of postgis Docker images to cover
a wider spectrum of geo libraries versions:

* `latest` (recommended upstream): uses latest stable Debian packages.
  These versions are generally conservative, so they may lag behind.
* `alpine`: build PostGIS from source on Alpine, and ship newer
  geospatial libs.
* `master`: provides development versions, therefore coverage for what's
  coming. Future compatibility issues can be caught in advance.

This split is important because each image differs significantly in
GEOS/PROJ/GDAL versions, so testing all increases confidence in
compatibility. More info at https://hub.docker.com/r/postgis/postgis/.

For example, at the time of this branch:

* latest stable in debian:
  * POSTGIS="3.5.2 dea6d0a"
  * GEOS="3.9.0-CAPI-1.16.2"
  * PROJ="7.2.1"
* latest stable in alpine:
  * POSTGIS="3.5.3 0"
  * GEOS="3.13.1-CAPI-1.19.2"
  * PROJ="9.6.0
* latest development branch:
  * POSTGIS="3.6.0dev 3.6.0beta1-29-g7c8cfe07d"
  * GEOS="3.14.0beta2-CAPI-1.20.1"
  * PROJ="9.7.0"
2025-08-27 11:33:13 -03:00
Natalia
1b0c4d5ea5 Ensured apt repo is updated before installing deps in "postgis" GitHub Action. 2025-08-27 11:33:13 -03:00
Sarah Boyce
4c71e33440 Added stub release notes and release date for 5.2.6, 5.1.12, and 4.2.24. 2025-08-27 16:01:20 +02:00
Sarah Boyce
d0e4dd5cdd Fixed #36572 -- Revert "Fixed #36546 -- Deprecated django.utils.crypto.constant_time_compare() in favor of hmac.compare_digest()."
This reverts commit 0246f47888.
2025-08-27 10:50:50 +02:00
Jacob Walls
c594574175 Clarified Trac "version" attribute in contributing guide. 2025-08-26 17:49:06 -04:00
Jacob Walls
d454aefbd1
Refs #15727 -- Captured failed request log in CSPMiddlewareTest. 2025-08-26 17:26:01 -04:00
Jacob Walls
66082a7dac
Corrected definition of "needsinfo" triage stage in contributing guide. 2025-08-26 16:00:47 -04:00
David Smith
07f44c9e9a Fixed #36568 -- Confirmed support for GEOS 3.14. 2025-08-26 16:01:41 -03:00
antoliny0919
3e7aedfb2e Fixed #36556 -- Fixed TabularInline width overflowing the page. 2025-08-26 13:45:28 +02:00
Natalia
9efce80ca7 Refs #36485 -- Ignored line-length formatting changes in git blame. 2025-08-26 08:31:24 -03:00
David Smith
43e4d0a142 Fixed #36485 -- Added lint-docs check in Tox and GitHub Actions.
The `check` docs target now runs spelling, black, and lint, so all
current documentation quality checks can be run with a single command.

Also documented the lint-docs check's availability and usage.
2025-08-25 10:51:10 -03:00
David Smith
f81e6e3a53 Refs #36485 -- Rewrapped docs to 79 columns line length.
Lines in the docs files were manually adjusted to conform to the
79 columns limit per line (plus newline), improving readability and
consistency across the content.
2025-08-25 10:51:10 -03:00
Natalia
4286a23df6 Refs #36485 -- Removed double spaces after periods in sentences. 2025-08-25 10:51:10 -03:00
Natalia
01a460f23e Refs #36485 -- Removed trailing spaces and tabs in docs. 2025-08-25 10:51:10 -03:00
David Smith
724e5ec6f2 Refs #36485 -- Fixed dangling hyphen and unbalanced inline markup in docs. 2025-08-25 10:51:10 -03:00
David Smith
6f8e23d1c1 Refs #36485 -- Removed unnecessary parentheses in :meth: and :func: roles in docs. 2025-08-25 10:51:10 -03:00
David Smith
ef2f16bc48 Refs #36485 -- Added sphinx-lint support and make lint rule for docs.
This adds a `lint.py` script to run sphinx-lint on Django's docs files,
a mathing `lint` target in the `docs/Makefile` and `docs/make.bat`, and
updates `docs/requirements.txt` accordingly.
2025-08-25 10:51:10 -03:00
SaJH
0246f47888 Fixed #36546 -- Deprecated django.utils.crypto.constant_time_compare() in favor of hmac.compare_digest().
Signed-off-by: SaJH <wogur981208@gmail.com>
2025-08-25 14:45:16 +02:00
SaJH
3ba24c18e7 Fixed #36251 -- Avoided mutating form Meta.fields in BaseInlineFormSet.
Signed-off-by: SaJH <wogur981208@gmail.com>
2025-08-25 10:05:45 +02:00
Jacob Walls
165ad74c57
Removed reference to flake8 file exclusions.
Obsolete since 41384812ef.
(six was removed in 9285926295fbfc86b70e7be8d595d4cfbe7895b8.)
2025-08-23 20:01:00 +02:00
Simon Charette
836894f27a Refs #470 -- Adjusted Field.db_returning to be backend agnostic.
Determining if a field is db_returning based on the default connection
feature availability prevents the usage of RETURNING for db_default
fields in setups where non-default backends do support RETURNING.

Whether or not the field should be attempted to be returned is already
checked at the compiler level which is backend aware.
2025-08-23 18:09:43 +02:00
Mariusz Felisiak
b3166e1e15 Refs #35530 -- Corrected deprecation message in auth.alogin().
Follow up to ceecd518b1.
2025-08-22 16:14:09 +02:00
antoliny0919
0b2493a0da Fixed #36558, Refs #36366 -- Fixed the "show all" link hover styling in admin pagination.
Regression in 3f59711581.
2025-08-22 09:25:03 +02:00
Clifford Gama
dd15f7dabb
Clarified "inline foreign key" to avoid confusion with generated fields in django/forms/models.py. 2025-08-21 13:28:30 -03:00
Natalia
d6a8e5f5e1 Fixed failing bulk_create test raising IntegrityError when run in reverse.
When running the `bulk_create` tests with Postgres settings and
`--reverse`, the following IntegrityError was raised in
bulk_create.tests.BulkCreateTransactionTests.test_objs_with_and_without_pk:

django.db.utils.IntegrityError: duplicate key value violates unique
constraint "bulk_create_country_pkey"
DETAIL:  Key (id)=(1) already exists.

This branch fixes this by ensuring the ID is unique since DB sequences
are not resetted between tests.
2025-08-21 12:25:57 -03:00
antoliny0919
aae7836cc0 Refs #36366 -- Fixed page number layout in admin pagination on small screens.
Regression in 3f59711581.
2025-08-21 17:04:28 +02:00
SaJH
f2a6c0477f Fixed #36399 -- Added support for multiple Cookie headers in HTTP/2 for ASGIRequest.
Signed-off-by: SaJH <wogur981208@gmail.com>
2025-08-21 16:48:54 +02:00
mengxun
ed7c1a5640 Fixed #36560 -- Prevented UpdateCacheMiddleware from caching responses with Cache-Control 'no-cache' or 'no-store'. 2025-08-21 16:48:36 +02:00
Jacob Walls
d3cf24e9b4 Refs #36430, #36416, #34378 -- Simplified batch size calculation in QuerySet.in_bulk(). 2025-08-21 16:47:41 +02:00
Jacob Walls
a2ce4900a6 Fixed #36430 -- Removed artificially low limit on single field bulk operations on SQLite. 2025-08-21 16:47:41 +02:00
David Smith
fb0d463b1f Fixed #36382 -- Confirmed support for GDAL 3.11.
TIGER driver was removed in GDAL 3.11.

eb793be039
2025-08-21 16:46:41 +02:00
Mariusz Felisiak
7063d31cc3
Refs #35303 -- Made small optimizations in alogout() and aget_user().
In alogout(), there is no need to check the is_authenticated attribute
when user is None.

In aget_user(), there is no need to call get_session_auth_hash() twice.

Follow up to 50f89ae850.
2025-08-20 10:29:07 +02:00
Xinyi Rong
cd7554e551 Fixed #36561 -- Used request.auser() in contrib.auth.aupdate_session_auth_hash(). 2025-08-20 09:14:50 +02:00
Mariusz Felisiak
bcddf641ae
Corrected release notes of calling format_html() without arguments. 2025-08-20 07:33:39 +02:00
mengxun
f5c944b314
Fixed spelling of "logged-in" when used as an adjective in docs. 2025-08-19 12:43:05 -03:00
Artyom Kotovskiy
f02b49d2f3 Fixed #27489 -- Renamed permissions upon model renaming in migrations. 2025-08-19 16:36:52 +02:00
antoliny0919
4187da258f Fixed #35892 -- Supported Widget.use_fieldset in admin forms. 2025-08-19 16:35:56 +02:00
David Smith
ad4a9e0f3b
Refs #25706 -- Fixed versionadded indentation in docs/ref/contrib/gis/forms-api.txt. 2025-08-18 18:21:00 -03:00
Claude Paroz
73b904c5e0 WIP: Refs #35281 -- Unified and generalized request error handling. 2024-11-17 19:19:14 +01:00
381 changed files with 6325 additions and 4365 deletions

View File

@ -11,3 +11,4 @@ ba755ca13123d2691a0926ddb64e5d0a2906a880
1ecf6889cabc9f3f60d3fdd651468cddd8f4da6e
69a93a88edb56ba47f624dac7a21aacc47ea474f
78298b51629e14c0e472898b635bc819d47b7f27
f81e6e3a53ee36e3f730a71aa55a5744982dd016

View File

@ -58,3 +58,19 @@ jobs:
echo "💥 📢 Code blocks in documentation must be reformatted with blacken-docs 📢 💥"
fi;
exit $RESULT
lint-docs:
runs-on: ubuntu-latest
name: lint-docs
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'
- run: python -m pip install sphinx-lint
- name: Build docs
run: |
cd docs
make lint

View File

@ -14,13 +14,17 @@ permissions:
contents: read
jobs:
postgis-latest:
postgis:
if: contains(github.event.pull_request.labels.*.name, 'geodjango')
runs-on: ubuntu-latest
name: Latest PostGIS
strategy:
fail-fast: false
matrix:
postgis-version: [latest, "17-3.5-alpine", "17-master"]
name: PostGIS ${{ matrix.postgis-version }}
services:
postgres:
image: postgis/postgis:latest
image: postgis/postgis:${{ matrix.postgis-version }}
env:
POSTGRES_DB: geodjango
POSTGRES_USER: user
@ -41,8 +45,10 @@ jobs:
python-version: '3.13'
cache: 'pip'
cache-dependency-path: 'tests/requirements/py3.txt'
- name: Update apt repo
run: sudo apt update
- name: Install libmemcached-dev for pylibmc
run: sudo apt install libmemcached-dev
run: sudo apt install -y libmemcached-dev
- name: Install geospatial dependencies
run: sudo apt install -y binutils libproj-dev gdal-bin
- name: Print PostGIS versions

View File

@ -1,9 +1,3 @@
from django.urls import include
from django.views import defaults
__all__ = ["handler400", "handler403", "handler404", "handler500", "include"]
handler400 = defaults.bad_request
handler403 = defaults.permission_denied
handler404 = defaults.page_not_found
handler500 = defaults.server_error
__all__ = ["include"]

View File

@ -173,6 +173,7 @@ class AdminField:
self.is_first = is_first # Whether this field is first on the line
self.is_checkbox = isinstance(self.field.field.widget, forms.CheckboxInput)
self.is_readonly = False
self.is_fieldset = self.field.field.widget.use_fieldset
def label_tag(self):
classes = []
@ -185,12 +186,14 @@ class AdminField:
if not self.is_first:
classes.append("inline")
attrs = {"class": " ".join(classes)} if classes else {}
tag = "legend" if self.is_fieldset else None
# checkboxes should not have a label suffix as the checkbox appears
# to the left of the label.
return self.field.label_tag(
contents=mark_safe(contents),
attrs=attrs,
label_suffix="" if self.is_checkbox else None,
tag=tag,
)
def errors(self):

View File

@ -1161,7 +1161,6 @@ a.deletelink:focus, a.deletelink:hover {
line-height: 22px;
margin: 0;
border-top: 1px solid var(--hairline-color);
width: 100%;
box-sizing: border-box;
}
@ -1176,25 +1175,17 @@ a.deletelink:focus, a.deletelink:hover {
padding: 0;
}
.paginator a:link, .paginator a:visited {
.paginator a {
display: inline-block;
padding: 2px 6px;
}
.paginator a:not(.showall) {
background: var(--button-bg);
text-decoration: none;
color: var(--button-fg);
}
.paginator a.showall {
border: none;
background: none;
color: var(--link-fg);
}
.paginator a.showall:focus, .paginator a.showall:hover {
background: none;
color: var(--link-hover-color);
}
.paginator a[aria-current="page"] {
color: var(--body-quiet-color);
background: transparent;
@ -1202,8 +1193,8 @@ a.deletelink:focus, a.deletelink:hover {
cursor: default;
}
.paginator a:not([aria-current="page"]):focus,
.paginator a:not([aria-current="page"]):hover {
.paginator a:not([aria-current="page"], .showall):focus,
.paginator a:not([aria-current="page"], .showall):hover {
color: white;
background: var(--link-hover-color);
}

View File

@ -54,6 +54,7 @@
#changelist .changelist-footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
border-top: 1px solid var(--hairline-color);
border-bottom: 1px solid var(--hairline-color);
@ -64,18 +65,17 @@
background: var(--body-bg);
border: none;
padding: 0;
overflow: hidden;
}
#changelist .paginator {
color: var(--body-quiet-color);
border-bottom: 1px solid var(--hairline-color);
background: var(--body-bg);
overflow: hidden;
}
#changelist .paginator ul {
padding: 0;
white-space: nowrap;
}
/* CHANGELIST TABLES */

View File

@ -36,12 +36,13 @@ form .form-row p {
/* FORM LABELS */
label {
legend, label {
font-weight: normal;
color: var(--body-quiet-color);
font-size: 0.8125rem;
}
.required legend, legend.required,
.required label, label.required {
font-weight: bold;
}
@ -91,6 +92,20 @@ fieldset .inline-heading,
/* ALIGNED FIELDSETS */
.aligned fieldset {
width: 100%;
border-top: none;
}
.aligned fieldset > div {
width: 100%;
}
.aligned legend {
float: left;
}
.aligned legend,
.aligned label {
display: block;
padding: 4px 10px 0 0;
@ -138,6 +153,10 @@ form .aligned div.radiolist {
padding: 0;
}
form .aligned fieldset div.help {
margin-left: 0;
}
form .aligned p.help,
form .aligned div.help {
margin-top: 0;
@ -413,9 +432,12 @@ body.popup .submit-row {
border: none;
}
.inline-related.tabular div.wrapper {
overflow-x: auto;
}
.inline-related.tabular fieldset.module table {
width: 100%;
overflow-x: scroll;
}
.last-related fieldset {

View File

@ -170,6 +170,7 @@ input[type="submit"], button {
/* Forms */
legend,
label {
font-size: 1rem;
}
@ -484,6 +485,7 @@ input[type="submit"], button {
padding-top: 15px;
}
.aligned legend,
.aligned label {
width: 100%;
min-width: auto;

View File

@ -301,6 +301,10 @@ p.datetime {
font-weight: bold;
}
p.datetime label {
display: inline;
}
.datetime span {
white-space: nowrap;
font-weight: normal;

View File

@ -15,7 +15,8 @@ Requires core.js and SelectBox.js.
const from_box = document.getElementById(field_id);
from_box.id += '_from'; // change its ID
from_box.className = 'filtered';
from_box.setAttribute('aria-labelledby', field_id + '_from_title');
from_box.setAttribute('aria-labelledby', field_id + '_from_label');
from_box.setAttribute('aria-describedby', `${field_id}_helptext ${field_id}_choose_helptext`);
for (const p of from_box.parentNode.getElementsByTagName('p')) {
if (p.classList.contains("info")) {
@ -42,12 +43,20 @@ Requires core.js and SelectBox.js.
const selector_available_title = quickElement('div', selector_available);
selector_available_title.id = field_id + '_from_title';
selector_available_title.className = 'selector-available-title';
quickElement('label', selector_available_title, interpolate(gettext('Available %s') + ' ', [field_name]), 'for', field_id + '_from');
quickElement(
'label',
selector_available_title,
interpolate(gettext('Available %s') + ' ', [field_name]),
'id',
field_id + '_from_label',
'for',
field_id + '_from'
);
quickElement(
'p',
selector_available_title,
interpolate(gettext('Choose %s by selecting them and then select the "Choose" arrow button.'), [field_name]),
'class', 'helptext'
'id', `${field_id}_choose_helptext`, 'class', 'helptext'
);
const filter_p = quickElement('p', selector_available, '', 'id', field_id + '_filter');
@ -102,12 +111,20 @@ Requires core.js and SelectBox.js.
const selector_chosen_title = quickElement('div', selector_chosen);
selector_chosen_title.className = 'selector-chosen-title';
selector_chosen_title.id = field_id + '_to_title';
quickElement('label', selector_chosen_title, interpolate(gettext('Chosen %s') + ' ', [field_name]), 'for', field_id + '_to');
quickElement(
'label',
selector_chosen_title,
interpolate(gettext('Chosen %s') + ' ', [field_name]),
'id',
field_id + '_to_label',
'for',
field_id + '_to'
);
quickElement(
'p',
selector_chosen_title,
interpolate(gettext('Remove %s by selecting them and then select the "Remove" arrow button.'), [field_name]),
'class', 'helptext'
'id', `${field_id}_remove_helptext`, 'class', 'helptext'
);
const filter_selected_p = quickElement('p', selector_chosen, '', 'id', field_id + '_filter_selected');
@ -134,7 +151,8 @@ Requires core.js and SelectBox.js.
'multiple', '',
'size', from_box.size,
'name', from_box.name,
'aria-labelledby', field_id + '_to_title',
'aria-labelledby', field_id + '_to_label',
'aria-describedby', `${field_id}_helptext ${field_id}_remove_helptext`,
'class', 'filtered'
);
const warning_footer = quickElement('div', selector_chosen, '', 'class', 'list-footer-display');

View File

@ -91,7 +91,10 @@
message = interpolate(message, [timezoneOffset]);
const warning = document.createElement('div');
const id = inp.id;
const field_id = inp.closest('p.datetime') ? id.slice(0, id.lastIndexOf("_")) : id;
warning.classList.add('help', warningClass);
warning.id = `${field_id}_timezone_warning_helptext`;
warning.textContent = message;
inp.parentNode.appendChild(warning);
},

View File

@ -40,7 +40,7 @@
<div class="form-row">
{{ form.usable_password.errors }}
<div class="flex-container">{{ form.usable_password.label_tag }} {{ form.usable_password }}</div>
<fieldset class="flex-container">{{ form.usable_password.legend_tag }} {{ form.usable_password }}</fieldset>
{% if form.usable_password.help_text %}
<div class="help"{% if form.usable_password.id_for_label %} id="{{ form.usable_password.id_for_label }}_helptext"{% endif %}>
<p>{{ form.usable_password.help_text|safe }}</p>

View File

@ -15,7 +15,8 @@
</h2>
{% if inline_admin_formset.is_collapsible %}</summary>{% endif %}
{{ inline_admin_formset.formset.non_form_errors }}
<table>
<div class="wrapper">
<table>
<thead><tr>
<th class="original"></th>
{% for field in inline_admin_formset.fields %}
@ -62,7 +63,8 @@
</tr>
{% endfor %}
</tbody>
</table>
</table>
</div>
{% if inline_admin_formset.is_collapsible %}</details>{% endif %}
</fieldset>
</div>

View File

@ -11,13 +11,14 @@
<div class="form-row{% if line.fields|length == 1 and line.errors %} errors{% endif %}{% if not line.has_visible_field %} hidden{% endif %}{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}">
{% if line.fields|length == 1 %}{{ line.errors }}{% else %}<div class="flex-container form-multiline">{% endif %}
{% for field in line %}
{% if field.is_fieldset %}<fieldset class="flex-container"{% if field.field.help_text %} aria-describedby="{{ field.field.id_for_label }}_helptext"{% endif %}>{{ field.label_tag }}{% endif %}
<div>
{% if not line.fields|length == 1 and not field.is_readonly %}{{ field.errors }}{% endif %}
<div class="flex-container{% if not line.fields|length == 1 %} fieldBox{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% if not field.is_readonly and field.errors %} errors{% endif %}{% if field.field.is_hidden %} hidden{% endif %}{% endif %}{% if field.is_checkbox %} checkbox-row{% endif %}">
{% if field.is_checkbox %}
{{ field.field }}{{ field.label_tag }}
{{ field.field }}{% if not field.is_fieldset %}{{ field.label_tag }}{% endif %}
{% else %}
{{ field.label_tag }}
{% if not field.is_fieldset %}{{ field.label_tag }}{% endif %}
{% if field.is_readonly %}
<div class="readonly">{{ field.contents }}</div>
{% else %}
@ -31,6 +32,7 @@
</div>
{% endif %}
</div>
{% if field.is_fieldset %}</fieldset>{% endif %}
{% endfor %}
{% if not line.fields|length == 1 %}</div>{% endif %}
</div>

View File

@ -1,4 +1,4 @@
<p class="datetime">
{{ date_label }} {% with widget=widget.subwidgets.0 %}{% include widget.template_name %}{% endwith %}<br>
{{ time_label }} {% with widget=widget.subwidgets.1 %}{% include widget.template_name %}{% endwith %}
<label {% if widget.attrs.id %}for="{{ widget.subwidgets.0.attrs.id }}"{% endif %}>{{ date_label }}</label> {% with widget=widget.subwidgets.0 %}{% include widget.template_name %}{% endwith %}<br>
<label {% if widget.attrs.id %}for="{{ widget.subwidgets.1.attrs.id }}"{% endif %}>{{ time_label }}</label> {% with widget=widget.subwidgets.1 %}{% include widget.template_name %}{% endwith %}
</p>

View File

@ -10,6 +10,7 @@ from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import URLValidator
from django.db.models import CASCADE, UUIDField
from django.forms.widgets import Select
from django.urls import reverse
from django.urls.exceptions import NoReverseMatch
from django.utils.html import smart_urlquote
@ -49,7 +50,16 @@ class FilteredSelectMultiple(forms.SelectMultiple):
return context
class BaseAdminDateWidget(forms.DateInput):
class DateTimeWidgetContextMixin:
def get_context(self, name, value, attrs):
context = super().get_context(name, value, attrs)
context["widget"]["attrs"][
"aria-describedby"
] = f"id_{name}_timezone_warning_helptext"
return context
class BaseAdminDateWidget(DateTimeWidgetContextMixin, forms.DateInput):
class Media:
js = [
"admin/js/calendar.js",
@ -65,7 +75,7 @@ class AdminDateWidget(BaseAdminDateWidget):
template_name = "admin/widgets/date.html"
class BaseAdminTimeWidget(forms.TimeInput):
class BaseAdminTimeWidget(DateTimeWidgetContextMixin, forms.TimeInput):
class Media:
js = [
"admin/js/calendar.js",
@ -98,8 +108,13 @@ class AdminSplitDateTime(forms.SplitDateTimeWidget):
context = super().get_context(name, value, attrs)
context["date_label"] = _("Date:")
context["time_label"] = _("Time:")
for widget in context["widget"]["subwidgets"]:
widget["attrs"]["aria-describedby"] = f"id_{name}_timezone_warning_helptext"
return context
def id_for_label(self, id_):
return id_
class AdminRadioSelect(forms.RadioSelect):
template_name = "admin/widgets/radio.html"
@ -270,18 +285,21 @@ class RelatedFieldWidgetWrapper(forms.Widget):
if can_add_related is None:
can_add_related = admin_site.is_registered(rel.model)
self.can_add_related = can_add_related
# XXX: The UX does not support multiple selected values.
multiple = getattr(widget, "allow_multiple_selected", False)
if not isinstance(widget, AutocompleteMixin):
self.attrs["data-context"] = "available-source"
self.can_change_related = not multiple and can_change_related
# Only single-select Select widgets are supported.
supported = not getattr(
widget, "allow_multiple_selected", False
) and isinstance(widget, Select)
self.can_change_related = supported and can_change_related
# XXX: The deletion UX can be confusing when dealing with cascading
# deletion.
cascade = getattr(rel, "on_delete", None) is CASCADE
self.can_delete_related = not multiple and not cascade and can_delete_related
self.can_view_related = not multiple and can_view_related
self.can_delete_related = supported and not cascade and can_delete_related
self.can_view_related = supported and can_view_related
# To check if the related object is registered with this AdminSite.
self.admin_site = admin_site
self.use_fieldset = True
def __deepcopy__(self, memo):
obj = copy.copy(self)

View File

@ -205,7 +205,7 @@ async def alogin(request, user, backend=None):
# RemovedInDjango61Warning.
if user is None:
warnings.warn(
"Fallback to request.user when user is None will be removed.",
"Fallback to request.auser() when user is None will be removed.",
RemovedInDjango61Warning,
stacklevel=2,
)
@ -269,8 +269,8 @@ async def alogout(request):
user = getattr(request, "auser", None)
if user is not None:
user = await user()
if not getattr(user, "is_authenticated", True):
user = None
if not getattr(user, "is_authenticated", True):
user = None
await user_logged_out.asend(sender=user.__class__, request=request, user=user)
await request.session.aflush()
if hasattr(request, "auser"):
@ -364,8 +364,8 @@ async def aget_user(request):
session_hash_verified = False
else:
session_auth_hash = user.get_session_auth_hash()
session_hash_verified = session_hash and constant_time_compare(
session_hash, user.get_session_auth_hash()
session_hash_verified = constant_time_compare(
session_hash, session_auth_hash
)
if not session_hash_verified:
# If the current secret does not verify the session, try
@ -408,5 +408,5 @@ def update_session_auth_hash(request, user):
async def aupdate_session_auth_hash(request, user):
"""See update_session_auth_hash()."""
await request.session.acycle_key()
if hasattr(user, "get_session_auth_hash") and request.user == user:
if hasattr(user, "get_session_auth_hash") and await request.auser() == user:
await request.session.aset(HASH_SESSION_KEY, user.get_session_auth_hash())

View File

@ -1,12 +1,12 @@
from django.apps import AppConfig
from django.core import checks
from django.db.models.query_utils import DeferredAttribute
from django.db.models.signals import post_migrate
from django.db.models.signals import post_migrate, pre_migrate
from django.utils.translation import gettext_lazy as _
from . import get_user_model
from .checks import check_middleware, check_models_permissions, check_user_model
from .management import create_permissions
from .management import create_permissions, rename_permissions
from .signals import user_logged_in
@ -20,6 +20,11 @@ class AuthConfig(AppConfig):
create_permissions,
dispatch_uid="django.contrib.auth.management.create_permissions",
)
pre_migrate.connect(
rename_permissions,
dispatch_uid="django.contrib.auth.management.rename_permissions",
)
last_login_field = getattr(get_user_model(), "last_login", None)
# Register the handler only if UserModel.last_login is a field.
if isinstance(last_login_field, DeferredAttribute):

View File

@ -9,7 +9,9 @@ from django.apps import apps as global_apps
from django.contrib.auth import get_permission_codename
from django.contrib.contenttypes.management import create_contenttypes
from django.core import exceptions
from django.db import DEFAULT_DB_ALIAS, router
from django.db import DEFAULT_DB_ALIAS, migrations, router, transaction
from django.db.utils import IntegrityError
from django.utils.text import camel_case_to_spaces
def _get_all_permissions(opts):
@ -108,6 +110,84 @@ def create_permissions(
print("Adding permission '%s'" % perm)
class RenamePermission(migrations.RunPython):
def __init__(self, app_label, old_model, new_model):
self.app_label = app_label
self.old_model = old_model
self.new_model = new_model
super(RenamePermission, self).__init__(
self.rename_forward, self.rename_backward
)
def _rename(self, apps, schema_editor, old_model, new_model):
ContentType = apps.get_model("contenttypes", "ContentType")
# Use the live Permission model instead of the frozen one, since frozen
# models do not retain foreign key constraints.
from django.contrib.auth.models import Permission
db = schema_editor.connection.alias
ctypes = ContentType.objects.filter(
app_label=self.app_label, model__icontains=old_model.lower()
)
for permission in Permission.objects.filter(
content_type_id__in=ctypes.values("id")
):
prefix = permission.codename.split("_")[0]
default_verbose_name = camel_case_to_spaces(new_model)
new_codename = f"{prefix}_{new_model.lower()}"
new_name = f"Can {prefix} {default_verbose_name}"
if permission.codename != new_codename or permission.name != new_name:
permission.codename = new_codename
permission.name = new_name
try:
with transaction.atomic(using=db):
permission.save(update_fields={"name", "codename"})
except IntegrityError:
pass
def rename_forward(self, apps, schema_editor):
self._rename(apps, schema_editor, self.old_model, self.new_model)
def rename_backward(self, apps, schema_editor):
self._rename(apps, schema_editor, self.new_model, self.old_model)
def rename_permissions(
plan,
verbosity=2,
interactive=True,
using=DEFAULT_DB_ALIAS,
apps=global_apps,
**kwargs,
):
"""
Insert a `RenamePermissionType` operation after every planned `RenameModel`
operation.
"""
try:
Permission = apps.get_model("auth", "Permission")
except LookupError:
return
else:
if not router.allow_migrate_model(using, Permission):
return
for migration, backward in plan:
inserts = []
for index, operation in enumerate(migration.operations):
if isinstance(operation, migrations.RenameModel):
operation = RenamePermission(
migration.app_label,
operation.old_name,
operation.new_name,
)
inserts.append((index + 1, operation))
for inserted, (index, operation) in enumerate(inserts):
migration.operations.insert(inserted + index, operation)
def get_system_username():
"""
Return the current system user's username, or an empty string if the

View File

@ -4,8 +4,7 @@ an interface for reading vector geometry data from many different file
formats (including ESRI shapefiles).
When instantiating a DataSource object, use the filename of a
GDAL-supported data source. For example, an SHP file or a
TIGER/Line file from the government.
GDAL-supported data source. For example, an SHP file.
The ds_driver keyword is used internally when a ctypes pointer
is passed in directly.

View File

@ -2,6 +2,7 @@ from ctypes import c_void_p
from django.contrib.gis.gdal.base import GDALBase
from django.contrib.gis.gdal.error import GDALException
from django.contrib.gis.gdal.libgdal import GDAL_VERSION
from django.contrib.gis.gdal.prototypes import ds as capi
from django.utils.encoding import force_bytes, force_str
@ -23,8 +24,6 @@ class Driver(GDALBase):
"esri": "ESRI Shapefile",
"shp": "ESRI Shapefile",
"shape": "ESRI Shapefile",
"tiger": "TIGER",
"tiger/line": "TIGER",
# raster
"tiff": "GTiff",
"tif": "GTiff",
@ -32,6 +31,14 @@ class Driver(GDALBase):
"jpg": "JPEG",
}
if GDAL_VERSION[:2] <= (3, 10):
_alias.update(
{
"tiger": "TIGER",
"tiger/line": "TIGER",
}
)
def __init__(self, dr_input):
"""
Initialize an GDAL/OGR driver on either a string or integer input.

View File

@ -22,6 +22,7 @@ if lib_path:
elif os.name == "nt":
# Windows NT shared libraries
lib_names = [
"gdal311",
"gdal310",
"gdal309",
"gdal308",
@ -38,6 +39,7 @@ elif os.name == "posix":
lib_names = [
"gdal",
"GDAL",
"gdal3.11.0",
"gdal3.10.0",
"gdal3.9.0",
"gdal3.8.0",

View File

@ -2,24 +2,16 @@
This module contains useful utilities for GeoDjango.
"""
from django.contrib.gis.utils.layermapping import LayerMapError, LayerMapping
from django.contrib.gis.utils.ogrinfo import ogrinfo
from django.contrib.gis.utils.ogrinspect import mapping, ogrinspect
from django.contrib.gis.utils.srs import add_srs_entry
from django.core.exceptions import ImproperlyConfigured
__all__ = [
"add_srs_entry",
"mapping",
"ogrinfo",
"ogrinspect",
"LayerMapError",
"LayerMapping",
]
try:
# LayerMapping requires DJANGO_SETTINGS_MODULE to be set,
# and ImproperlyConfigured is raised if that's not the case.
from django.contrib.gis.utils.layermapping import LayerMapError, LayerMapping
__all__ += ["LayerMapError", "LayerMapping"]
except ImproperlyConfigured:
pass

View File

@ -7,4 +7,3 @@ class RedirectAdmin(admin.ModelAdmin):
list_display = ("old_path", "new_path")
list_filter = ("site",)
search_fields = ("old_path", "new_path")
radio_fields = {"site": admin.VERTICAL}

View File

@ -131,7 +131,7 @@ def check_custom_error_handlers(app_configs, **kwargs):
errors = []
# All handlers take (request, exception) arguments except handler500
# which takes (request).
for status_code, num_parameters in [(400, 2), (403, 2), (404, 2), (500, 1)]:
for status_code, num_parameters in [(400, 2), (403, 2), (404, 2), (500, 2)]:
try:
handler = resolver.resolve_error_handler(status_code)
except (ImportError, ViewDoesNotExist) as e:

View File

@ -94,7 +94,11 @@ class ASGIRequest(HttpRequest):
# HTTP/2 say only ASCII chars are allowed in headers, but decode
# latin1 just in case.
value = value.decode("latin1")
if corrected_name in self.META:
if corrected_name == "HTTP_COOKIE":
value = value.rstrip("; ")
if "HTTP_COOKIE" in self.META:
value = self.META[corrected_name] + "; " + value
elif corrected_name in self.META:
value = self.META[corrected_name] + "," + value
self.META[corrected_name] = value
# Pull out request encoding, if provided.

View File

@ -208,13 +208,6 @@ class BaseDatabaseOperations:
else:
return ["DISTINCT"], []
def fetch_returned_insert_columns(self, cursor, returning_params):
"""
Given a cursor object that has just performed an INSERT...RETURNING
statement into a table, return the newly created data.
"""
return cursor.fetchone()
def force_group_by(self):
"""
Return a GROUP BY clause to use with a HAVING clause when no grouping
@ -358,13 +351,31 @@ class BaseDatabaseOperations:
"""
return value
def return_insert_columns(self, fields):
def returning_columns(self, fields):
"""
For backends that support returning columns as part of an insert query,
return the SQL and params to append to the INSERT query. The returned
fragment should contain a format string to hold the appropriate column.
For backends that support returning columns as part of an insert or
update query, return the SQL and params to append to the query.
The returned fragment should contain a format string to hold the
appropriate column.
"""
pass
if not fields:
return "", ()
columns = [
"%s.%s"
% (
self.quote_name(field.model._meta.db_table),
self.quote_name(field.column),
)
for field in fields
]
return "RETURNING %s" % ", ".join(columns), ()
def fetch_returned_rows(self, cursor, returning_params):
"""
Given a cursor object for a DML query with a RETURNING statement,
return the selected returning rows of tuples.
"""
return cursor.fetchall()
def compiler(self, compiler_name):
"""

View File

@ -148,13 +148,6 @@ class DatabaseOperations(BaseDatabaseOperations):
else:
return f"TIME({sql})", params
def fetch_returned_insert_rows(self, cursor):
"""
Given a cursor object that has just performed an INSERT...RETURNING
statement into a table, return the tuple of returned data.
"""
return cursor.fetchall()
def format_for_duration_arithmetic(self, sql):
return "INTERVAL %s MICROSECOND" % sql
@ -182,20 +175,6 @@ class DatabaseOperations(BaseDatabaseOperations):
return name # Quoting once is enough.
return "`%s`" % name
def return_insert_columns(self, fields):
# MySQL doesn't support an INSERT...RETURNING statement.
if not fields:
return "", ()
columns = [
"%s.%s"
% (
self.quote_name(field.model._meta.db_table),
self.quote_name(field.column),
)
for field in fields
]
return "RETURNING %s" % ", ".join(columns), ()
def sql_flush(self, style, tables, *, reset_sequences=False, allow_cascade=False):
if not tables:
return []

View File

@ -22,7 +22,7 @@ from django.utils.functional import cached_property
from django.utils.regex_helper import _lazy_re_compile
from .base import Database
from .utils import BulkInsertMapper, InsertVar, Oracle_datetime
from .utils import BoundVar, BulkInsertMapper, Oracle_datetime
class DatabaseOperations(BaseDatabaseOperations):
@ -298,12 +298,27 @@ END;
def deferrable_sql(self):
return " DEFERRABLE INITIALLY DEFERRED"
def fetch_returned_insert_columns(self, cursor, returning_params):
columns = []
for param in returning_params:
value = param.get_value()
columns.append(value[0])
return tuple(columns)
def returning_columns(self, fields):
if not fields:
return "", ()
field_names = []
params = []
for field in fields:
field_names.append(
"%s.%s"
% (
self.quote_name(field.model._meta.db_table),
self.quote_name(field.column),
)
)
params.append(BoundVar(field))
return "RETURNING %s INTO %s" % (
", ".join(field_names),
", ".join(["%s"] * len(params)),
), tuple(params)
def fetch_returned_rows(self, cursor, returning_params):
return list(zip(*(param.get_value() for param in returning_params)))
def no_limit_value(self):
return None
@ -391,25 +406,6 @@ END;
match_option = "'i'"
return "REGEXP_LIKE(%%s, %%s, %s)" % match_option
def return_insert_columns(self, fields):
if not fields:
return "", ()
field_names = []
params = []
for field in fields:
field_names.append(
"%s.%s"
% (
self.quote_name(field.model._meta.db_table),
self.quote_name(field.column),
)
)
params.append(InsertVar(field))
return "RETURNING %s INTO %s" % (
", ".join(field_names),
", ".join(["%s"] * len(params)),
), tuple(params)
def __foreign_key_constraints(self, table_name, recursive):
with self.connection.cursor() as cursor:
if recursive:

View File

@ -4,7 +4,7 @@ import decimal
from .base import Database
class InsertVar:
class BoundVar:
"""
A late-binding cursor variable that can be passed to Cursor.execute
as a parameter, in order to receive the id of the row created by an

View File

@ -155,13 +155,6 @@ class DatabaseOperations(BaseDatabaseOperations):
return f"SELECT * FROM {placeholder_rows}"
return super().bulk_insert_sql(fields, placeholder_rows)
def fetch_returned_insert_rows(self, cursor):
"""
Given a cursor object that has just performed an INSERT...RETURNING
statement into a table, return the tuple of returned data.
"""
return cursor.fetchall()
def lookup_cast(self, lookup_type, internal_type=None):
lookup = "%s"
# Cast text lookups to text to allow things like filter(x__contains=4)
@ -324,19 +317,6 @@ class DatabaseOperations(BaseDatabaseOperations):
return cursor.query.decode()
return None
def return_insert_columns(self, fields):
if not fields:
return "", ()
columns = [
"%s.%s"
% (
self.quote_name(field.model._meta.db_table),
self.quote_name(field.column),
)
for field in fields
]
return "RETURNING %s" % ", ".join(columns), ()
if is_psycopg3:
def adapt_integerfield_value(self, value, internal_type):

View File

@ -32,9 +32,6 @@ class DatabaseOperations(BaseDatabaseOperations):
"""
SQLite has a variable limit defined by SQLITE_LIMIT_VARIABLE_NUMBER
(reflected in max_query_params).
If there's only a single field to insert, the limit is 500
(SQLITE_MAX_COMPOUND_SELECT).
"""
fields = list(
chain.from_iterable(
@ -46,9 +43,7 @@ class DatabaseOperations(BaseDatabaseOperations):
for field in fields
)
)
if len(fields) == 1:
return 500
elif len(fields) > 1:
if fields:
return self.connection.features.max_query_params // len(fields)
else:
return len(objs)
@ -89,13 +84,6 @@ class DatabaseOperations(BaseDatabaseOperations):
"""
return f"django_date_extract(%s, {sql})", (lookup_type.lower(), *params)
def fetch_returned_insert_rows(self, cursor):
"""
Given a cursor object that has just performed an INSERT...RETURNING
statement into a table, return the list of returned data.
"""
return cursor.fetchall()
def format_for_duration_arithmetic(self, sql):
"""Do nothing since formatting is handled in the custom function."""
return sql
@ -404,20 +392,6 @@ class DatabaseOperations(BaseDatabaseOperations):
return "INSERT OR IGNORE INTO"
return super().insert_statement(on_conflict=on_conflict)
def return_insert_columns(self, fields):
# SQLite < 3.35 doesn't support an INSERT...RETURNING statement.
if not fields:
return "", ()
columns = [
"%s.%s"
% (
self.quote_name(field.model._meta.db_table),
self.quote_name(field.column),
)
for field in fields
]
return "RETURNING %s" % ", ".join(columns), ()
def on_conflict_suffix_sql(self, fields, on_conflict, update_fields, unique_fields):
if (
on_conflict == OnConflict.UPDATE

View File

@ -932,9 +932,7 @@ class Field(RegisterLookupMixin):
@property
def db_returning(self):
"""Private API intended only to be used by Django itself."""
return (
self.has_db_default() and connection.features.can_return_columns_from_insert
)
return self.has_db_default()
def set_attributes_from_name(self, name):
self.name = self.name or name

View File

@ -35,6 +35,7 @@ from django.db.models.utils import (
resolve_callables,
)
from django.utils import timezone
from django.utils.deprecation import RemovedInDjango70Warning
from django.utils.functional import cached_property
# The maximum number of results to fetch in a get() query.
@ -1187,10 +1188,8 @@ class QuerySet(AltersData):
if not id_list:
return {}
filter_key = "{}__in".format(field_name)
max_params = connections[self.db].features.max_query_params or 0
num_fields = len(opts.pk_fields) if field_name == "pk" else 1
batch_size = max_params // num_fields
id_list = tuple(id_list)
batch_size = connections[self.db].ops.bulk_batch_size([opts.pk], id_list)
# If the database has a limit on the number of query parameters
# (e.g. SQLite), retrieve objects in batches if necessary.
if batch_size and batch_size < len(id_list):
@ -1396,7 +1395,12 @@ class QuerySet(AltersData):
def _values(self, *fields, **expressions):
clone = self._chain()
if expressions:
clone = clone.annotate(**expressions)
# RemovedInDjango70Warning: When the deprecation ends, deindent as:
# clone = clone.annotate(**expressions)
with warnings.catch_warnings(
action="ignore", category=RemovedInDjango70Warning
):
clone = clone.annotate(**expressions)
clone._fields = fields
clone.query.set_values(fields)
return clone

View File

@ -1890,7 +1890,7 @@ class SQLInsertCompiler(SQLCompiler):
result.append(on_conflict_suffix_sql)
# Skip empty r_sql to allow subclasses to customize behavior for
# 3rd party backends. Refs #19096.
r_sql, self.returning_params = self.connection.ops.return_insert_columns(
r_sql, self.returning_params = self.connection.ops.returning_columns(
self.returning_fields
)
if r_sql:
@ -1925,20 +1925,16 @@ class SQLInsertCompiler(SQLCompiler):
cursor.execute(sql, params)
if not self.returning_fields:
return []
obj_len = len(self.query.objs)
if (
self.connection.features.can_return_rows_from_bulk_insert
and len(self.query.objs) > 1
and obj_len > 1
) or (
self.connection.features.can_return_columns_from_insert and obj_len == 1
):
rows = self.connection.ops.fetch_returned_insert_rows(cursor)
cols = [field.get_col(opts.db_table) for field in self.returning_fields]
elif self.connection.features.can_return_columns_from_insert:
assert len(self.query.objs) == 1
rows = [
self.connection.ops.fetch_returned_insert_columns(
cursor,
self.returning_params,
)
]
rows = self.connection.ops.fetch_returned_rows(
cursor, self.returning_params
)
cols = [field.get_col(opts.db_table) for field in self.returning_fields]
elif returning_fields and isinstance(
returning_field := returning_fields[0], AutoField

View File

@ -1219,7 +1219,7 @@ class Query(BaseExpression):
if "aggregate" in {frame.function for frame in inspect.stack()}:
stacklevel = 5
else:
# annotate() and alias().
# annotate(), alias(), and values().
stacklevel = 6
warnings.warn(
"Using percent signs in a column alias is deprecated.",
@ -2269,8 +2269,21 @@ class Query(BaseExpression):
join_info.joins,
join_info.path,
)
for target in targets:
cols.append(join_info.transform_function(target, final_alias))
if len(targets) > 1:
transformed_targets = [
join_info.transform_function(target, final_alias)
for target in targets
]
cols.append(
ColPairs(
final_alias if self.alias_cols else None,
[col.target for col in transformed_targets],
[col.output_field for col in transformed_targets],
join_info.final_field,
)
)
else:
cols.append(join_info.transform_function(targets[0], final_alias))
if cols:
self.set_select(cols)
except MultiJoin:

View File

@ -1134,11 +1134,10 @@ class BaseInlineFormSet(BaseModelFormSet):
self.unique_fields = {self.fk.name}
super().__init__(data, files, prefix=prefix, queryset=qs, **kwargs)
# Add the generated field to form._meta.fields if it's defined to make
# sure validation isn't skipped on that field.
# Add the inline foreign key field to form._meta.fields if it's defined
# to make sure validation isn't skipped on that field.
if self.form._meta.fields and self.fk.name not in self.form._meta.fields:
if isinstance(self.form._meta.fields, tuple):
self.form._meta.fields = list(self.form._meta.fields)
self.form._meta.fields = list(self.form._meta.fields)
self.form._meta.fields.append(self.fk.name)
def initial_form_count(self):

View File

@ -530,6 +530,7 @@ class ClearableFileInput(FileInput):
input_text = _("Change")
template_name = "django/forms/widgets/clearable_file_input.html"
checked = False
use_fieldset = True
def clear_checkbox_name(self, name):
"""

View File

@ -721,11 +721,10 @@ def parse_boundary_stream(stream, max_header_size):
# Eliminate blank lines
for line in header.split(b"\r\n"):
# This terminology ("main value" and "dictionary of
# parameters") is from the Python docs.
try:
main_value_pair, params = parse_header_parameters(line.decode())
name, value = main_value_pair.split(":", 1)
header_name, value_and_params = line.decode().split(":", 1)
name = header_name.lower().rstrip(" ")
value, params = parse_header_parameters(value_and_params.lstrip(" "))
params = {k: v.encode() for k, v in params.items()}
except ValueError: # Invalid header.
continue

View File

@ -211,6 +211,23 @@ class HttpResponseBase:
def get(self, header, alternate=None):
return self.headers.get(header, alternate)
@classmethod
def response_class_by_status_code(cls, status_code):
return {
200: HttpResponse,
301: HttpResponsePermanentRedirect,
302: HttpResponseRedirect,
304: HttpResponseNotModified,
307: HttpResponseRedirect,
308: HttpResponsePermanentRedirect,
400: HttpResponseBadRequest,
403: HttpResponseForbidden,
404: HttpResponseNotFound,
405: HttpResponseNotAllowed,
410: HttpResponseGone,
500: HttpResponseServerError,
}.get(status_code, cls)
def set_cookie(
self,
key,

View File

@ -100,8 +100,17 @@ class UpdateCacheMiddleware(MiddlewareMixin):
):
return response
# Don't cache a response with 'Cache-Control: private'
if "private" in response.get("Cache-Control", ()):
# Don't cache responses when the Cache-Control header is set to
# private, no-cache, or no-store.
cache_control = response.get("Cache-Control", ())
if any(
directive in cache_control
for directive in (
"private",
"no-cache",
"no-store",
)
):
return response
# Page timeout takes precedence over the "max-age" and the default

View File

@ -1,5 +1,3 @@
from http import HTTPStatus
from django.conf import settings
from django.utils.csp import CSP, LazyNonce, build_policy
from django.utils.deprecation import MiddlewareMixin
@ -14,22 +12,21 @@ class ContentSecurityPolicyMiddleware(MiddlewareMixin):
request._csp_nonce = LazyNonce()
def process_response(self, request, response):
# In DEBUG mode, exclude CSP headers for specific status codes that
# trigger the debug view.
exempted_status_codes = {
HTTPStatus.NOT_FOUND,
HTTPStatus.INTERNAL_SERVER_ERROR,
}
if settings.DEBUG and response.status_code in exempted_status_codes:
return response
nonce = get_nonce(request)
sentinel = object()
if (csp_config := getattr(response, "_csp_config", sentinel)) is sentinel:
csp_config = settings.SECURE_CSP
if (csp_ro_config := getattr(response, "_csp_ro_config", sentinel)) is sentinel:
csp_ro_config = settings.SECURE_CSP_REPORT_ONLY
for header, config in [
(CSP.HEADER_ENFORCE, settings.SECURE_CSP),
(CSP.HEADER_REPORT_ONLY, settings.SECURE_CSP_REPORT_ONLY),
(CSP.HEADER_ENFORCE, csp_config),
(CSP.HEADER_REPORT_ONLY, csp_ro_config),
]:
# If headers are already set on the response, don't overwrite them.
# This allows for views to set their own CSP headers as needed.
# An empty config means CSP headers are not added to the response.
if config and header not in response:
response.headers[str(header)] = build_policy(config, nonce)

View File

@ -10,6 +10,7 @@ import functools
import inspect
import re
import string
import warnings
from importlib import import_module
from pickle import PicklingError
from urllib.parse import quote
@ -21,6 +22,7 @@ from django.core.checks import Error, Warning
from django.core.checks.urls import check_resolver
from django.core.exceptions import ImproperlyConfigured
from django.utils.datastructures import MultiValueDict
from django.utils.deprecation import RemovedInDjango61Warning
from django.utils.functional import cached_property
from django.utils.http import RFC3986_SUBDELIMS, escape_leading_slashes
from django.utils.regex_helper import _lazy_re_compile, normalize
@ -739,15 +741,26 @@ class URLResolver:
raise ImproperlyConfigured(msg.format(name=self.urlconf_name)) from e
return patterns
def resolve_error_handler(self, view_type):
callback = getattr(self.urlconf_module, "handler%s" % view_type, None)
if not callback:
def resolve_error_handler(self, status_code):
# RemovedInDjango61Warning.
callback = getattr(self.urlconf_module, f"handler{status_code}", None)
if callback:
warnings.warn(
"handler<status> custom error handlers are deprecated, please "
"replace them by a generic `error_handler` view function.",
RemovedInDjango61Warning,
)
return get_callable(callback)
error_view = getattr(self.urlconf_module, "error_handler", None)
if error_view:
error_view.status_code = status_code
else:
# No handler specified in file; use lazy import, since
# django.conf.urls imports this file.
from django.conf import urls
# django.views.defaults imports this file.
from django.views.defaults import DefaultErrorView
callback = getattr(urls, "handler%s" % view_type)
return get_callable(callback)
error_view = DefaultErrorView.as_view(status_code=status_code)
return error_view
def reverse(self, lookup_view, *args, **kwargs):
return self._reverse_with_prefix(lookup_view, "", *args, **kwargs)

View File

@ -10,7 +10,7 @@ from urllib.parse import parse_qsl, quote, unquote, urlencode, urlsplit, urlunsp
from django.conf import settings
from django.core.exceptions import SuspiciousOperation, ValidationError
from django.core.validators import EmailValidator
from django.core.validators import DomainNameValidator, EmailValidator
from django.utils.deprecation import RemovedInDjango70Warning
from django.utils.functional import Promise, cached_property, keep_lazy, keep_lazy_text
from django.utils.http import MAX_URL_LENGTH, RFC3986_GENDELIMS, RFC3986_SUBDELIMS
@ -296,7 +296,9 @@ class Urlizer:
simple_url_re = _lazy_re_compile(r"^https?://\[?\w", re.IGNORECASE)
simple_url_2_re = _lazy_re_compile(
r"^www\.|^(?!http)\w[^@]+\.(com|edu|gov|int|mil|net|org)($|/.*)$", re.IGNORECASE
rf"^www\.|^(?!http)(?:{DomainNameValidator.hostname_re})"
r"\.(com|edu|gov|int|mil|net|org)($|/.*)$",
re.IGNORECASE,
)
word_split_re = _lazy_re_compile(r"""([\s<>"']+)""")

View File

@ -18,6 +18,7 @@ from django.utils.encoding import force_str
from django.utils.module_loading import import_string
from django.utils.regex_helper import _lazy_re_compile
from django.utils.version import get_docs_version
from django.views.decorators.csp import csp_override, csp_report_only_override
from django.views.decorators.debug import coroutine_functions_to_sensitive_variables
# Minimal Django templates engine to render the error templates
@ -59,6 +60,8 @@ class CallableSettingWrapper:
return repr(self._wrapped)
@csp_override({})
@csp_report_only_override({})
def technical_500_response(request, exc_type, exc_value, tb, status_code=500):
"""
Create a technical server error response. The last three arguments are
@ -606,6 +609,8 @@ class ExceptionReporter:
tb = tb.tb_next
@csp_override({})
@csp_report_only_override({})
def technical_404_response(request, exception):
"""Create a technical 404 error response. `exception` is the Http404."""
try:

View File

@ -0,0 +1,39 @@
from functools import wraps
from asgiref.sync import iscoroutinefunction
def _make_csp_decorator(config_attr_name, config_attr_value):
"""General CSP override decorator factory."""
if not isinstance(config_attr_value, dict):
raise TypeError("CSP config should be a mapping.")
def decorator(view_func):
@wraps(view_func)
async def _wrapped_async_view(request, *args, **kwargs):
response = await view_func(request, *args, **kwargs)
setattr(response, config_attr_name, config_attr_value)
return response
@wraps(view_func)
def _wrapped_sync_view(request, *args, **kwargs):
response = view_func(request, *args, **kwargs)
setattr(response, config_attr_name, config_attr_value)
return response
if iscoroutinefunction(view_func):
return _wrapped_async_view
return _wrapped_sync_view
return decorator
def csp_override(config):
"""Override the Content-Security-Policy header for a view."""
return _make_csp_decorator("_csp_config", config)
def csp_report_only_override(config):
"""Override the Content-Security-Policy-Report-Only header for a view."""
return _make_csp_decorator("_csp_ro_config", config)

View File

@ -1,13 +1,17 @@
from urllib.parse import quote
from django.http import (
HttpResponse,
HttpResponseBadRequest,
HttpResponseForbidden,
HttpResponseNotFound,
HttpResponseServerError,
)
from django.template import Context, Engine, TemplateDoesNotExist, loader
from django.utils.decorators import method_decorator
from django.views.debug import DEBUG_ENGINE
from django.views.decorators.csrf import requires_csrf_token
from django.views.generic.base import ContextMixin, View
ERROR_404_TEMPLATE_NAME = "404.html"
ERROR_403_TEMPLATE_NAME = "403.html"
@ -148,3 +152,63 @@ def permission_denied(request, exception, template_name=ERROR_403_TEMPLATE_NAME)
return HttpResponseForbidden(
template.render(request=request, context={"exception": str(exception)})
)
@method_decorator(requires_csrf_token, name="dispatch")
class DefaultErrorView(ContextMixin, View):
status_code = None
context_by_status = {
400: {"title": "Bad Request (400)", "details": ""},
403: {"title": "403 Forbidden", "details": ""},
404: {
"title": "Not Found",
"details": "The requested resource was not found on this server.",
},
500: {"title": "Server Error (500)", "details": ""},
}
def setup(self, request, exception=None, **kwargs):
self.exception = exception
return super().setup(request, **kwargs)
def get(self, request, *args, **kwargs):
response_class = HttpResponse.response_class_by_status_code(self.status_code)
context = self.get_context_data(**kwargs)
try:
template = loader.get_template(self.get_template_name())
content = template.render(context, request)
except TemplateDoesNotExist:
template = DEBUG_ENGINE.from_string(ERROR_PAGE_TEMPLATE % context)
content = template.render(context=Context(context))
return response_class(content, status=self.status_code)
def post(self, *args, **kwargs):
return self.get(*args, **kwargs)
def get_template_name(self):
return f"{self.status_code}.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context |= self.context_by_status.get(
self.status_code, {"title": f"Error ({self.status_code})", "details": ""}
)
context |= {
"request_path": quote(self.request.path),
"exception": self.exception_as_string(),
}
return context
def exception_as_string(self):
if self.status_code == 404:
# Try to get an "interesting" exception message, if any (and not the
# ugly Resolver404 dictionary)
try:
message = self.exception.args[0]
except (AttributeError, IndexError):
pass
else:
if isinstance(message, str):
return message
return self.exception.__class__.__name__
return str(self.exception)

View File

@ -51,6 +51,7 @@ help:
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " spelling to check for typos in documentation"
@echo " black to apply the black formatting to code blocks in documentation"
@echo " lint to check for linting errors in documentation"
clean:
@ -175,6 +176,11 @@ black:
@echo
@echo "Code blocks reformatted"
check: spelling black
lint:
$(PYTHON) lint.py
@echo
@echo "Documentation lint complete."
check: spelling black lint
@echo
@echo "Style and spelling checks completed."

View File

@ -25,4 +25,4 @@ Indices, glossary and tables
* :ref:`genindex`
* :ref:`modindex`
* :doc:`glossary`
* :doc:`/glossary`

View File

@ -22,8 +22,8 @@ only allows access to users with those two fields both set to True.
How do I automatically set a field's value to the user who last edited the object in the admin?
===============================================================================================
The :class:`~django.contrib.admin.ModelAdmin` class provides customization hooks
that allow you to transform an object as it saved, using details from the
The :class:`~django.contrib.admin.ModelAdmin` class provides customization
hooks that allow you to transform an object as it saved, using details from the
request. By extracting the current user from the request, and customizing the
:meth:`~django.contrib.admin.ModelAdmin.save_model` hook, you can update an
object to reflect the user that edited it. See :ref:`the documentation on
@ -33,8 +33,8 @@ How do I limit admin access so that objects can only be edited by the users who
=============================================================================================
The :class:`~django.contrib.admin.ModelAdmin` class also provides customization
hooks that allow you to control the visibility and editability of objects in the
admin. Using the same trick of extracting the user from the request, the
hooks that allow you to control the visibility and editability of objects in
the admin. Using the same trick of extracting the user from the request, the
:meth:`~django.contrib.admin.ModelAdmin.get_queryset` and
:meth:`~django.contrib.admin.ModelAdmin.has_change_permission` can be used to
control the visibility and editability of objects in the admin.

View File

@ -32,8 +32,9 @@ thrilled to be able to give something back to the open-source community.
What does "Django" mean, and how do you pronounce it?
=====================================================
Django is named after `Django Reinhardt`_, a jazz manouche guitarist from the 1930s
to early 1950s. To this day, he's considered one of the best guitarists of all time.
Django is named after `Django Reinhardt`_, a jazz manouche guitarist from the
1930s to early 1950s. To this day, he's considered one of the best guitarists
of all time.
Listen to his music. You'll like it.
@ -185,9 +186,10 @@ corresponds to a web page on the official Django site.
Because the documentation is :source:`stored in revision control <docs>`, you
can browse documentation changes just like you can browse code changes.
Technically, the docs on Django's site are generated from the latest development
versions of those reST documents, so the docs on the Django site may offer more
information than the docs that come with the latest Django release.
Technically, the docs on Django's site are generated from the latest
development versions of those reST documents, so the docs on the Django site
may offer more information than the docs that come with the latest Django
release.
How do I cite Django?
=====================

View File

@ -8,8 +8,8 @@ How do I get started?
#. `Download the code`_.
#. Install Django (read the :doc:`installation guide </intro/install>`).
#. Walk through the :doc:`tutorial </intro/tutorial01>`.
#. Check out the rest of the :doc:`documentation </index>`, and `ask questions`_ if you
run into trouble.
#. Check out the rest of the :doc:`documentation </index>`, and
`ask questions`_ if you run into trouble.
.. _`Download the code`: https://www.djangoproject.com/download/
.. _ask questions: https://www.djangoproject.com/community/

View File

@ -27,8 +27,8 @@ the following:
``connection.queries`` includes all SQL statements -- INSERTs, UPDATES,
SELECTs, etc. Each time your app hits the database, the query will be recorded.
If you are using :doc:`multiple databases</topics/db/multi-db>`, you can use the
same interface on each member of the ``connections`` dictionary:
If you are using :doc:`multiple databases</topics/db/multi-db>`, you can use
the same interface on each member of the ``connections`` dictionary:
.. code-block:: pycon

View File

@ -51,7 +51,8 @@ Glossary
See :class:`property`.
queryset
An object representing some set of rows to be fetched from the database.
An object representing some set of rows to be fetched from the
database.
See :doc:`/topics/db/queries`.

View File

@ -4,7 +4,7 @@ How to authenticate using ``REMOTE_USER``
This document describes how to make use of external authentication sources
(where the web server sets the ``REMOTE_USER`` environment variable) in your
Django applications. This type of authentication solution is typically seen on
Django applications. This type of authentication solution is typically seen on
intranet sites, with single sign-on solutions such as IIS and Integrated
Windows Authentication or Apache and `mod_authnz_ldap`_, `CAS`_, `WebAuth`_,
`mod_auth_sspi`_, etc.
@ -15,9 +15,9 @@ Windows Authentication or Apache and `mod_authnz_ldap`_, `CAS`_, `WebAuth`_,
.. _mod_auth_sspi: https://sourceforge.net/projects/mod-auth-sspi
When the web server takes care of authentication it typically sets the
``REMOTE_USER`` environment variable for use in the underlying application. In
``REMOTE_USER`` environment variable for use in the underlying application. In
Django, ``REMOTE_USER`` is made available in the :attr:`request.META
<django.http.HttpRequest.META>` attribute. Django can be configured to make
<django.http.HttpRequest.META>` attribute. Django can be configured to make
use of the ``REMOTE_USER`` value using the ``RemoteUserMiddleware``
or ``PersistentRemoteUserMiddleware``, and
:class:`~django.contrib.auth.backends.RemoteUserBackend` classes found in
@ -76,7 +76,7 @@ regardless of ``AUTHENTICATION_BACKENDS``.
If your authentication mechanism uses a custom HTTP header and not
``REMOTE_USER``, you can subclass ``RemoteUserMiddleware`` and set the
``header`` attribute to the desired ``request.META`` key. For example:
``header`` attribute to the desired ``request.META`` key. For example:
.. code-block:: python
:caption: ``mysite/middleware.py``

View File

@ -37,9 +37,9 @@ Using CSRF protection with AJAX
===============================
While the above method can be used for AJAX POST requests, it has some
inconveniences: you have to remember to pass the CSRF token in as POST data with
every POST request. For this reason, there is an alternative method: on each
XMLHttpRequest, set a custom ``X-CSRFToken`` header (as specified by the
inconveniences: you have to remember to pass the CSRF token in as POST data
with every POST request. For this reason, there is an alternative method: on
each XMLHttpRequest, set a custom ``X-CSRFToken`` header (as specified by the
:setting:`CSRF_HEADER_NAME` setting) to the value of the CSRF token. This is
often easier because many JavaScript frameworks provide hooks that allow
headers to be set on every request.
@ -217,11 +217,11 @@ Testing and CSRF protection
===========================
The ``CsrfViewMiddleware`` will usually be a big hindrance to testing view
functions, due to the need for the CSRF token which must be sent with every POST
request. For this reason, Django's HTTP client for tests has been modified to
set a flag on requests which relaxes the middleware and the ``csrf_protect``
decorator so that they no longer rejects requests. In every other respect
(e.g. sending cookies etc.), they behave the same.
functions, due to the need for the CSRF token which must be sent with every
POST request. For this reason, Django's HTTP client for tests has been modified
to set a flag on requests which relaxes the middleware and the ``csrf_protect``
decorator so that they no longer rejects requests. In every other respect (e.g.
sending cookies etc.), they behave the same.
If, for some reason, you *want* the test client to perform CSRF
checks, you can create an instance of the test client that enforces
@ -237,8 +237,8 @@ Edge cases
Certain views can have unusual requirements that mean they don't fit the normal
pattern envisaged here. A number of utilities can be useful in these
situations. The scenarios they might be needed in are described in the following
section.
situations. The scenarios they might be needed in are described in the
following section.
Disabling CSRF protection for just a few views
----------------------------------------------
@ -265,8 +265,8 @@ There may be some views that are unprotected and have been exempted by
``csrf_exempt``, but still need to include the CSRF token.
Solution: use :func:`~django.views.decorators.csrf.csrf_exempt` followed by
:func:`~django.views.decorators.csrf.requires_csrf_token`. (i.e. ``requires_csrf_token``
should be the innermost decorator).
:func:`~django.views.decorators.csrf.requires_csrf_token`. (i.e.
``requires_csrf_token`` should be the innermost decorator).
Protecting a view for only one path
-----------------------------------
@ -304,8 +304,8 @@ view that sends the page.
CSRF protection in reusable applications
========================================
Because it is possible for the developer to turn off the ``CsrfViewMiddleware``,
all relevant views in contrib apps use the ``csrf_protect`` decorator to ensure
the security of these applications against CSRF. It is recommended that the
developers of other reusable apps that want the same guarantees also use the
``csrf_protect`` decorator on their views.
Because it is possible for the developer to turn off the
``CsrfViewMiddleware``, all relevant views in contrib apps use the
``csrf_protect`` decorator to ensure the security of these applications against
CSRF. It is recommended that the developers of other reusable apps that want
the same guarantees also use the ``csrf_protect`` decorator on their views.

View File

@ -16,8 +16,9 @@ You'll need to follow these steps:
class MyStorage(Storage): ...
#. Django must be able to instantiate your storage system without any arguments.
This means that any settings should be taken from ``django.conf.settings``::
#. Django must be able to instantiate your storage system without any
arguments. This means that any settings should be taken from
``django.conf.settings``::
from django.conf import settings
from django.core.files.storage import Storage
@ -29,17 +30,17 @@ You'll need to follow these steps:
option = settings.CUSTOM_STORAGE_OPTIONS
...
#. Your storage class must implement the :meth:`_open()` and :meth:`_save()`
#. Your storage class must implement the :meth:`_open` and :meth:`_save`
methods, along with any other methods appropriate to your storage class. See
below for more on these methods.
In addition, if your class provides local file storage, it must override
the ``path()`` method.
#. Your storage class must be :ref:`deconstructible <custom-deconstruct-method>`
so it can be serialized when it's used on a field in a migration. As long
as your field has arguments that are themselves
:ref:`serializable <migration-serializing>`, you can use the
#. Your storage class must be :ref:`deconstructible
<custom-deconstruct-method>` so it can be serialized when it's used on a
field in a migration. As long as your field has arguments that are
themselves :ref:`serializable <migration-serializing>`, you can use the
``django.utils.deconstruct.deconstructible`` class decorator for this
(that's what Django uses on FileSystemStorage).
@ -73,16 +74,16 @@ objects. These are:
**Required**.
Called by ``Storage.open()``, this is the actual mechanism the storage class
uses to open the file. This must return a ``File`` object, though in most cases,
you'll want to return some subclass here that implements logic specific to the
backend storage system. The :exc:`FileNotFoundError` exception should be raised
when a file doesn't exist.
uses to open the file. This must return a ``File`` object, though in most
cases, you'll want to return some subclass here that implements logic specific
to the backend storage system. The :exc:`FileNotFoundError` exception should be
raised when a file doesn't exist.
.. method:: _save(name, content)
Called by ``Storage.save()``. The ``name`` will already have gone through
``get_valid_name()`` and ``get_available_name()``, and the ``content`` will be a
``File`` object itself.
``get_valid_name()`` and ``get_available_name()``, and the ``content`` will be
a ``File`` object itself.
Should return the actual name of the file saved (usually the ``name`` passed
in, but if the storage needs to change the file name return the new name

View File

@ -39,9 +39,9 @@ lookup, then we need to tell Django about it::
return "%s <> %s" % (lhs, rhs), params
To register the ``NotEqual`` lookup we will need to call ``register_lookup`` on
the field class we want the lookup to be available for. In this case, the lookup
makes sense on all ``Field`` subclasses, so we register it with ``Field``
directly::
the field class we want the lookup to be available for. In this case, the
lookup makes sense on all ``Field`` subclasses, so we register it with
``Field`` directly::
from django.db.models import Field
@ -61,10 +61,10 @@ could place the implementation in a ``models.py`` file, or register the lookup
in the ``ready()`` method of an ``AppConfig``.
Taking a closer look at the implementation, the first required attribute is
``lookup_name``. This allows the ORM to understand how to interpret ``name__ne``
and use ``NotEqual`` to generate the SQL. By convention, these names are always
lowercase strings containing only letters, but the only hard requirement is
that it must not contain the string ``__``.
``lookup_name``. This allows the ORM to understand how to interpret
``name__ne`` and use ``NotEqual`` to generate the SQL. By convention, these
names are always lowercase strings containing only letters, but the only hard
requirement is that it must not contain the string ``__``.
We then need to define the ``as_sql`` method. This takes a ``SQLCompiler``
object, called ``compiler``, and the active database connection.
@ -112,8 +112,8 @@ or where it did not exceed a certain amount
functionality which is possible in a database backend independent manner,
and without duplicating functionality already in Django.
We will start by writing an ``AbsoluteValue`` transformer. This will use the SQL
function ``ABS()`` to transform the value before comparison::
We will start by writing an ``AbsoluteValue`` transformer. This will use the
SQL function ``ABS()`` to transform the value before comparison::
from django.db.models import Transform
@ -227,16 +227,16 @@ Notice also that as both sides are used multiple times in the query the params
need to contain ``lhs_params`` and ``rhs_params`` multiple times.
The final query does the inversion (``27`` to ``-27``) directly in the
database. The reason for doing this is that if the ``self.rhs`` is something else
than a plain integer value (for example an ``F()`` reference) we can't do the
transformations in Python.
database. The reason for doing this is that if the ``self.rhs`` is something
else than a plain integer value (for example an ``F()`` reference) we can't do
the transformations in Python.
.. note::
In fact, most lookups with ``__abs`` could be implemented as range queries
like this, and on most database backends it is likely to be more sensible to
do so as you can make use of the indexes. However with PostgreSQL you may
want to add an index on ``abs(change)`` which would allow these queries to
be very efficient.
like this, and on most database backends it is likely to be more sensible
to do so as you can make use of the indexes. However with PostgreSQL you
may want to add an index on ``abs(change)`` which would allow these queries
to be very efficient.
A bilateral transformer example
===============================
@ -252,10 +252,10 @@ very useful in practice as Django already comes with a bunch of built-in
case-insensitive lookups, but it will be a nice demonstration of bilateral
transformations in a database-agnostic way.
We define an ``UpperCase`` transformer which uses the SQL function ``UPPER()`` to
transform the values before comparison. We define
:attr:`bilateral = True <django.db.models.Transform.bilateral>` to indicate that
this transformation should apply to both ``lhs`` and ``rhs``::
We define an ``UpperCase`` transformer which uses the SQL function ``UPPER()``
to transform the values before comparison. We define :attr:`bilateral = True
<django.db.models.Transform.bilateral>` to indicate that this transformation
should apply to both ``lhs`` and ``rhs``::
from django.db.models import Transform
@ -272,8 +272,8 @@ Next, let's register it::
CharField.register_lookup(UpperCase)
TextField.register_lookup(UpperCase)
Now, the queryset ``Author.objects.filter(name__upper="doe")`` will generate a case
insensitive query like this:
Now, the queryset ``Author.objects.filter(name__upper="doe")`` will generate a
case insensitive query like this:
.. code-block:: sql

View File

@ -28,8 +28,8 @@ whose name doesn't begin with an underscore. For example:
tests.py
views.py
In this example, the ``closepoll`` command will be made available to any project
that includes the ``polls`` application in :setting:`INSTALLED_APPS`.
In this example, the ``closepoll`` command will be made available to any
project that includes the ``polls`` application in :setting:`INSTALLED_APPS`.
The ``_private.py`` module will not be available as a management command.
@ -73,13 +73,12 @@ look like this::
.. _management-commands-output:
.. note::
When you are using management commands and wish to provide console
output, you should write to ``self.stdout`` and ``self.stderr``,
instead of printing to ``stdout`` and ``stderr`` directly. By
using these proxies, it becomes much easier to test your custom
command. Note also that you don't need to end messages with a newline
character, it will be added automatically, unless you specify the ``ending``
parameter::
When you are using management commands and wish to provide console output,
you should write to ``self.stdout`` and ``self.stderr``, instead of
printing to ``stdout`` and ``stderr`` directly. By using these proxies, it
becomes much easier to test your custom command. Note also that you don't
need to end messages with a newline character, it will be added
automatically, unless you specify the ``ending`` parameter::
self.stdout.write("Unterminated line", ending="")
@ -99,7 +98,8 @@ Accepting optional arguments
The same ``closepoll`` could be easily modified to delete a given poll instead
of closing it by accepting additional command line options. These custom
options can be added in the :meth:`~BaseCommand.add_arguments` method like this::
options can be added in the :meth:`~BaseCommand.add_arguments` method like
this::
class Command(BaseCommand):
def add_arguments(self, parser):
@ -120,7 +120,7 @@ options can be added in the :meth:`~BaseCommand.add_arguments` method like this:
# ...
The option (``delete`` in our example) is available in the options dict
parameter of the handle method. See the :py:mod:`argparse` Python documentation
parameter of the handle method. See the :mod:`argparse` Python documentation
for more about ``add_argument`` usage.
In addition to being able to add custom command line options, all
@ -208,7 +208,7 @@ All attributes can be set in your derived class and can be used in
If your command defines mandatory positional arguments, you can customize
the message error returned in the case of missing arguments. The default is
output by :py:mod:`argparse` ("too few arguments").
output by :mod:`argparse` ("too few arguments").
.. attribute:: BaseCommand.output_transaction
@ -273,7 +273,8 @@ the :meth:`~BaseCommand.handle` method must be implemented.
Django.
You can customize the instance by overriding this method and calling
``super()`` with ``kwargs`` of :class:`~argparse.ArgumentParser` parameters.
``super()`` with ``kwargs`` of :class:`~argparse.ArgumentParser`
parameters.
.. method:: BaseCommand.add_arguments(parser)

View File

@ -7,17 +7,18 @@ How to create custom model fields
Introduction
============
The :doc:`model reference </topics/db/models>` documentation explains how to use
Django's standard field classes -- :class:`~django.db.models.CharField`,
The :doc:`model reference </topics/db/models>` documentation explains how to
use Django's standard field classes -- :class:`~django.db.models.CharField`,
:class:`~django.db.models.DateField`, etc. For many purposes, those classes are
all you'll need. Sometimes, though, the Django version won't meet your precise
requirements, or you'll want to use a field that is entirely different from
those shipped with Django.
Django's built-in field types don't cover every possible database column type --
only the common types, such as ``VARCHAR`` and ``INTEGER``. For more obscure
Django's built-in field types don't cover every possible database column type
-- only the common types, such as ``VARCHAR`` and ``INTEGER``. For more obscure
column types, such as geographic polygons or even user-created types such as
`PostgreSQL custom types`_, you can define your own Django ``Field`` subclasses.
`PostgreSQL custom types`_, you can define your own Django ``Field``
subclasses.
.. _PostgreSQL custom types: https://www.postgresql.org/docs/current/sql-createtype.html
@ -33,7 +34,7 @@ easier to follow, we'll use a consistent example throughout this document:
wrapping a Python object representing the deal of cards in a hand of Bridge_.
Don't worry, you don't have to know how to play Bridge to follow this example.
You only need to know that 52 cards are dealt out equally to four players, who
are traditionally called *north*, *east*, *south* and *west*. Our class looks
are traditionally called *north*, *east*, *south* and *west*. Our class looks
something like this::
class Hand:
@ -106,13 +107,13 @@ What does a field class do?
---------------------------
All of Django's fields (and when we say *fields* in this document, we always
mean model fields and not :doc:`form fields </ref/forms/fields>`) are subclasses
of :class:`django.db.models.Field`. Most of the information that Django records
about a field is common to all fields -- name, help text, uniqueness and so
forth. Storing all that information is handled by ``Field``. We'll get into the
precise details of what ``Field`` can do later on; for now, suffice it to say
that everything descends from ``Field`` and then customizes key pieces of the
class behavior.
mean model fields and not :doc:`form fields </ref/forms/fields>`) are
subclasses of :class:`django.db.models.Field`. Most of the information that
Django records about a field is common to all fields -- name, help text,
uniqueness and so forth. Storing all that information is handled by ``Field``.
We'll get into the precise details of what ``Field`` can do later on; for now,
suffice it to say that everything descends from ``Field`` and then customizes
key pieces of the class behavior.
It's important to realize that a Django field class is not what is stored in
your model attributes. The model attributes contain normal Python objects. The
@ -149,9 +150,9 @@ is most similar to. Can you subclass an existing Django field and save yourself
some work? If not, you should subclass the :class:`~django.db.models.Field`
class, from which everything is descended.
Initializing your new field is a matter of separating out any arguments that are
specific to your case from the common arguments and passing the latter to the
``__init__()`` method of :class:`~django.db.models.Field` (or your parent
Initializing your new field is a matter of separating out any arguments that
are specific to your case from the common arguments and passing the latter to
the ``__init__()`` method of :class:`~django.db.models.Field` (or your parent
class).
In our example, we'll call our field ``HandField``. (It's a good idea to call
@ -214,9 +215,9 @@ The ``Field.__init__()`` method takes the following parameters:
* :attr:`~django.db.models.Field.choices`
* :attr:`~django.db.models.Field.help_text`
* :attr:`~django.db.models.Field.db_column`
* :attr:`~django.db.models.Field.db_tablespace`: Only for index creation, if the
backend supports :doc:`tablespaces </topics/db/tablespaces>`. You can usually
ignore this option.
* :attr:`~django.db.models.Field.db_tablespace`: Only for index creation, if
the backend supports :doc:`tablespaces </topics/db/tablespaces>`. You can
usually ignore this option.
* :attr:`~django.db.models.Field.auto_created`: ``True`` if the field was
automatically created, as for the :class:`~django.db.models.OneToOneField`
used by model inheritance. For advanced use only.
@ -253,9 +254,9 @@ name and import path. You do, however, have to care about the positional
and keyword arguments, as these are likely the things you are changing.
For example, in our ``HandField`` class we're always forcibly setting
max_length in ``__init__()``. The ``deconstruct()`` method on the base ``Field``
class will see this and try to return it in the keyword arguments; thus,
we can drop it from the keyword arguments for readability::
max_length in ``__init__()``. The ``deconstruct()`` method on the base
``Field`` class will see this and try to return it in the keyword arguments;
thus, we can drop it from the keyword arguments for readability::
from django.db import models
@ -471,10 +472,11 @@ over this field. You are then responsible for creating the column in the right
table in some other way, but this gives you a way to tell Django to get out of
the way.
The :meth:`~Field.rel_db_type` method is called by fields such as ``ForeignKey``
and ``OneToOneField`` that point to another field to determine their database
column data types. For example, if you have an ``UnsignedAutoField``, you also
need the foreign keys that point to that field to use the same data type::
The :meth:`~Field.rel_db_type` method is called by fields such as
``ForeignKey`` and ``OneToOneField`` that point to another field to determine
their database column data types. For example, if you have an
``UnsignedAutoField``, you also need the foreign keys that point to that field
to use the same data type::
# MySQL unsigned integer (range 0 to 4294967295).
class UnsignedAutoField(models.AutoField):
@ -648,8 +650,8 @@ a custom form field (and even a form widget). See the :doc:`forms documentation
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::
Continuing our ongoing example, we can write the :meth:`~Field.formfield`
method as::
class HandField(models.Field):
# ...

View File

@ -39,8 +39,8 @@ For example:
The customization above adds :func:`~django.urls.resolve` and
:func:`~django.urls.reverse` to the default namespace, which already includes
all models from the apps listed in :setting:`INSTALLED_APPS` plus what is
imported by default. These objects will be available in the ``shell`` without
all models from the apps listed in :setting:`INSTALLED_APPS` plus what is
imported by default. These objects will be available in the ``shell`` without
requiring a manual import.
Running this customized ``shell`` command with ``verbosity=2`` would show:
@ -48,7 +48,7 @@ Running this customized ``shell`` command with ``verbosity=2`` would show:
.. console::
13 objects imported automatically:
from django.db import connection, reset_queries, models
from django.conf import settings
from django.contrib.admin.models import LogEntry

View File

@ -264,7 +264,7 @@ Template filter code falls into one of two situations:
reviewing your code.
Marking a filter ``is_safe`` will coerce the filter's return value to
a string. If your filter should return a boolean or other non-string
a string. If your filter should return a boolean or other non-string
value, marking it ``is_safe`` will probably have unintended
consequences (such as converting a boolean False to the string
'False').
@ -285,13 +285,13 @@ Template filter code falls into one of two situations:
order to make things easier for your template authors.
In order for your filter to know the current auto-escaping state, set the
``needs_autoescape`` flag to ``True`` when you register your filter function.
(If you don't specify this flag, it defaults to ``False``). This flag tells
Django that your filter function wants to be passed an extra keyword
argument, called ``autoescape``, that is ``True`` if auto-escaping is in
effect and ``False`` otherwise. It is recommended to set the default of the
``autoescape`` parameter to ``True``, so that if you call the function
from Python code it will have escaping enabled by default.
``needs_autoescape`` flag to ``True`` when you register your filter
function. (If you don't specify this flag, it defaults to ``False``). This
flag tells Django that your filter function wants to be passed an extra
keyword argument, called ``autoescape``, that is ``True`` if auto-escaping
is in effect and ``False`` otherwise. It is recommended to set the default
of the ``autoescape`` parameter to ``True``, so that if you call the
function from Python code it will have escaping enabled by default.
For example, let's write a filter that emphasizes the first character of
a string::
@ -509,7 +509,7 @@ Simple block tags
When a section of rendered template needs to be passed into a custom tag,
Django provides the ``simple_block_tag`` helper function to accomplish this.
Similar to :meth:`~django.template.Library.simple_tag()`, this function accepts
Similar to :meth:`~django.template.Library.simple_tag`, this function accepts
a custom tag function, but with the additional ``content`` argument, which
contains the rendered content as defined inside the tag. This allows dynamic
template sections to be easily incorporated into custom tags.
@ -827,8 +827,8 @@ Advanced custom template tags
-----------------------------
Sometimes the basic features for custom template tag creation aren't enough.
Don't worry, Django gives you complete access to the internals required to build
a template tag from the ground up.
Don't worry, Django gives you complete access to the internals required to
build a template tag from the ground up.
A quick overview
----------------
@ -841,7 +841,7 @@ When Django compiles a template, it splits the raw template text into *nodes*.
Each node is an instance of ``django.template.Node`` and has a ``render()``
method. A compiled template is a list of ``Node`` objects. When you call
``render()`` on a compiled template object, the template calls ``render()`` on
each ``Node`` in its node list, with the given context. The results are all
each ``Node`` in its node list, with the given context. The results are all
concatenated together to form the output of the template.
Thus, to define a custom template tag, you specify how the raw template tag is
@ -856,10 +856,10 @@ function with the tag contents and the parser object itself. This function is
responsible for returning a ``Node`` instance based on the contents of the tag.
For example, let's write a full implementation of our template tag,
``{% current_time %}``, that displays the current date/time, formatted according
to a parameter given in the tag, in :func:`~time.strftime` syntax. It's a good
idea to decide the tag syntax before anything else. In our case, let's say the
tag should be used like this:
``{% current_time %}``, that displays the current date/time, formatted
according to a parameter given in the tag, in :func:`~time.strftime` syntax.
It's a good idea to decide the tag syntax before anything else. In our case,
let's say the tag should be used like this:
.. code-block:: html+django
@ -1159,7 +1159,7 @@ Now your tag should begin to look like this::
return FormatTimeNode(date_to_be_formatted, format_string[1:-1])
You also have to change the renderer to retrieve the actual contents of the
``date_updated`` property of the ``blog_entry`` object. This can be
``date_updated`` property of the ``blog_entry`` object. This can be
accomplished by using the ``Variable()`` class in ``django.template``.
To use the ``Variable`` class, instantiate it with the name of the variable to
@ -1300,9 +1300,10 @@ Here's how a simplified ``{% comment %}`` tag might be implemented::
The actual implementation of :ttag:`{% comment %}<comment>` is slightly
different in that it allows broken template tags to appear between
``{% comment %}`` and ``{% endcomment %}``. It does so by calling
``parser.skip_past('endcomment')`` instead of ``parser.parse(('endcomment',))``
followed by ``parser.delete_first_token()``, thus avoiding the generation of a
node list.
``parser.skip_past('endcomment')`` instead of
``parser.parse(('endcomment',))`` followed by
``parser.delete_first_token()``, thus avoiding the generation of a node
list.
``parser.parse()`` takes a tuple of names of block tags *to parse until*. It
returns an instance of ``django.template.NodeList``, which is a list of

View File

@ -40,8 +40,9 @@ For more advanced usage, please read the `Uvicorn documentation <Uvicorn_>`_.
Deploying Django using Uvicorn and Gunicorn
===========================================
Gunicorn_ is a robust web server that implements process monitoring and automatic
restarts. This can be useful when running Uvicorn in a production environment.
Gunicorn_ is a robust web server that implements process monitoring and
automatic restarts. This can be useful when running Uvicorn in a production
environment.
To install Uvicorn and Gunicorn, use the following:

View File

@ -29,8 +29,8 @@ You should also consider how you will handle :doc:`static files
:doc:`error reporting</howto/error-reporting>`.
Finally, before you deploy your application to production, you should run
through our :doc:`deployment checklist<checklist>` to ensure that your
configurations are suitable.
through our :doc:`deployment checklist </howto/deployment/checklist>` to ensure
that your configurations are suitable.
.. _WSGI: https://wsgi.readthedocs.io/en/latest/
.. _ASGI: https://asgi.readthedocs.io/en/latest/

View File

@ -2,10 +2,10 @@
How to authenticate against Django's user database from Apache
==============================================================
Since keeping multiple authentication databases in sync is a common problem when
dealing with Apache, you can configure Apache to authenticate against Django's
:doc:`authentication system </topics/auth/index>` directly. This requires Apache
version >= 2.2 and mod_wsgi >= 2.0. For example, you could:
Since keeping multiple authentication databases in sync is a common problem
when dealing with Apache, you can configure Apache to authenticate against
Django's :doc:`authentication system </topics/auth/index>` directly. This
requires Apache version >= 2.2 and mod_wsgi >= 2.0. For example, you could:
* Serve static/media files directly from Apache only to authenticated users.

View File

@ -37,9 +37,9 @@ deployments.
WSGI servers obtain the path to the ``application`` callable from their
configuration. Django's built-in server, namely the :djadmin:`runserver`
command, reads it from the :setting:`WSGI_APPLICATION` setting. By default, it's
set to ``<project_name>.wsgi.application``, which points to the ``application``
callable in :file:`<project_name>/wsgi.py`.
command, reads it from the :setting:`WSGI_APPLICATION` setting. By default,
it's set to ``<project_name>.wsgi.application``, which points to the
``application`` callable in :file:`<project_name>/wsgi.py`.
Configuring the settings module
===============================

View File

@ -124,8 +124,8 @@ use ``WSGIPythonPath``; instead you should use the ``python-path`` option to
WSGIProcessGroup example.com
If you want to serve your project in a subdirectory
(``https://example.com/mysite`` in this example), you can add ``WSGIScriptAlias``
to the configuration above:
(``https://example.com/mysite`` in this example), you can add
``WSGIScriptAlias`` to the configuration above:
.. code-block:: apache

View File

@ -4,8 +4,8 @@ How to manage error reporting
When you're running a public site you should always turn off the
:setting:`DEBUG` setting. That will make your server run much faster, and will
also prevent malicious users from seeing details of your application that can be
revealed by the error pages.
also prevent malicious users from seeing details of your application that can
be revealed by the error pages.
However, running with :setting:`DEBUG` set to ``False`` means you'll never see
errors generated by your site -- everyone will instead see your public error
@ -87,11 +87,11 @@ regular expression objects. For example::
re.compile(r"^/phpmyadmin/"),
]
In this example, a 404 to any URL ending with ``.php`` or ``.cgi`` will *not* be
reported. Neither will any URL starting with ``/phpmyadmin/``.
In this example, a 404 to any URL ending with ``.php`` or ``.cgi`` will *not*
be reported. Neither will any URL starting with ``/phpmyadmin/``.
The following example shows how to exclude some conventional URLs that browsers and
crawlers often request::
The following example shows how to exclude some conventional URLs that browsers
and crawlers often request::
import re
@ -220,7 +220,8 @@ filtered out of error reports in a production environment (that is, where
disclosed.
To systematically hide all POST parameters of a request in error reports,
do not provide any argument to the ``sensitive_post_parameters`` decorator::
do not provide any argument to the ``sensitive_post_parameters``
decorator::
@sensitive_post_parameters()
def my_view(request): ...
@ -379,5 +380,5 @@ within any given view by setting the ``HttpRequest``s
You can also set up custom error reporting by writing a custom piece of
:ref:`exception middleware <exception-middleware>`. If you do write custom
error handling, it's a good idea to emulate Django's built-in error handling
and only report/log errors if :setting:`DEBUG` is ``False``.
error handling, it's a good idea to emulate Django's built-in error
handling and only report/log errors if :setting:`DEBUG` is ``False``.

View File

@ -26,8 +26,8 @@ however, this data isn't loaded automatically, except if you use
A fixture is a collection of data that Django knows how to import into a
database. The most straightforward way of creating a fixture if you've already
got some data is to use the :djadmin:`manage.py dumpdata <dumpdata>` command.
Or, you can write fixtures by hand; fixtures can be written as JSON, XML or YAML
(with PyYAML_ installed) documents. The :doc:`serialization documentation
Or, you can write fixtures by hand; fixtures can be written as JSON, XML or
YAML (with PyYAML_ installed) documents. The :doc:`serialization documentation
</topics/serialization>` has more details about each of these supported
:ref:`serialization formats <serialization-formats>`.

View File

@ -44,8 +44,8 @@ Save this as a file by using standard Unix output redirection:
$ python manage.py inspectdb > models.py
This feature is meant as a shortcut, not as definitive model generation. See the
:djadmin:`documentation of inspectdb <inspectdb>` for more information.
This feature is meant as a shortcut, not as definitive model generation. See
the :djadmin:`documentation of inspectdb <inspectdb>` for more information.
Once you've cleaned up your models, name the file ``models.py`` and put it in
the Python package that holds your app. Then add the app to your

View File

@ -25,7 +25,7 @@ To send a log message from within your code, you place a logging call into it.
logging, use a view function as suggested in the example below.
First, import the Python logging library, and then obtain a logger instance
with :py:func:`logging.getLogger`. Provide the ``getLogger()`` method with a
with :func:`logging.getLogger`. Provide the ``getLogger()`` method with a
name to identify it and the records it emits. A good option is to use
``__name__`` (see :ref:`naming-loggers` below for more on this) which will
provide the name of the current Python module as a dotted path::
@ -43,7 +43,7 @@ And then in a function, for example in a view, send a record to the logger::
if some_risky_state:
logger.warning("Platform is running at risk")
When this code is executed, a :py:class:`~logging.LogRecord` containing that
When this code is executed, a :class:`~logging.LogRecord` containing that
message will be sent to the logger. If you're using Django's default logging
configuration, the message will appear in the console.
@ -129,7 +129,7 @@ file ``general.log`` (at the project root):
Different handler classes take different configuration options. For more
information on available handler classes, see the
:class:`~django.utils.log.AdminEmailHandler` provided by Django and the various
:py:mod:`handler classes <logging.handlers>` provided by Python.
:mod:`handler classes <logging.handlers>` provided by Python.
Logging levels can also be set on the handlers (by default, they accept log
messages of all levels). Using the example above, adding:
@ -238,7 +238,7 @@ application. A named logging configuration will capture logs only from loggers
with matching names.
The namespace of a logger instance is defined using
:py:func:`~logging.getLogger`. For example in ``views.py`` of ``my_app``::
:func:`~logging.getLogger`. For example in ``views.py`` of ``my_app``::
logger = logging.getLogger(__name__)

View File

@ -3,8 +3,8 @@ How to create CSV output
========================
This document explains how to output CSV (Comma Separated Values) dynamically
using Django views. To do this, you can either use the Python CSV library or the
Django template system.
using Django views. To do this, you can either use the Python CSV library or
the Django template system.
Using the Python CSV library
============================
@ -101,9 +101,10 @@ the assembly and transmission of a large CSV file::
Using the template system
=========================
Alternatively, you can use the :doc:`Django template system </topics/templates>`
to generate CSV. This is lower-level than using the convenient Python :mod:`csv`
module, but the solution is presented here for completeness.
Alternatively, you can use the :doc:`Django template system
</topics/templates>` to generate CSV. This is lower-level than using the
convenient Python :mod:`csv` module, but the solution is presented here for
completeness.
The idea here is to pass a list of items to your template, and have the
template output the commas in a :ttag:`for` loop.

View File

@ -87,8 +87,8 @@ mention:
browsers will handle the PDF using whatever program/plugin they've been
configured to use for PDFs.
* You can provide an arbitrary ``filename`` parameter. It'll be used by browsers
in the "Save as..." dialog.
* You can provide an arbitrary ``filename`` parameter. It'll be used by
browsers in the "Save as..." dialog.
* You can hook into the ReportLab API: The same buffer passed as the first
argument to ``canvas.Canvas`` can be fed to the
@ -112,8 +112,8 @@ Other formats
Notice that there isn't a lot in these examples that's PDF-specific -- just the
bits using ``reportlab``. You can use a similar technique to generate any
arbitrary format that you can find a Python library for. Also see
:doc:`/howto/outputting-csv` for another example and some techniques you can use
when generated text-based formats.
:doc:`/howto/outputting-csv` for another example and some techniques you can
use when generated text-based formats.
.. seealso::

View File

@ -63,7 +63,8 @@ in the ``templates`` directory, and add the template files to that folder:
The template loader first looks for templates in the ``DIRS`` directory. When
the views in the ``blog`` app ask for the ``blog/post.html`` and
``blog/list.html`` templates, the loader will return the files you just created.
``blog/list.html`` templates, the loader will return the files you just
created.
Overriding from an app's template directory
===========================================

View File

@ -3,7 +3,7 @@ How to manage static files (e.g. images, JavaScript, CSS)
=========================================================
Websites generally need to serve additional files such as images, JavaScript,
or CSS. In Django, we refer to these files as "static files". Django provides
or CSS. In Django, we refer to these files as "static files". Django provides
:mod:`django.contrib.staticfiles` to help you manage them.
This page describes how you can serve these static files.
@ -155,10 +155,10 @@ file-serving functionality: It doesn't know about the finders feature of the
collected under :setting:`STATIC_ROOT`.
Because of this, ``staticfiles`` ships its own
:class:`django.contrib.staticfiles.testing.StaticLiveServerTestCase`, a subclass
of the built-in one that has the ability to transparently serve all the assets
during execution of these tests in a way very similar to what we get at
development time with ``DEBUG = True``, i.e. without having to collect them
:class:`django.contrib.staticfiles.testing.StaticLiveServerTestCase`, a
subclass of the built-in one that has the ability to transparently serve all
the assets during execution of these tests in a way very similar to what we get
at development time with ``DEBUG = True``, i.e. without having to collect them
using :djadmin:`collectstatic` first.
Deployment

View File

@ -91,7 +91,8 @@ Once you're ready, it is time to :doc:`install the new Django version
is a major upgrade, you might want to set up a new environment with all the
dependencies first.
If you installed Django with pip_, you can use the ``--upgrade`` or ``-U`` flag:
If you installed Django with pip_, you can use the ``--upgrade`` or ``-U``
flag:
.. console::
@ -127,6 +128,6 @@ If you are using caching provided by Django, you should consider clearing your
cache after upgrading. Otherwise you may run into problems, for example, if you
are caching pickled objects as these objects are not guaranteed to be
pickle-compatible across Django versions. A past instance of incompatibility
was caching pickled :class:`~django.http.HttpResponse` objects, either
directly or indirectly via the :func:`~django.views.decorators.cache.cache_page`
was caching pickled :class:`~django.http.HttpResponse` objects, either directly
or indirectly via the :func:`~django.views.decorators.cache.cache_page`
decorator.

View File

@ -37,7 +37,7 @@ attribute::
migrations.RunPython(forwards),
]
You can also provide hints that will be passed to the :meth:`allow_migrate()`
You can also provide hints that will be passed to the :meth:`allow_migrate`
method of database routers as ``**hints``:
.. code-block:: python
@ -173,7 +173,8 @@ the respective field according to your needs.
migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
]
* Now you can apply the migrations as usual with the :djadmin:`migrate` command.
* Now you can apply the migrations as usual with the :djadmin:`migrate`
command.
Note there is a race condition if you allow objects to be created while this
migration is running. Objects created after the ``AddField`` and before
@ -197,7 +198,7 @@ a transaction by setting the ``atomic`` attribute to ``False``::
Within such a migration, all operations are run without a transaction. It's
possible to execute parts of the migration inside a transaction using
:func:`~django.db.transaction.atomic()` or by passing ``atomic=True`` to
:func:`~django.db.transaction.atomic` or by passing ``atomic=True`` to
``RunPython``.
Here's an example of a non-atomic data migration that updates a large table in
@ -277,12 +278,13 @@ Migrating data between third-party apps
You can use a data migration to move data from one third-party application to
another.
If you plan to remove the old app later, you'll need to set the ``dependencies``
property based on whether or not the old app is installed. Otherwise, you'll
have missing dependencies once you uninstall the old app. Similarly, you'll
need to catch :exc:`LookupError` in the ``apps.get_model()`` call that
retrieves models from the old app. This approach allows you to deploy your
project anywhere without first installing and then uninstalling the old app.
If you plan to remove the old app later, you'll need to set the
``dependencies`` property based on whether or not the old app is installed.
Otherwise, you'll have missing dependencies once you uninstall the old app.
Similarly, you'll need to catch :exc:`LookupError` in the ``apps.get_model()``
call that retrieves models from the old app. This approach allows you to deploy
your project anywhere without first installing and then uninstalling the old
app.
Here's a sample migration:

View File

@ -12,34 +12,34 @@ First steps
Are you new to Django or to programming? This is the place to start!
* **From scratch:**
:doc:`Overview <intro/overview>` |
:doc:`Installation <intro/install>`
:doc:`Overview </intro/overview>` |
:doc:`Installation </intro/install>`
* **Tutorial:**
:doc:`Part 1: Requests and responses <intro/tutorial01>` |
:doc:`Part 2: Models and the admin site <intro/tutorial02>` |
:doc:`Part 3: Views and templates <intro/tutorial03>` |
:doc:`Part 4: Forms and generic views <intro/tutorial04>` |
:doc:`Part 5: Testing <intro/tutorial05>` |
:doc:`Part 6: Static files <intro/tutorial06>` |
:doc:`Part 7: Customizing the admin site <intro/tutorial07>` |
:doc:`Part 8: Adding third-party packages <intro/tutorial08>`
:doc:`Part 1: Requests and responses </intro/tutorial01>` |
:doc:`Part 2: Models and the admin site </intro/tutorial02>` |
:doc:`Part 3: Views and templates </intro/tutorial03>` |
:doc:`Part 4: Forms and generic views </intro/tutorial04>` |
:doc:`Part 5: Testing </intro/tutorial05>` |
:doc:`Part 6: Static files </intro/tutorial06>` |
:doc:`Part 7: Customizing the admin site </intro/tutorial07>` |
:doc:`Part 8: Adding third-party packages </intro/tutorial08>`
* **Advanced Tutorials:**
:doc:`How to write reusable apps <intro/reusable-apps>` |
:doc:`Writing your first contribution to Django <intro/contributing>`
:doc:`How to write reusable apps </intro/reusable-apps>` |
:doc:`Writing your first contribution to Django </intro/contributing>`
Getting help
============
Having trouble? We'd like to help!
* Try the :doc:`FAQ <faq/index>` -- it's got answers to many common questions.
* Try the :doc:`FAQ </faq/index>` -- it's got answers to many common questions.
* Looking for specific information? Try the :ref:`genindex`, :ref:`modindex` or
the :doc:`detailed table of contents <contents>`.
the :doc:`detailed table of contents </contents>`.
* Not found anything? See :doc:`faq/help` for information on getting support
* Not found anything? See :doc:`/faq/help` for information on getting support
and asking questions to the community.
* Report bugs with Django in our `ticket tracker`_.
@ -74,46 +74,46 @@ Django provides an abstraction layer (the "models") for structuring and
manipulating the data of your web application. Learn more about it below:
* **Models:**
:doc:`Introduction to models <topics/db/models>` |
:doc:`Field types <ref/models/fields>` |
:doc:`Indexes <ref/models/indexes>` |
:doc:`Meta options <ref/models/options>` |
:doc:`Model class <ref/models/class>`
:doc:`Introduction to models </topics/db/models>` |
:doc:`Field types </ref/models/fields>` |
:doc:`Indexes </ref/models/indexes>` |
:doc:`Meta options </ref/models/options>` |
:doc:`Model class </ref/models/class>`
* **QuerySets:**
:doc:`Making queries <topics/db/queries>` |
:doc:`QuerySet method reference <ref/models/querysets>` |
:doc:`Lookup expressions <ref/models/lookups>`
:doc:`Making queries </topics/db/queries>` |
:doc:`QuerySet method reference </ref/models/querysets>` |
:doc:`Lookup expressions </ref/models/lookups>`
* **Model instances:**
:doc:`Instance methods <ref/models/instances>` |
:doc:`Accessing related objects <ref/models/relations>`
:doc:`Instance methods </ref/models/instances>` |
:doc:`Accessing related objects </ref/models/relations>`
* **Migrations:**
:doc:`Introduction to Migrations<topics/migrations>` |
:doc:`Operations reference <ref/migration-operations>` |
:doc:`SchemaEditor <ref/schema-editor>` |
:doc:`Writing migrations <howto/writing-migrations>`
:doc:`Introduction to Migrations</topics/migrations>` |
:doc:`Operations reference </ref/migration-operations>` |
:doc:`SchemaEditor </ref/schema-editor>` |
:doc:`Writing migrations </howto/writing-migrations>`
* **Advanced:**
:doc:`Managers <topics/db/managers>` |
:doc:`Raw SQL <topics/db/sql>` |
:doc:`Transactions <topics/db/transactions>` |
:doc:`Aggregation <topics/db/aggregation>` |
:doc:`Search <topics/db/search>` |
:doc:`Custom fields <howto/custom-model-fields>` |
:doc:`Multiple databases <topics/db/multi-db>` |
:doc:`Custom lookups <howto/custom-lookups>` |
:doc:`Query Expressions <ref/models/expressions>` |
:doc:`Conditional Expressions <ref/models/conditional-expressions>` |
:doc:`Database Functions <ref/models/database-functions>`
:doc:`Managers </topics/db/managers>` |
:doc:`Raw SQL </topics/db/sql>` |
:doc:`Transactions </topics/db/transactions>` |
:doc:`Aggregation </topics/db/aggregation>` |
:doc:`Search </topics/db/search>` |
:doc:`Custom fields </howto/custom-model-fields>` |
:doc:`Multiple databases </topics/db/multi-db>` |
:doc:`Custom lookups </howto/custom-lookups>` |
:doc:`Query Expressions </ref/models/expressions>` |
:doc:`Conditional Expressions </ref/models/conditional-expressions>` |
:doc:`Database Functions </ref/models/database-functions>`
* **Other:**
:doc:`Supported databases <ref/databases>` |
:doc:`Legacy databases <howto/legacy-databases>` |
:doc:`Providing initial data <howto/initial-data>` |
:doc:`Optimize database access <topics/db/optimization>` |
:doc:`PostgreSQL specific features <ref/contrib/postgres/index>`
:doc:`Supported databases </ref/databases>` |
:doc:`Legacy databases </howto/legacy-databases>` |
:doc:`Providing initial data </howto/initial-data>` |
:doc:`Optimize database access </topics/db/optimization>` |
:doc:`PostgreSQL specific features </ref/contrib/postgres/index>`
The view layer
==============
@ -123,39 +123,39 @@ processing a user's request and for returning the response. Find all you need
to know about views via the links below:
* **The basics:**
:doc:`URLconfs <topics/http/urls>` |
:doc:`View functions <topics/http/views>` |
:doc:`Shortcuts <topics/http/shortcuts>` |
:doc:`Decorators <topics/http/decorators>` |
:doc:`Asynchronous Support <topics/async>`
:doc:`URLconfs </topics/http/urls>` |
:doc:`View functions </topics/http/views>` |
:doc:`Shortcuts </topics/http/shortcuts>` |
:doc:`Decorators </topics/http/decorators>` |
:doc:`Asynchronous Support </topics/async>`
* **Reference:**
:doc:`Built-in Views <ref/views>` |
:doc:`Request/response objects <ref/request-response>` |
:doc:`TemplateResponse objects <ref/template-response>`
:doc:`Built-in Views </ref/views>` |
:doc:`Request/response objects </ref/request-response>` |
:doc:`TemplateResponse objects </ref/template-response>`
* **File uploads:**
:doc:`Overview <topics/http/file-uploads>` |
:doc:`File objects <ref/files/file>` |
:doc:`Storage API <ref/files/storage>` |
:doc:`Managing files <topics/files>` |
:doc:`Custom storage <howto/custom-file-storage>`
:doc:`Overview </topics/http/file-uploads>` |
:doc:`File objects </ref/files/file>` |
:doc:`Storage API </ref/files/storage>` |
:doc:`Managing files </topics/files>` |
:doc:`Custom storage </howto/custom-file-storage>`
* **Class-based views:**
:doc:`Overview <topics/class-based-views/index>` |
:doc:`Built-in display views <topics/class-based-views/generic-display>` |
:doc:`Built-in editing views <topics/class-based-views/generic-editing>` |
:doc:`Using mixins <topics/class-based-views/mixins>` |
:doc:`API reference <ref/class-based-views/index>` |
:doc:`Flattened index<ref/class-based-views/flattened-index>`
:doc:`Overview </topics/class-based-views/index>` |
:doc:`Built-in display views </topics/class-based-views/generic-display>` |
:doc:`Built-in editing views </topics/class-based-views/generic-editing>` |
:doc:`Using mixins </topics/class-based-views/mixins>` |
:doc:`API reference </ref/class-based-views/index>` |
:doc:`Flattened index </ref/class-based-views/flattened-index>`
* **Advanced:**
:doc:`Generating CSV <howto/outputting-csv>` |
:doc:`Generating PDF <howto/outputting-pdf>`
:doc:`Generating CSV </howto/outputting-csv>` |
:doc:`Generating PDF </howto/outputting-pdf>`
* **Middleware:**
:doc:`Overview <topics/http/middleware>` |
:doc:`Built-in middleware classes <ref/middleware>`
:doc:`Overview </topics/http/middleware>` |
:doc:`Built-in middleware classes </ref/middleware>`
The template layer
==================
@ -165,17 +165,17 @@ information to be presented to the user. Learn how this syntax can be used by
designers and how it can be extended by programmers:
* **The basics:**
:doc:`Overview <topics/templates>`
:doc:`Overview </topics/templates>`
* **For designers:**
:doc:`Language overview <ref/templates/language>` |
:doc:`Built-in tags and filters <ref/templates/builtins>` |
:doc:`Humanization <ref/contrib/humanize>`
:doc:`Language overview </ref/templates/language>` |
:doc:`Built-in tags and filters </ref/templates/builtins>` |
:doc:`Humanization </ref/contrib/humanize>`
* **For programmers:**
:doc:`Template API <ref/templates/api>` |
:doc:`Custom tags and filters <howto/custom-template-tags>` |
:doc:`Custom template backend <howto/custom-template-backend>`
:doc:`Template API </ref/templates/api>` |
:doc:`Custom tags and filters </howto/custom-template-tags>` |
:doc:`Custom template backend </howto/custom-template-backend>`
Forms
=====
@ -184,16 +184,16 @@ Django provides a rich framework to facilitate the creation of forms and the
manipulation of form data.
* **The basics:**
:doc:`Overview <topics/forms/index>` |
:doc:`Form API <ref/forms/api>` |
:doc:`Built-in fields <ref/forms/fields>` |
:doc:`Built-in widgets <ref/forms/widgets>`
:doc:`Overview </topics/forms/index>` |
:doc:`Form API </ref/forms/api>` |
:doc:`Built-in fields </ref/forms/fields>` |
:doc:`Built-in widgets </ref/forms/widgets>`
* **Advanced:**
:doc:`Forms for models <topics/forms/modelforms>` |
:doc:`Integrating media <topics/forms/media>` |
:doc:`Formsets <topics/forms/formsets>` |
:doc:`Customizing validation <ref/forms/validation>`
:doc:`Forms for models </topics/forms/modelforms>` |
:doc:`Integrating media </topics/forms/media>` |
:doc:`Formsets </topics/forms/formsets>` |
:doc:`Customizing validation </ref/forms/validation>`
The development process
=======================
@ -202,32 +202,32 @@ Learn about the various components and tools to help you in the development and
testing of Django applications:
* **Settings:**
:doc:`Overview <topics/settings>` |
:doc:`Full list of settings <ref/settings>`
:doc:`Overview </topics/settings>` |
:doc:`Full list of settings </ref/settings>`
* **Applications:**
:doc:`Overview <ref/applications>`
:doc:`Overview </ref/applications>`
* **Exceptions:**
:doc:`Overview <ref/exceptions>`
:doc:`Overview </ref/exceptions>`
* **django-admin and manage.py:**
:doc:`Overview <ref/django-admin>` |
:doc:`Adding custom commands <howto/custom-management-commands>`
:doc:`Overview </ref/django-admin>` |
:doc:`Adding custom commands </howto/custom-management-commands>`
* **Testing:**
:doc:`Introduction <topics/testing/index>` |
:doc:`Writing and running tests <topics/testing/overview>` |
:doc:`Included testing tools <topics/testing/tools>` |
:doc:`Advanced topics <topics/testing/advanced>`
:doc:`Introduction </topics/testing/index>` |
:doc:`Writing and running tests </topics/testing/overview>` |
:doc:`Included testing tools </topics/testing/tools>` |
:doc:`Advanced topics </topics/testing/advanced>`
* **Deployment:**
:doc:`Overview <howto/deployment/index>` |
:doc:`WSGI servers <howto/deployment/wsgi/index>` |
:doc:`ASGI servers <howto/deployment/asgi/index>` |
:doc:`Deploying static files <howto/static-files/deployment>` |
:doc:`Tracking code errors by email <howto/error-reporting>` |
:doc:`Deployment checklist <howto/deployment/checklist>`
:doc:`Overview </howto/deployment/index>` |
:doc:`WSGI servers </howto/deployment/wsgi/index>` |
:doc:`ASGI servers </howto/deployment/asgi/index>` |
:doc:`Deploying static files </howto/static-files/deployment>` |
:doc:`Tracking code errors by email </howto/error-reporting>` |
:doc:`Deployment checklist </howto/deployment/checklist>`
The admin
=========
@ -235,9 +235,9 @@ The admin
Find all you need to know about the automated admin interface, one of Django's
most popular features:
* :doc:`Admin site <ref/contrib/admin/index>`
* :doc:`Admin actions <ref/contrib/admin/actions>`
* :doc:`Admin documentation generator<ref/contrib/admin/admindocs>`
* :doc:`Admin site </ref/contrib/admin/index>`
* :doc:`Admin actions </ref/contrib/admin/actions>`
* :doc:`Admin documentation generator </ref/contrib/admin/admindocs>`
Security
========
@ -245,13 +245,13 @@ Security
Security is a topic of paramount importance in the development of web
applications and Django provides multiple protection tools and mechanisms:
* :doc:`Security overview <topics/security>`
* :doc:`Disclosed security issues in Django <releases/security>`
* :doc:`Clickjacking protection <ref/clickjacking>`
* :doc:`Cross Site Request Forgery protection <ref/csrf>`
* :doc:`Cryptographic signing <topics/signing>`
* :doc:`Security overview </topics/security>`
* :doc:`Disclosed security issues in Django </releases/security>`
* :doc:`Clickjacking protection </ref/clickjacking>`
* :doc:`Cross Site Request Forgery protection </ref/csrf>`
* :doc:`Cryptographic signing </topics/signing>`
* :ref:`Security Middleware <security-middleware>`
* :doc:`Content Security Policy <ref/csp>`
* :doc:`Content Security Policy </ref/csp>`
Internationalization and localization
=====================================
@ -260,10 +260,10 @@ Django offers a robust internationalization and localization framework to
assist you in the development of applications for multiple languages and world
regions:
* :doc:`Overview <topics/i18n/index>` |
:doc:`Internationalization <topics/i18n/translation>` |
* :doc:`Overview </topics/i18n/index>` |
:doc:`Internationalization </topics/i18n/translation>` |
:ref:`Localization <how-to-create-language-files>` |
:doc:`Localized web UI formatting and form input <topics/i18n/formatting>`
:doc:`Localized web UI formatting and form input </topics/i18n/formatting>`
* :doc:`Time zones </topics/i18n/timezones>`
Performance and optimization
@ -272,14 +272,14 @@ Performance and optimization
There are a variety of techniques and tools that can help get your code running
more efficiently - faster, and using fewer system resources.
* :doc:`Performance and optimization overview <topics/performance>`
* :doc:`Performance and optimization overview </topics/performance>`
Geographic framework
====================
:doc:`GeoDjango <ref/contrib/gis/index>` intends to be a world-class geographic
web framework. Its goal is to make it as easy as possible to build GIS web
applications and harness the power of spatially enabled data.
:doc:`GeoDjango </ref/contrib/gis/index>` intends to be a world-class
geographic web framework. Its goal is to make it as easy as possible to build
GIS web applications and harness the power of spatially enabled data.
Common web application tools
============================
@ -288,36 +288,36 @@ Django offers multiple tools commonly needed in the development of web
applications:
* **Authentication:**
:doc:`Overview <topics/auth/index>` |
:doc:`Using the authentication system <topics/auth/default>` |
:doc:`Password management <topics/auth/passwords>` |
:doc:`Customizing authentication <topics/auth/customizing>` |
:doc:`API Reference <ref/contrib/auth>`
* :doc:`Caching <topics/cache>`
* :doc:`Logging <topics/logging>`
* :doc:`Sending emails <topics/email>`
* :doc:`Syndication feeds (RSS/Atom) <ref/contrib/syndication>`
* :doc:`Pagination <topics/pagination>`
* :doc:`Messages framework <ref/contrib/messages>`
* :doc:`Serialization <topics/serialization>`
* :doc:`Sessions <topics/http/sessions>`
* :doc:`Sitemaps <ref/contrib/sitemaps>`
* :doc:`Static files management <ref/contrib/staticfiles>`
* :doc:`Data validation <ref/validators>`
:doc:`Overview </topics/auth/index>` |
:doc:`Using the authentication system </topics/auth/default>` |
:doc:`Password management </topics/auth/passwords>` |
:doc:`Customizing authentication </topics/auth/customizing>` |
:doc:`API Reference </ref/contrib/auth>`
* :doc:`Caching </topics/cache>`
* :doc:`Logging </topics/logging>`
* :doc:`Sending emails </topics/email>`
* :doc:`Syndication feeds (RSS/Atom) </ref/contrib/syndication>`
* :doc:`Pagination </topics/pagination>`
* :doc:`Messages framework </ref/contrib/messages>`
* :doc:`Serialization </topics/serialization>`
* :doc:`Sessions </topics/http/sessions>`
* :doc:`Sitemaps </ref/contrib/sitemaps>`
* :doc:`Static files management </ref/contrib/staticfiles>`
* :doc:`Data validation </ref/validators>`
Other core functionalities
==========================
Learn about some other core functionalities of the Django framework:
* :doc:`Conditional content processing <topics/conditional-view-processing>`
* :doc:`Content types and generic relations <ref/contrib/contenttypes>`
* :doc:`Flatpages <ref/contrib/flatpages>`
* :doc:`Redirects <ref/contrib/redirects>`
* :doc:`Signals <topics/signals>`
* :doc:`System check framework <topics/checks>`
* :doc:`The sites framework <ref/contrib/sites>`
* :doc:`Unicode in Django <ref/unicode>`
* :doc:`Conditional content processing </topics/conditional-view-processing>`
* :doc:`Content types and generic relations </ref/contrib/contenttypes>`
* :doc:`Flatpages </ref/contrib/flatpages>`
* :doc:`Redirects </ref/contrib/redirects>`
* :doc:`Signals </topics/signals>`
* :doc:`System check framework </topics/checks>`
* :doc:`The sites framework </ref/contrib/sites>`
* :doc:`Unicode in Django </ref/unicode>`
The Django open-source project
==============================
@ -326,23 +326,23 @@ Learn about the development process for the Django project itself and about how
you can contribute:
* **Community:**
:doc:`Contributing to Django <internals/contributing/index>` |
:doc:`The release process <internals/release-process>` |
:doc:`Team organization <internals/organization>` |
:doc:`The Django source code repository <internals/git>` |
:doc:`Security policies <internals/security>` |
:doc:`Mailing lists and Forum<internals/mailing-lists>`
:doc:`Contributing to Django </internals/contributing/index>` |
:doc:`The release process </internals/release-process>` |
:doc:`Team organization </internals/organization>` |
:doc:`The Django source code repository </internals/git>` |
:doc:`Security policies </internals/security>` |
:doc:`Mailing lists and Forum </internals/mailing-lists>`
* **Design philosophies:**
:doc:`Overview <misc/design-philosophies>`
:doc:`Overview </misc/design-philosophies>`
* **Documentation:**
:doc:`About this documentation <internals/contributing/writing-documentation>`
:doc:`About this documentation </internals/contributing/writing-documentation>`
* **Third-party distributions:**
:doc:`Overview <misc/distributions>`
:doc:`Overview </misc/distributions>`
* **Django over time:**
:doc:`API stability <misc/api-stability>` |
:doc:`Release notes and upgrading instructions <releases/index>` |
:doc:`Deprecation Timeline <internals/deprecation>`
:doc:`API stability </misc/api-stability>` |
:doc:`Release notes and upgrading instructions </releases/index>` |
:doc:`Deprecation Timeline </internals/deprecation>`

View File

@ -5,7 +5,7 @@ Reporting bugs and requesting features
.. Important::
Please report security issues **only** to
security@djangoproject.com. This is a private list only open to
security@djangoproject.com. This is a private list only open to
long-time, highly trusted Django developers, and its archives are
not public. For further details, please see :doc:`our security
policies </internals/security>`.
@ -55,7 +55,7 @@ particular:
as they are filed.
To understand the lifecycle of your ticket once you have created it, refer to
:doc:`triaging-tickets`.
:ref:`triage-workflow`.
Reporting user interface bugs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -4,7 +4,8 @@ Committing code
This section is addressed to the mergers and to anyone interested in knowing
how code gets committed into Django. If you're a community member who wants to
contribute code to Django, look at :doc:`writing-code/working-with-git` instead.
contribute code to Django, look at
:doc:`/internals/contributing/writing-code/working-with-git` instead.
.. _handling-pull-requests:

View File

@ -61,8 +61,8 @@ the date, time and numbers formatting particularities of your locale. See
The format files aren't managed by the use of Transifex. To change them, you
must:
* :doc:`Create a pull request<writing-code/submitting-patches>` against the
Django Git ``main`` branch, as for any code change.
* :ref:`Create a pull request <patch-review-checklist>` against the Django Git
``main`` branch, as for any code change.
* Open a ticket in Django's ticket system, set its ``Component`` field to
``Translations``, set the "has patch" flag, and include the link to the pull

View File

@ -47,14 +47,15 @@ Keep old patches up-to-date
Oftentimes the codebase will change between a patch being submitted and the
time it gets reviewed. Make sure it still applies cleanly and functions as
expected. Updating a patch is both useful and important! See more on
:doc:`writing-code/submitting-patches`.
:ref:`patch-review-checklist`.
Write some documentation
------------------------
Django's documentation is great but it can always be improved. Did you find a
typo? Do you think that something should be clarified? Go ahead and suggest a
documentation patch! See also the guide on :doc:`writing-documentation`.
documentation patch! See also the guide on
:doc:`/internals/contributing/writing-documentation`.
.. note::

View File

@ -29,11 +29,13 @@ confusion or disagreement.
Django is a community project, and every contribution helps. We can't do this
without **you**!
.. _triage-workflow:
Triage workflow
===============
Unfortunately, not all reports in the ticket tracker provide all the
:doc:`required details<bugs-and-features>`. A number of tickets have proposed
:ref:`required details <reporting-bugs>`. A number of tickets have proposed
solutions, but those don't necessarily meet all the requirements :ref:`adhering
to the guidelines for contributing <patch-style>`.
@ -168,8 +170,8 @@ Has patch
---------
This means the ticket has an associated solution. These will be reviewed to
ensure they adhere to the :doc:`documented guidelines
<writing-code/submitting-patches>`.
ensure they adhere to the :ref:`documented guidelines
<patch-review-checklist>`.
The following three fields (Needs documentation, Needs tests,
Patch needs improvement) apply only if a patch has been supplied.
@ -234,8 +236,11 @@ majority of tickets have a severity of "Normal".
Version
-------
It is possible to use the *version* attribute to indicate in which
version the reported bug was identified.
The *version* attribute indicates the earliest version in which the bug was
reproduced. During triage, this field can be updated, but there is no need to
make further updates when that version goes out of support. The field should
not be reset to "dev" to show the issue still exists: instead, the tested
commit hash can be noted in a comment.
UI/UX
-----
@ -350,8 +355,7 @@ Then, you can help out by:
"wontfix".
* Closing "Unreviewed" tickets as "needsinfo" when the description is too
sparse to be actionable, or when they're feature requests requiring a
discussion on the `Django Forum`_.
sparse to be actionable.
* Correcting the "Needs tests", "Needs documentation", or "Has patch"
flags for tickets where they are incorrectly set.
@ -383,7 +387,7 @@ Then, you can help out by:
several that are useful for triaging tickets and reviewing proposals as
suggested above.
You can also find more :doc:`new-contributors`.
You can also find more :doc:`/internals/contributing/new-contributors`.
.. _Reports page: https://code.djangoproject.com/wiki/Reports
@ -438,10 +442,10 @@ Next, we mark the current point in history as being "bad" since the test fails:
Now, we need to find a point in git history before the regression was
introduced (i.e. a point where the test passes). Use something like
``git checkout HEAD~100`` to check out an earlier revision (100 commits earlier,
in this case). Check if the test fails. If so, mark that point as "bad"
(``git bisect bad``), then check out an earlier revision and recheck. Once you
find a revision where your test passes, mark it as "good":
``git checkout HEAD~100`` to check out an earlier revision (100 commits
earlier, in this case). Check if the test fails. If so, mark that point as
"bad" (``git bisect bad``), then check out an earlier revision and recheck.
Once you find a revision where your test passes, mark it as "good":
.. code-block:: shell

View File

@ -46,11 +46,9 @@ Python style
* Unless otherwise specified, follow :pep:`8`.
Use :pypi:`flake8` to check for problems in this area. Note that our
``.flake8`` file contains some excluded files (deprecated modules we don't
care about cleaning up and some third-party code that Django vendors) as well
as some excluded errors that we don't consider as gross violations. Remember
that :pep:`8` is only a guide, so respect the style of the surrounding code
as a primary goal.
``.flake8`` file excludes some errors that we don't consider as gross
violations. Remember that :pep:`8` is only a guide, so respect the style of
the surrounding code as a primary goal.
An exception to :pep:`8` is our rules on line lengths. We allow up to 88
characters in code, as this is the line length used by ``black``.
@ -58,8 +56,8 @@ Python style
These limits are checked when ``flake8`` is run.
* String variable interpolation may use
:py:ref:`%-formatting <old-string-formatting>`, :py:ref:`f-strings
<f-strings>`, or :py:meth:`str.format` as appropriate, with the goal of
:ref:`%-formatting <old-string-formatting>`, :ref:`f-strings
<f-strings>`, or :meth:`str.format` as appropriate, with the goal of
maximizing code readability.
Final judgments of readability are left to the Merger's discretion. As a
@ -98,13 +96,12 @@ Python style
* In docstrings, follow the style of existing docstrings and :pep:`257`.
* In tests, use
:meth:`~django.test.SimpleTestCase.assertRaisesMessage` and
:meth:`~django.test.SimpleTestCase.assertWarnsMessage`
instead of :meth:`~unittest.TestCase.assertRaises` and
:meth:`~unittest.TestCase.assertWarns` so you can check the
exception or warning message. Use :meth:`~unittest.TestCase.assertRaisesRegex`
and :meth:`~unittest.TestCase.assertWarnsRegex` only if you need regular
* In tests, use :meth:`~django.test.SimpleTestCase.assertRaisesMessage` and
:meth:`~django.test.SimpleTestCase.assertWarnsMessage` instead of
:meth:`~unittest.TestCase.assertRaises` and
:meth:`~unittest.TestCase.assertWarns` so you can check the exception or
warning message. Use :meth:`~unittest.TestCase.assertRaisesRegex` and
:meth:`~unittest.TestCase.assertWarnsRegex` only if you need regular
expression matching.
Use :meth:`assertIs(…, True/False)<unittest.TestCase.assertIs>` for testing
@ -151,9 +148,10 @@ Imports
* Put imports in these groups: future, standard library, third-party libraries,
other Django components, local Django component, try/excepts. Sort lines in
each group alphabetically by the full module name. Place all ``import module``
statements before ``from module import objects`` in each section. Use absolute
imports for other Django components and relative imports for local components.
each group alphabetically by the full module name. Place all
``import module`` statements before ``from module import objects`` in each
section. Use absolute imports for other Django components and relative
imports for local components.
* On each line, alphabetize the items with the upper case items grouped before
the lowercase items.
@ -506,6 +504,6 @@ JavaScript style
================
For details about the JavaScript code style used by Django, see
:doc:`javascript`.
:doc:`/internals/contributing/writing-code/javascript`.
.. _editorconfig: https://editorconfig.org/

View File

@ -17,8 +17,8 @@ Code style
for indentation, but there are some exceptions.
* When naming variables, use ``camelCase`` instead of ``underscore_case``.
Different JavaScript files sometimes use a different code style. Please try to
conform to the code style of each file.
Different JavaScript files sometimes use a different code style. Please try
to conform to the code style of each file.
* Use the `ESLint`_ code linter to check your code for bugs and style errors.
ESLint will be run when you run the JavaScript tests. We also recommended
@ -89,8 +89,8 @@ The JavaScript tests may be run from a web browser or from the command line.
Testing from a web browser
~~~~~~~~~~~~~~~~~~~~~~~~~~
To run the tests from a web browser, open up :source:`js_tests/tests.html` in your
browser.
To run the tests from a web browser, open up :source:`js_tests/tests.html` in
your browser.
To measure code coverage when running the tests, you need to view that file
over HTTP. To view code coverage:

View File

@ -15,7 +15,8 @@ If you are fixing a really trivial issue, for example changing a word in the
documentation, the preferred way to provide the patch is using GitHub pull
requests without a Trac ticket.
See the :doc:`working-with-git` for more details on how to use pull requests.
See the :doc:`/internals/contributing/writing-code/working-with-git` for more
details on how to use pull requests.
"Claiming" tickets
==================
@ -109,19 +110,20 @@ requirements:
* The code required to fix a problem or add a feature is an essential part
of a solution, but it is not the only part. A good fix should also include a
:doc:`regression test <unit-tests>` to validate the behavior that has been
fixed and to prevent the problem from arising again. Also, if some tickets
are relevant to the code that you've written, mention the ticket numbers in
some comments in the test so that one can easily trace back the relevant
discussions after your patch gets committed, and the tickets get closed.
:doc:`regression test </internals/contributing/writing-code/unit-tests>` to
validate the behavior that has been fixed and to prevent the problem from
arising again. Also, if some tickets are relevant to the code that you've
written, mention the ticket numbers in some comments in the test so that one
can easily trace back the relevant discussions after your patch gets
committed, and the tickets get closed.
* If the code adds a new feature, or modifies the behavior of an existing
feature, the change should also contain documentation.
When you think your work is ready to be reviewed, send :doc:`a GitHub pull
request <working-with-git>`.
If you can't send a pull request for some reason, you can also use patches in
Trac. When using this style, follow these guidelines.
request </internals/contributing/writing-code/working-with-git>`. If you can't
send a pull request for some reason, you can also use patches in Trac. When
using this style, follow these guidelines.
* Submit patches in the format returned by the ``git diff`` command.
@ -204,9 +206,12 @@ whether to accept it.
Some examples of DEPs that have been approved and fully implemented:
* `DEP 181: ORM Expressions <https://github.com/django/deps/blob/main/final/0181-orm-expressions.rst>`_
* `DEP 182: Multiple Template Engines <https://github.com/django/deps/blob/main/final/0182-multiple-template-engines.rst>`_
* `DEP 201: Simplified routing syntax <https://github.com/django/deps/blob/main/final/0201-simplified-routing-syntax.rst>`_
* `DEP 181: ORM Expressions
<https://github.com/django/deps/blob/main/final/0181-orm-expressions.rst>`_
* `DEP 182: Multiple Template Engines
<https://github.com/django/deps/blob/main/final/0182-multiple-template-engines.rst>`_
* `DEP 201: Simplified routing syntax
<https://github.com/django/deps/blob/main/final/0201-simplified-routing-syntax.rst>`_
.. _Django Forum: https://forum.djangoproject.com/
.. _Django Enhancement Proposals: https://github.com/django/deps
@ -226,19 +231,19 @@ There are a couple of reasons that code in Django might be deprecated:
no longer needs to support the older version of Python that doesn't include
the library, the library will be deprecated in Django.
As the :ref:`deprecation policy<internal-release-deprecation-policy>` describes,
the first release of Django that deprecates a feature (``A.B``) should raise a
``RemovedInDjangoXXWarning`` (where XX is the Django version where the feature
will be removed) when the deprecated feature is invoked. Assuming we have good
test coverage, these warnings are converted to errors when :ref:`running the
test suite <running-unit-tests>` with warnings enabled:
As the :ref:`deprecation policy<internal-release-deprecation-policy>`
describes, the first release of Django that deprecates a feature (``A.B``)
should raise a ``RemovedInDjangoXXWarning`` (where XX is the Django version
where the feature will be removed) when the deprecated feature is invoked.
Assuming we have good test coverage, these warnings are converted to errors
when :ref:`running the test suite <running-unit-tests>` with warnings enabled:
``python -Wa runtests.py``. Thus, when adding a ``RemovedInDjangoXXWarning``
you need to eliminate or silence any warnings generated when running the tests.
The first step is to remove any use of the deprecated behavior by Django itself.
Next you can silence warnings in tests that actually test the deprecated
behavior by using the ``ignore_warnings`` decorator, either at the test or class
level:
The first step is to remove any use of the deprecated behavior by Django
itself. Next you can silence warnings in tests that actually test the
deprecated behavior by using the ``ignore_warnings`` decorator, either at the
test or class level:
#) In a particular test::
@ -305,8 +310,9 @@ Finally, there are a couple of updates to Django's documentation to make:
applicable, to the current release notes (``docs/releases/A.B.txt``) under
the "Features deprecated in A.B" heading.
#) Add an entry in the deprecation timeline (``docs/internals/deprecation.txt``)
under the appropriate version describing what code will be removed.
#) Add an entry in the deprecation timeline
(``docs/internals/deprecation.txt``) under the appropriate version
describing what code will be removed.
Once you have completed these steps, you are finished with the deprecation.
In each :term:`feature release <Feature release>`, all
@ -402,10 +408,10 @@ Bugs
* Is there a proper regression test (the test should fail before the fix
is applied)?
* If it's a bug that :ref:`qualifies for a backport <supported-versions-policy>`
to the stable version of Django, is there a release note in
``docs/releases/A.B.C.txt``? Bug fixes that will be applied only to the main
branch don't need a release note.
* If it's a bug that :ref:`qualifies for a backport
<supported-versions-policy>` to the stable version of Django, is there a
release note in ``docs/releases/A.B.C.txt``? Bug fixes that will be applied
only to the main branch don't need a release note.
New Features
------------

View File

@ -69,11 +69,11 @@ command from any place in the Django source tree:
$ tox
By default, ``tox`` runs the test suite with the bundled test settings file for
SQLite, ``black``, ``blacken-docs``, ``flake8``, ``isort``, and the
documentation spelling checker. In addition to the system dependencies noted
elsewhere in this documentation, the command ``python3`` must be on your path
and linked to the appropriate version of Python. A list of default environments
can be seen as follows:
SQLite, ``black``, ``blacken-docs``, ``flake8``, ``isort``, ``lint-docs`` and
the documentation spelling checker. In addition to the system dependencies
noted elsewhere in this documentation, the command ``python3`` must be on your
path and linked to the appropriate version of Python. A list of default
environments can be seen as follows:
.. console::
@ -84,6 +84,7 @@ can be seen as follows:
flake8>=3.7.0
docs
isort>=5.1.0
lint-docs
Testing other Python versions and database backends
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -398,9 +399,9 @@ and also excludes several directories not relevant to the results
Contrib apps
============
Tests for contrib apps can be found in the :source:`tests/` directory, typically
under ``<app_name>_tests``. For example, tests for ``contrib.auth`` are located
in :source:`tests/auth_tests`.
Tests for contrib apps can be found in the :source:`tests/` directory,
typically under ``<app_name>_tests``. For example, tests for ``contrib.auth``
are located in :source:`tests/auth_tests`.
.. _troubleshooting-unit-tests:

View File

@ -4,7 +4,7 @@ Working with Git and GitHub
This section explains how the community can contribute code to Django via pull
requests. If you're interested in how :ref:`mergers <mergers-team>` handle
them, see :doc:`../committing-code`.
them, see :ref:`handling-pull-requests`.
Below, we are going to show how to create a GitHub pull request containing the
changes for Trac ticket #xxxxx. By creating a fully-ready pull request, you
@ -142,7 +142,7 @@ When you think your work is ready to be pulled into Django, you should create
a pull request at GitHub. A good pull request means:
* commits with one logical change in each, following the
:doc:`coding style <coding-style>`,
:doc:`coding style </internals/contributing/writing-code/coding-style>`,
* well-formed messages for each commit: a summary line and then paragraphs
wrapped at 72 characters thereafter -- see the :ref:`committing guidelines

View File

@ -158,8 +158,9 @@ Documentation quality checks
----------------------------
Several checks help maintain Django's documentation quality, including
:ref:`spelling <documentation-spelling-check>` and
:ref:`code block formatting <documentation-code-block-format-check>`.
:ref:`spelling <documentation-spelling-check>`,
:ref:`code block formatting <documentation-code-block-format-check>`, and
:ref:`documentation style <documentation-lint-check>`.
These checks are run automatically in CI and must pass before documentation
changes can be merged. They can also be run locally with a single command:
@ -191,7 +192,7 @@ If you encounter false-positives (error output that actually is correct), do
one of the following:
* Surround inline code or brand/technology names with double grave accents
(``).
(\`\`)
* Find synonyms that the spell checker recognizes.
* If, and only if, you are sure the word you are using is correct - add it
to ``docs/spelling_wordlist`` (please keep the list in alphabetical order).
@ -205,8 +206,8 @@ All Python code blocks should be formatted using the :pypi:`blacken-docs`
auto-formatter. This is automatically run by the :ref:`pre-commit hook
<coding-style-pre-commit>` if configured.
The check can also be run manually: provided that ``blacken-docs`` is installed,
run the following command from the ``docs`` directory:
The check can also be run manually: provided that ``blacken-docs`` is
installed, run the following command from the ``docs`` directory:
.. console::
@ -215,6 +216,31 @@ run the following command from the ``docs`` directory:
The formatter will report any issues by printing them to the terminal and will
reformat code blocks where possible.
.. _documentation-lint-check:
Documentation lint check
~~~~~~~~~~~~~~~~~~~~~~~~
Django's documentation is checked for reStructuredText style and formal issues
using :pypi:`sphinx-lint`. This helps catch problems like stray tabs, trailing
whitespace, excessive line length, and similar formatting problems.
Once ``sphinx-lint`` is installed, the check can be run with the following
command from the ``docs`` directory:
.. console::
$ make lint
The command prints any violations to the terminal in the form
``path:line: message``. If problems are encountered:
* Read the message and fix the indicated issue (for example, remove trailing
whitespace, adjust backticks, or replace tabs with spaces).
* For long lines consider wrapping text onto new lines or breaking long inline
links into named references. The custom line length check should already skip
common false positives such as headings, tables and long links.
.. _documentation-link-check:
Link check
@ -245,8 +271,8 @@ Entries that have a status of "broken" need to be fixed. Those that have a
status of "redirected" may need to be updated to point to the canonical
location, e.g. the scheme has changed ``http://`` → ``https://``. In certain
cases, we do not want to update a "redirected" link, e.g. a rewrite to always
point to the latest or stable version of the documentation, e.g. ``/en/stable/`` →
``/en/3.2/``.
point to the latest or stable version of the documentation, e.g.
``/en/stable/`` → ``/en/3.2/``.
Writing style
=============
@ -523,12 +549,12 @@ General improvements or other changes to the APIs that should be emphasized
should use the "``.. versionchanged:: X.Y``" directive (with the same format
as the ``versionadded`` mentioned above.
These ``versionadded`` and ``versionchanged`` blocks should be "self-contained."
In other words, since we only keep these annotations around for two releases,
it's nice to be able to remove the annotation and its contents without having
to reflow, reindent, or edit the surrounding text. For example, instead of
putting the entire description of a new or changed feature in a block, do
something like this:
These ``versionadded`` and ``versionchanged`` blocks should be
"self-contained." In other words, since we only keep these annotations around
for two releases, it's nice to be able to remove the annotation and its
contents without having to reflow, reindent, or edit the surrounding text. For
example, instead of putting the entire description of a new or changed feature
in a block, do something like this:
.. code-block:: rst
@ -659,12 +685,12 @@ you'd like to help translate the documentation into another language.
``django-admin`` man page
=========================
Sphinx can generate a manual page for the
:doc:`django-admin </ref/django-admin>` command. This is configured in
``docs/conf.py``. Unlike other documentation output, this man page should be
included in the Django repository and the releases as
``docs/man/django-admin.1``. There isn't a need to update this file when
updating the documentation, as it's updated once as part of the release process.
Sphinx can generate a manual page for the :doc:`django-admin
</ref/django-admin>` command. This is configured in ``docs/conf.py``. Unlike
other documentation output, this man page should be included in the Django
repository and the releases as ``docs/man/django-admin.1``. There isn't a need
to update this file when updating the documentation, as it's updated once as
part of the release process.
To generate an updated version of the man page, in the ``docs`` directory, run:

View File

@ -64,9 +64,9 @@ details on these changes.
* The ``all`` keyword argument of ``django.contrib.staticfiles.finders.find()``
will be removed.
* The fallback to ``request.user`` when ``user`` is ``None`` in
``django.contrib.auth.login()`` and ``django.contrib.auth.alogin()`` will be
removed.
* Fallbacks to ``request.user`` and ``request.auser()`` when ``user`` is
``None`` in ``django.contrib.auth.login()`` and
``django.contrib.auth.alogin()``, respectively, will be removed.
* The ``ordering`` keyword argument of the PostgreSQL specific aggregation
functions ``django.contrib.postgres.aggregates.ArrayAgg``,
@ -742,12 +742,12 @@ details on these changes.
* The ability to use a dotted Python path for the ``LOGIN_URL`` and
``LOGIN_REDIRECT_URL`` settings will be removed.
* Support for :py:mod:`optparse` will be dropped for custom management commands
(replaced by :py:mod:`argparse`).
* Support for :mod:`optparse` will be dropped for custom management commands
(replaced by :mod:`argparse`).
* The class ``django.core.management.NoArgsCommand`` will be removed. Use
:class:`~django.core.management.BaseCommand` instead, which takes no arguments
by default.
:class:`~django.core.management.BaseCommand` instead, which takes no
arguments by default.
* ``django.core.context_processors`` module will be removed.
@ -777,7 +777,8 @@ details on these changes.
* ``get_all_related_many_to_many_objects()``
* ``get_all_related_m2m_objects_with_model()``
* The ``error_message`` argument of ``django.forms.RegexField`` will be removed.
* The ``error_message`` argument of ``django.forms.RegexField`` will be
removed.
* The ``unordered_list`` filter will no longer support old style lists.
@ -803,7 +804,8 @@ details on these changes.
``django.contrib.admin.helpers.InlineAdminForm`` will be removed.
* The backwards compatibility shim to allow ``FormMixin.get_form()`` to be
defined with no default value for its ``form_class`` argument will be removed.
defined with no default value for its ``form_class`` argument will be
removed.
* The following settings will be removed:
@ -821,7 +823,7 @@ details on these changes.
:func:`~django.template.loader.get_template` and
:func:`~django.template.loader.select_template` won't accept a
:class:`~django.template.Context` in their
:meth:`~django.template.backends.base.Template.render()` method anymore.
:meth:`~django.template.backends.base.Template.render` method anymore.
* :doc:`Template response APIs </ref/template-response>` will enforce the use
of :class:`dict` and backend-dependent template objects instead of
@ -870,14 +872,14 @@ details on these changes.
* Support for the legacy ``%(<foo>)s`` syntax in ``ModelFormMixin.success_url``
will be removed.
* ``GeoQuerySet`` aggregate methods ``collect()``, ``extent()``, ``extent3d()``,
``make_line()``, and ``unionagg()`` will be removed.
* ``GeoQuerySet`` aggregate methods ``collect()``, ``extent()``,
``extent3d()``, ``make_line()``, and ``unionagg()`` will be removed.
* Ability to specify ``ContentType.name`` when creating a content type instance
will be removed.
* Support for the old signature of ``allow_migrate`` will be removed. It changed
from ``allow_migrate(self, db, model)`` to
* Support for the old signature of ``allow_migrate`` will be removed. It
changed from ``allow_migrate(self, db, model)`` to
``allow_migrate(self, db, app_label, model_name=None, **hints)``.
* Support for the syntax of ``{% cycle %}`` that uses comma-separated arguments
@ -1000,8 +1002,8 @@ details on these changes.
* ``django.utils.module_loading.import_by_path`` will be removed in favor of
``django.utils.module_loading.import_string``.
* ``ssi`` and ``url`` template tags will be removed from the ``future`` template
tag library (used during the 1.3/1.4 deprecation period).
* ``ssi`` and ``url`` template tags will be removed from the ``future``
template tag library (used during the 1.3/1.4 deprecation period).
* ``django.utils.text.javascript_quote`` will be removed.
@ -1011,9 +1013,9 @@ details on these changes.
* The ``cache_choices`` option to :class:`~django.forms.ModelChoiceField` and
:class:`~django.forms.ModelMultipleChoiceField` will be removed.
* The default value of the
:attr:`RedirectView.permanent <django.views.generic.base.RedirectView.permanent>`
attribute will change from ``True`` to ``False``.
* The default value of the :attr:`RedirectView.permanent
<django.views.generic.base.RedirectView.permanent>` attribute will change
from ``True`` to ``False``.
* ``django.contrib.sitemaps.FlatPageSitemap`` will be removed in favor of
``django.contrib.flatpages.sitemaps.FlatPageSitemap``.
@ -1096,8 +1098,8 @@ details on these changes.
* The ``CACHE_MIDDLEWARE_ANONYMOUS_ONLY`` setting will be removed.
* Usage of the hardcoded *Hold down "Control", or "Command" on a Mac, to select
more than one.* string to override or append to user-provided ``help_text`` in
forms for ManyToMany model fields will not be performed by Django anymore
more than one.* string to override or append to user-provided ``help_text``
in forms for ManyToMany model fields will not be performed by Django anymore
either at the model or forms layer.
* The ``Model._meta.get_(add|change|delete)_permission`` methods will
@ -1110,8 +1112,9 @@ details on these changes.
(``django.contrib.gis.sitemaps.views.index`` and
``django.contrib.gis.sitemaps.views.sitemap``).
* ``django.utils.html.fix_ampersands``, the ``fix_ampersands`` template filter and
``django.utils.html.clean_html`` will be removed following an accelerated deprecation.
* ``django.utils.html.fix_ampersands``, the ``fix_ampersands`` template filter
and ``django.utils.html.clean_html`` will be removed following an accelerated
deprecation.
.. _deprecation-removed-in-1.7:
@ -1238,9 +1241,8 @@ details on these changes.
``django.contrib.gis.utils`` will be removed.
* ``django.conf.urls.defaults`` will be removed. The functions
``include()``, ``patterns()``, and ``url()``, plus
:data:`~django.conf.urls.handler404` and :data:`~django.conf.urls.handler500`
are now available through ``django.conf.urls``.
``include()``, ``patterns()``, and ``url()``, plus ``handler404` and
``handler500`` are now available through ``django.conf.urls``.
* The functions ``setup_environ()`` and ``execute_manager()`` will be removed
from :mod:`django.core.management`. This also means that the old (pre-1.4)
@ -1249,8 +1251,8 @@ details on these changes.
* Setting the ``is_safe`` and ``needs_autoescape`` flags as attributes of
template filter functions will no longer be supported.
* The attribute ``HttpRequest.raw_post_data`` was renamed to ``HttpRequest.body``
in 1.4. The backward compatibility will be removed --
* The attribute ``HttpRequest.raw_post_data`` was renamed to
``HttpRequest.body`` in 1.4. The backward compatibility will be removed --
``HttpRequest.raw_post_data`` will no longer work.
* The value for the ``post_url_continue`` parameter in
@ -1293,7 +1295,7 @@ details on these changes.
</topics/class-based-views/index>`.
* The ``django.core.servers.basehttp.AdminMediaHandler`` will be
removed. In its place use
removed. In its place use
``django.contrib.staticfiles.handlers.StaticFilesHandler``.
* The template tags library ``adminmedia`` and the template tag ``{%
@ -1335,10 +1337,10 @@ details on these changes.
performance issues and will follow a slightly accelerated deprecation
timeframe.
* Translations located under the so-called *project path* will be ignored during
the translation building process performed at runtime. The
:setting:`LOCALE_PATHS` setting can be used for the same task by including the
filesystem path to a ``locale`` directory containing non-app-specific
* Translations located under the so-called *project path* will be ignored
during the translation building process performed at runtime. The
:setting:`LOCALE_PATHS` setting can be used for the same task by including
the filesystem path to a ``locale`` directory containing non-app-specific
translations in its value.
* The Markup contrib app will no longer support versions of Python-Markdown
@ -1356,7 +1358,7 @@ details on these changes.
See the :ref:`Django 1.2 release notes<deprecated-features-1.2>` for more
details on these changes.
* ``CsrfResponseMiddleware`` and ``CsrfMiddleware`` will be removed. Use
* ``CsrfResponseMiddleware`` and ``CsrfMiddleware`` will be removed. Use
the ``{% csrf_token %}`` template tag inside forms to enable CSRF
protection. ``CsrfViewMiddleware`` remains and is enabled by default.
@ -1384,7 +1386,7 @@ details on these changes.
* The ``Message`` model (in ``django.contrib.auth``), its related
manager in the ``User`` model (``user.message_set``), and the
associated methods (``user.message_set.create()`` and
``user.get_and_delete_messages()``), will be removed. The
``user.get_and_delete_messages()``), will be removed. The
:doc:`messages framework </ref/contrib/messages>` should be used
instead. The related ``messages`` variable returned by the
auth context processor will also be removed. Note that this
@ -1396,7 +1398,7 @@ details on these changes.
will no longer be checked and can be removed from custom backends.
* Authentication backends will need to support the ``AnonymousUser`` class
being passed to all methods dealing with permissions. The
being passed to all methods dealing with permissions. The
``supports_anonymous_user`` variable will no longer be checked and can be
removed from custom backends.
@ -1423,7 +1425,7 @@ details on these changes.
``django.contrib.syndication`` will be removed. The class-based view
``views.Feed`` should be used instead.
* ``django.core.context_processors.auth``. This release will
* ``django.core.context_processors.auth``. This release will
remove the old method in favor of the new method in
``django.contrib.auth.context_processors.auth``.
@ -1454,7 +1456,7 @@ details on these changes.
See the :ref:`Django 1.1 release notes<deprecated-features-1.1>` for more
details on these changes.
* ``AdminSite.root()``. This method of hooking up the admin URLs will be
* ``AdminSite.root()``. This method of hooking up the admin URLs will be
removed in favor of including ``admin.site.urls``.
* Authentication backends need to define the boolean attributes

View File

@ -115,11 +115,11 @@ updates.
committed until the final release happened.
For example, shortly after the release of Django 1.3 the branch
``stable/1.3.x`` was created. Official support for that release has expired,
and so it no longer receives direct maintenance from the Django project.
However, that and all other similarly named branches continue to exist, and
interested community members have occasionally used them to provide
unofficial support for old Django releases.
``stable/1.3.x`` was created. Official support for that release has
expired, and so it no longer receives direct maintenance from the Django
project. However, that and all other similarly named branches continue to
exist, and interested community members have occasionally used them to
provide unofficial support for old Django releases.
Tags
====

View File

@ -471,7 +471,8 @@ Building the artifacts
.. admonition:: Optionally use helper scripts
You can streamline some of the steps below using helper scripts from the Wiki:
You can streamline some of the steps below using helper scripts from the
Wiki:
* `Release script
<https://code.djangoproject.com/wiki/ReleaseScript>`_

View File

@ -5,7 +5,7 @@ Mailing lists and Forum
.. Important::
Please report security issues **only** to
security@djangoproject.com. This is a private list only open to
security@djangoproject.com. This is a private list only open to
long-time, highly trusted Django developers, and its archives are
not public. For further details, please see :doc:`our security
policies </internals/security>`.

View File

@ -72,9 +72,9 @@ to make the role of Merger sustainable.
The following restrictions apply to the role of Merger:
- A person must not simultaneously serve as a member of the steering council. If
a Merger is elected to the steering council, they shall cease to be a Merger
immediately upon taking up membership in the steering council.
- A person must not simultaneously serve as a member of the steering council.
If a Merger is elected to the steering council, they shall cease to be a
Merger immediately upon taking up membership in the steering council.
- A person may serve in the roles of Releaser and Merger simultaneously.
The selection process, when a vacancy occurs or when the steering council deems
@ -122,10 +122,10 @@ upload them to the :pypi:`Python Package Index <Django>` and to the
Membership
----------
`The steering council`_ selects Releasers_ as necessary to maintain their number
at a minimum of three, in order to spread the workload and avoid over-burdening
or burning out any individual Releaser. There is no upper limit to the number
of Releasers.
`The steering council`_ selects Releasers_ as necessary to maintain their
number at a minimum of three, in order to spread the workload and avoid
over-burdening or burning out any individual Releaser. There is no upper limit
to the number of Releasers.
It's not a requirement that a Releaser is also a Django Fellow, but the Django
Software Foundation has the power to use funding of Fellow positions as a way
@ -223,13 +223,14 @@ who demonstrate:
years must still demonstrate an understanding of Django's changes and
direction within those three years.
A new council is elected after each release cycle of Django. The election process
works as follows:
A new council is elected after each release cycle of Django. The election
process works as follows:
#. The steering council directs one of its members to notify the Secretary of the
Django Software Foundation, in writing, of the triggering of the election,
and the condition which triggered it. The Secretary post to the appropriate
venue -- the `Django Forum`_ to announce the election and its timeline.
#. The steering council directs one of its members to notify the Secretary of
the Django Software Foundation, in writing, of the triggering of the
election, and the condition which triggered it. The Secretary post to the
appropriate venue -- the `Django Forum`_ to announce the election and its
timeline.
#. As soon as the election is announced, the `DSF Board`_ begin a period of
voter registration. All `individual members of the DSF`_ are automatically
registered and need not explicitly register. All other persons who believe
@ -267,12 +268,12 @@ A member of the steering council may be removed by:
- Becoming disqualified due to actions taken by the Code of Conduct committee
of the Django Software Foundation.
- Determining that they did not possess the qualifications of a member of the
steering council. This determination must be made jointly by the other members
of the steering council, and the `DSF Board`_. A valid determination of
ineligibility requires that all other members of the steering council and all
members of the DSF Board vote who can vote on the issue (the affected person,
if a DSF Board member, must not vote) vote "yes" on a motion that the person
in question is ineligible.
steering council. This determination must be made jointly by the other
members of the steering council, and the `DSF Board`_. A valid determination
of ineligibility requires that all other members of the steering council and
all members of the DSF Board vote who can vote on the issue (the affected
person, if a DSF Board member, must not vote) vote "yes" on a motion that the
person in question is ineligible.
.. _`Django Forum`: https://forum.djangoproject.com/
.. _`Django Git repository`: https://github.com/django/django/

View File

@ -31,7 +31,8 @@ own branch, called ``stable/A.B.x``, and bugfix/security releases will be
issued from those branches.
For more information about how the Django project issues new releases for
security purposes, please see :doc:`our security policies <security>`.
security purposes, please see :doc:`our security policies
</internals/security>`.
.. glossary::
@ -45,8 +46,8 @@ security purposes, please see :doc:`our security policies <security>`.
bugs and/or security issues.
These releases will be 100% compatible with the associated feature release,
unless this is impossible for security reasons or to prevent data loss.
So the answer to "should I upgrade to the latest patch release?" will always
unless this is impossible for security reasons or to prevent data loss. So
the answer to "should I upgrade to the latest patch release?" will always
be "yes."
Long-term support release
@ -123,8 +124,8 @@ See also the :ref:`deprecating-a-feature` guide.
Supported versions
==================
At any moment in time, Django's developer team will support a set of releases to
varying levels. See `the supported versions section
At any moment in time, Django's developer team will support a set of releases
to varying levels. See `the supported versions section
<https://www.djangoproject.com/download/#supported-versions>`_ of the download
page for the current state of support for each version.

View File

@ -292,7 +292,8 @@ requires a security release:
* Exploits which fail to follow security best practices, such as failure to
sanitize user input. For other examples, see our :ref:`security
documentation <cross-site-scripting>`.
* Exploits in AI generated code that do not adhere to security best practices.
* Exploits in AI generated code that do not adhere to security best
practices.
The security team may conclude that the source of the vulnerability is within
the Python standard library, in which case the reporter will be asked to report
@ -303,8 +304,8 @@ On occasion, a security release may be issued to help resolve a security
vulnerability within a popular third-party package. These reports should come
from the package maintainers.
If you are unsure whether your finding meets these criteria, please still report
it :ref:`privately by emailing security@djangoproject.com
If you are unsure whether your finding meets these criteria, please still
report it :ref:`privately by emailing security@djangoproject.com
<reporting-security-issues>`. The security team will review your report and
recommend the correct course of action.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Some files were not shown because too many files have changed in this diff Show More