Fixed #34140 -- Reformatted code blocks in docs with blacken-docs.

This commit is contained in:
django-bot 2023-02-28 20:53:28 +01:00 committed by Mariusz Felisiak
parent 6015bab80e
commit 14459f80ee
193 changed files with 5797 additions and 4481 deletions

View file

@ -33,10 +33,10 @@ First, you must add the
:class:`django.contrib.auth.middleware.AuthenticationMiddleware`::
MIDDLEWARE = [
'...',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.RemoteUserMiddleware',
'...',
"...",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.auth.middleware.RemoteUserMiddleware",
"...",
]
Next, you must replace the :class:`~django.contrib.auth.backends.ModelBackend`
@ -44,7 +44,7 @@ with :class:`~django.contrib.auth.backends.RemoteUserBackend` in the
:setting:`AUTHENTICATION_BACKENDS` setting::
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.RemoteUserBackend',
"django.contrib.auth.backends.RemoteUserBackend",
]
With this setup, ``RemoteUserMiddleware`` will detect the username in
@ -81,8 +81,9 @@ If your authentication mechanism uses a custom HTTP header and not
from django.contrib.auth.middleware import RemoteUserMiddleware
class CustomHeaderMiddleware(RemoteUserMiddleware):
header = 'HTTP_AUTHUSER'
header = "HTTP_AUTHUSER"
.. warning::

View file

@ -205,6 +205,7 @@ will require a CSRF token to be inserted you should use the
from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_protect
@cache_page(60 * 15)
@csrf_protect
def my_view(request):
@ -280,17 +281,17 @@ path within it that needs protection. Example::
from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_exempt
def my_view(request):
@csrf_protect
def protected_path(request):
do_something()
if some_condition():
return protected_path(request)
return protected_path(request)
else:
do_something_else()
do_something_else()
Protecting a page that uses AJAX without an HTML form
-----------------------------------------------------

View file

@ -13,6 +13,7 @@ You'll need to follow these steps:
from django.core.files.storage import Storage
class MyStorage(Storage):
...
@ -22,6 +23,7 @@ You'll need to follow these steps:
from django.conf import settings
from django.core.files.storage import Storage
class MyStorage(Storage):
def __init__(self, option=None):
if not option:
@ -135,4 +137,5 @@ Storages are then accessed by alias from from the
:data:`django.core.files.storage.storages` dictionary::
from django.core.files.storage import storages
example_storage = storages["example"]

View file

@ -28,14 +28,15 @@ lookup, then we need to tell Django about it::
from django.db.models import Lookup
class NotEqual(Lookup):
lookup_name = 'ne'
lookup_name = "ne"
def as_sql(self, compiler, connection):
lhs, lhs_params = self.process_lhs(compiler, connection)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = lhs_params + rhs_params
return '%s <> %s' % (lhs, rhs), params
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
@ -43,12 +44,14 @@ makes sense on all ``Field`` subclasses, so we register it with ``Field``
directly::
from django.db.models import Field
Field.register_lookup(NotEqual)
Lookup registration can also be done using a decorator pattern::
from django.db.models import Field
@Field.register_lookup
class NotEqualLookup(Lookup):
...
@ -115,13 +118,15 @@ function ``ABS()`` to transform the value before comparison::
from django.db.models import Transform
class AbsoluteValue(Transform):
lookup_name = 'abs'
function = 'ABS'
lookup_name = "abs"
function = "ABS"
Next, let's register it for ``IntegerField``::
from django.db.models import IntegerField
IntegerField.register_lookup(AbsoluteValue)
We can now run the queries we had before.
@ -167,9 +172,10 @@ be done by adding an ``output_field`` attribute to the transform::
from django.db.models import FloatField, Transform
class AbsoluteValue(Transform):
lookup_name = 'abs'
function = 'ABS'
lookup_name = "abs"
function = "ABS"
@property
def output_field(self):
@ -197,14 +203,16 @@ The implementation is::
from django.db.models import Lookup
class AbsoluteValueLessThan(Lookup):
lookup_name = 'lt'
lookup_name = "lt"
def as_sql(self, compiler, connection):
lhs, lhs_params = compiler.compile(self.lhs.lhs)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = lhs_params + rhs_params + lhs_params + rhs_params
return '%s < %s AND %s > -%s' % (lhs, rhs, lhs, rhs), params
return "%s < %s AND %s > -%s" % (lhs, rhs, lhs, rhs), params
AbsoluteValue.register_lookup(AbsoluteValueLessThan)
@ -252,14 +260,16 @@ this transformation should apply to both ``lhs`` and ``rhs``::
from django.db.models import Transform
class UpperCase(Transform):
lookup_name = 'upper'
function = 'UPPER'
lookup_name = "upper"
function = "UPPER"
bilateral = True
Next, let's register it::
from django.db.models import CharField, TextField
CharField.register_lookup(UpperCase)
TextField.register_lookup(UpperCase)
@ -287,7 +297,8 @@ We can change the behavior on a specific backend by creating a subclass of
lhs, lhs_params = self.process_lhs(compiler, connection)
rhs, rhs_params = self.process_rhs(compiler, connection)
params = lhs_params + rhs_params
return '%s != %s' % (lhs, rhs), params
return "%s != %s" % (lhs, rhs), params
Field.register_lookup(MySQLNotEqual)
@ -310,7 +321,7 @@ would override ``get_lookup`` with something like::
class CoordinatesField(Field):
def get_lookup(self, lookup_name):
if lookup_name.startswith('x'):
if lookup_name.startswith("x"):
try:
dimension = int(lookup_name.removeprefix("x"))
except ValueError:

View file

@ -49,14 +49,15 @@ look like this::
from django.core.management.base import BaseCommand, CommandError
from polls.models import Question as Poll
class Command(BaseCommand):
help = 'Closes the specified poll for voting'
help = "Closes the specified poll for voting"
def add_arguments(self, parser):
parser.add_argument('poll_ids', nargs='+', type=int)
parser.add_argument("poll_ids", nargs="+", type=int)
def handle(self, *args, **options):
for poll_id in options['poll_ids']:
for poll_id in options["poll_ids"]:
try:
poll = Poll.objects.get(pk=poll_id)
except Poll.DoesNotExist:
@ -65,7 +66,9 @@ look like this::
poll.opened = False
poll.save()
self.stdout.write(self.style.SUCCESS('Successfully closed poll "%s"' % poll_id))
self.stdout.write(
self.style.SUCCESS('Successfully closed poll "%s"' % poll_id)
)
.. _management-commands-output:
@ -78,7 +81,7 @@ look like this::
character, it will be added automatically, unless you specify the ``ending``
parameter::
self.stdout.write("Unterminated line", ending='')
self.stdout.write("Unterminated line", ending="")
The new custom command can be called using ``python manage.py closepoll
<poll_ids>``.
@ -101,18 +104,18 @@ options can be added in the :meth:`~BaseCommand.add_arguments` method like this:
class Command(BaseCommand):
def add_arguments(self, parser):
# Positional arguments
parser.add_argument('poll_ids', nargs='+', type=int)
parser.add_argument("poll_ids", nargs="+", type=int)
# Named (optional) arguments
parser.add_argument(
'--delete',
action='store_true',
help='Delete poll instead of closing it',
"--delete",
action="store_true",
help="Delete poll instead of closing it",
)
def handle(self, *args, **options):
# ...
if options['delete']:
if options["delete"]:
poll.delete()
# ...
@ -138,6 +141,7 @@ decorator on your :meth:`~BaseCommand.handle` method::
from django.core.management.base import BaseCommand, no_translations
class Command(BaseCommand):
...
@ -230,7 +234,7 @@ All attributes can be set in your derived class and can be used in
An instance attribute that helps create colored output when writing to
``stdout`` or ``stderr``. For example::
self.stdout.write(self.style.SUCCESS('...'))
self.stdout.write(self.style.SUCCESS("..."))
See :ref:`syntax-coloring` to learn how to modify the color palette and to
see the available styles (use uppercased versions of the "roles" described

View file

@ -162,12 +162,12 @@ behave like any existing field, so we'll subclass directly from
from django.db import models
class HandField(models.Field):
class HandField(models.Field):
description = "A hand of cards (bridge style)"
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 104
kwargs["max_length"] = 104
super().__init__(*args, **kwargs)
Our ``HandField`` accepts most of the standard field options (see the list
@ -259,10 +259,10 @@ we can drop it from the keyword arguments for readability::
from django.db import models
class HandField(models.Field):
class HandField(models.Field):
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 104
kwargs["max_length"] = 104
super().__init__(*args, **kwargs)
def deconstruct(self):
@ -277,6 +277,7 @@ such as when the default value is being used::
from django.db import models
class CommaSepField(models.Field):
"Implements comma-separated storage of lists"
@ -288,7 +289,7 @@ such as when the default value is being used::
name, path, args, kwargs = super().deconstruct()
# Only include kwarg if it's not the default
if self.separator != ",":
kwargs['separator'] = self.separator
kwargs["separator"] = self.separator
return name, path, args, kwargs
More complex examples are beyond the scope of this document, but remember -
@ -326,7 +327,6 @@ no-op ``AlterField`` operations.
For example::
class CommaSepField(models.Field):
@property
def non_db_attrs(self):
return super().non_db_attrs + ("separator",)
@ -353,6 +353,7 @@ reference it::
class CustomCharField(models.CharField):
...
class CustomTextField(models.TextField):
...
@ -397,9 +398,10 @@ subclass ``Field`` and implement the :meth:`~Field.db_type` method, like so::
from django.db import models
class MytypeField(models.Field):
def db_type(self, connection):
return 'mytype'
return "mytype"
Once you have ``MytypeField``, you can use it in any model, just like any other
``Field`` type::
@ -419,10 +421,10 @@ For example::
class MyDateField(models.Field):
def db_type(self, connection):
if connection.vendor == 'mysql':
return 'datetime'
if connection.vendor == "mysql":
return "datetime"
else:
return 'timestamp'
return "timestamp"
The :meth:`~Field.db_type` and :meth:`~Field.rel_db_type` methods are called by
Django when the framework constructs the ``CREATE TABLE`` statements for your
@ -442,7 +444,8 @@ sense to have a ``CharMaxlength25Field``, shown here::
# This is a silly example of hard-coded parameters.
class CharMaxlength25Field(models.Field):
def db_type(self, connection):
return 'char(25)'
return "char(25)"
# In the model:
class MyModel(models.Model):
@ -460,7 +463,8 @@ time -- i.e., when the class is instantiated. To do that, implement
super().__init__(*args, **kwargs)
def db_type(self, connection):
return 'char(%s)' % self.max_length
return "char(%s)" % self.max_length
# In the model:
class MyModel(models.Model):
@ -481,10 +485,10 @@ 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):
def db_type(self, connection):
return 'integer UNSIGNED AUTO_INCREMENT'
return "integer UNSIGNED AUTO_INCREMENT"
def rel_db_type(self, connection):
return 'integer UNSIGNED'
return "integer UNSIGNED"
.. _converting-values-to-python-objects:
@ -522,15 +526,17 @@ instances::
from django.db import models
from django.utils.translation import gettext_lazy as _
def parse_hand(hand_string):
"""Takes a string of cards and splits into a full hand."""
p1 = re.compile('.{26}')
p2 = re.compile('..')
p1 = re.compile(".{26}")
p2 = re.compile("..")
args = [p2.findall(x) for x in p1.findall(hand_string)]
if len(args) != 4:
raise ValidationError(_("Invalid input for a Hand instance"))
return Hand(*args)
class HandField(models.Field):
# ...
@ -569,8 +575,9 @@ For example::
# ...
def get_prep_value(self, value):
return ''.join([''.join(l) for l in (value.north,
value.east, value.south, value.west)])
return "".join(
["".join(l) for l in (value.north, value.east, value.south, value.west)]
)
.. warning::
@ -653,7 +660,7 @@ as::
def formfield(self, **kwargs):
# This is a fairly standard way to set up some defaults
# while letting the caller override them.
defaults = {'form_class': MyFormField}
defaults = {"form_class": MyFormField}
defaults.update(kwargs)
return super().formfield(**defaults)
@ -680,7 +687,7 @@ For example::
# ...
def get_internal_type(self):
return 'CharField'
return "CharField"
No matter which database backend we are using, this will mean that
:djadmin:`migrate` and other SQL commands create the right column type for

View file

@ -19,14 +19,13 @@ fictional ``foobar`` template library::
class FooBar(BaseEngine):
# Name of the subdirectory containing the templates for this engine
# inside an installed application.
app_dirname = 'foobar'
app_dirname = "foobar"
def __init__(self, params):
params = params.copy()
options = params.pop('OPTIONS').copy()
options = params.pop("OPTIONS").copy()
super().__init__(params)
self.engine = foobar.Engine(**options)
@ -47,7 +46,6 @@ fictional ``foobar`` template library::
class Template:
def __init__(self, template):
self.template = template
@ -55,9 +53,9 @@ fictional ``foobar`` template library::
if context is None:
context = {}
if request is not None:
context['request'] = request
context['csrf_input'] = csrf_input_lazy(request)
context['csrf_token'] = csrf_token_lazy(request)
context["request"] = request
context["csrf_input"] = csrf_input_lazy(request)
context["csrf_token"] = csrf_token_lazy(request)
return self.template.render(context)
See `DEP 182`_ for more information.
@ -127,25 +125,25 @@ a :class:`dict` with the following values:
Given the above template error, ``template_debug`` would look like::
{
'name': '/path/to/template.html',
'message': "Invalid block tag: 'syntax'",
'source_lines': [
(1, 'some\n'),
(2, 'lines\n'),
(3, 'before\n'),
(4, 'Hello {% syntax error %} {{ world }}\n'),
(5, 'some\n'),
(6, 'lines\n'),
(7, 'after\n'),
(8, ''),
"name": "/path/to/template.html",
"message": "Invalid block tag: 'syntax'",
"source_lines": [
(1, "some\n"),
(2, "lines\n"),
(3, "before\n"),
(4, "Hello {% syntax error %} {{ world }}\n"),
(5, "some\n"),
(6, "lines\n"),
(7, "after\n"),
(8, ""),
],
'line': 4,
'before': 'Hello ',
'during': '{% syntax error %}',
'after': ' {{ world }}\n',
'total': 9,
'bottom': 9,
'top': 1,
"line": 4,
"before": "Hello ",
"during": "{% syntax error %}",
"after": " {{ world }}\n",
"total": 9,
"bottom": 9,
"top": 1,
}
.. _template-origin-api:

View file

@ -111,7 +111,7 @@ Here's an example filter definition::
def cut(value, arg):
"""Removes all values of arg from the given string"""
return value.replace(arg, '')
return value.replace(arg, "")
And here's an example of how that filter would be used:
@ -122,7 +122,7 @@ And here's an example of how that filter would be used:
Most filters don't take arguments. In this case, leave the argument out of your
function::
def lower(value): # Only one argument.
def lower(value): # Only one argument.
"""Converts a string into all lowercase"""
return value.lower()
@ -134,8 +134,8 @@ Registering custom filters
Once you've written your filter definition, you need to register it with
your ``Library`` instance, to make it available to Django's template language::
register.filter('cut', cut)
register.filter('lower', lower)
register.filter("cut", cut)
register.filter("lower", lower)
The ``Library.filter()`` method takes two arguments:
@ -145,9 +145,10 @@ The ``Library.filter()`` method takes two arguments:
You can use ``register.filter()`` as a decorator instead::
@register.filter(name='cut')
@register.filter(name="cut")
def cut(value, arg):
return value.replace(arg, '')
return value.replace(arg, "")
@register.filter
def lower(value):
@ -175,6 +176,7 @@ convert an object to its string value before being passed to your function::
register = template.Library()
@register.filter
@stringfilter
def lower(value):
@ -242,7 +244,7 @@ Template filter code falls into one of two situations:
@register.filter(is_safe=True)
def add_xx(value):
return '%sxx' % value
return "%sxx" % value
When this filter is used in a template where auto-escaping is enabled,
Django will escape the output whenever the input is not already marked
@ -300,6 +302,7 @@ Template filter code falls into one of two situations:
register = template.Library()
@register.filter(needs_autoescape=True)
def initial_letter_filter(text, autoescape=True):
first, other = text[0], text[1:]
@ -307,7 +310,7 @@ Template filter code falls into one of two situations:
esc = conditional_escape
else:
esc = lambda x: x
result = '<strong>%s</strong>%s' % (esc(first), esc(other))
result = "<strong>%s</strong>%s" % (esc(first), esc(other))
return mark_safe(result)
The ``needs_autoescape`` flag and the ``autoescape`` keyword argument mean
@ -345,12 +348,10 @@ Template filter code falls into one of two situations:
from django.template.defaultfilters import linebreaksbr, urlize
@register.filter(needs_autoescape=True)
def urlize_and_linebreaks(text, autoescape=True):
return linebreaksbr(
urlize(text, autoescape=autoescape),
autoescape=autoescape
)
return linebreaksbr(urlize(text, autoescape=autoescape), autoescape=autoescape)
Then:
@ -378,7 +379,7 @@ objects, you'll usually register it with the ``expects_localtime`` flag set to
try:
return 9 <= value.hour < 17
except AttributeError:
return ''
return ""
When this flag is set, if the first argument to your filter is a time zone
aware datetime, Django will convert it to the current time zone before passing
@ -421,6 +422,7 @@ Our ``current_time`` function could thus be written like this::
register = template.Library()
@register.simple_tag
def current_time(format_string):
return datetime.datetime.now().strftime(format_string)
@ -450,7 +452,7 @@ If your template tag needs to access the current context, you can use the
@register.simple_tag(takes_context=True)
def current_time(context, format_string):
timezone = context['timezone']
timezone = context["timezone"]
return your_get_current_time_method(timezone, format_string)
Note that the first argument *must* be called ``context``.
@ -460,9 +462,10 @@ on :ref:`inclusion tags<howto-custom-template-tags-inclusion-tags>`.
If you need to rename your tag, you can provide a custom name for it::
register.simple_tag(lambda x: x - 1, name='minusone')
register.simple_tag(lambda x: x - 1, name="minusone")
@register.simple_tag(name='minustwo')
@register.simple_tag(name="minustwo")
def some_function(value):
return value - 2
@ -471,8 +474,8 @@ arguments. For example::
@register.simple_tag
def my_tag(a, b, *args, **kwargs):
warning = kwargs['warning']
profile = kwargs['profile']
warning = kwargs["warning"]
profile = kwargs["profile"]
...
return ...
@ -537,7 +540,7 @@ for the template fragment. Example::
def show_results(poll):
choices = poll.choice_set.all()
return {'choices': choices}
return {"choices": choices}
Next, create the template used to render the tag's output. This template is a
fixed feature of the tag: the tag writer specifies it, not the template
@ -557,7 +560,7 @@ in a file called ``results.html`` in a directory that's searched by the
template loader, we'd register the tag like this::
# Here, register is a django.template.Library instance, as before
@register.inclusion_tag('results.html')
@register.inclusion_tag("results.html")
def show_results(poll):
...
@ -565,7 +568,8 @@ Alternatively it is possible to register the inclusion tag using a
:class:`django.template.Template` instance::
from django.template.loader import get_template
t = get_template('results.html')
t = get_template("results.html")
register.inclusion_tag(t)(show_results)
...when first creating the function.
@ -581,11 +585,11 @@ For example, say you're writing an inclusion tag that will always be used in a
context that contains ``home_link`` and ``home_title`` variables that point
back to the main page. Here's what the Python function would look like::
@register.inclusion_tag('link.html', takes_context=True)
@register.inclusion_tag("link.html", takes_context=True)
def jump_link(context):
return {
'link': context['home_link'],
'title': context['home_title'],
"link": context["home_link"],
"title": context["home_title"],
}
Note that the first parameter to the function *must* be called ``context``.
@ -615,10 +619,10 @@ only difference between this case and the previous ``inclusion_tag`` example.
``inclusion_tag`` functions may accept any number of positional or keyword
arguments. For example::
@register.inclusion_tag('my_template.html')
@register.inclusion_tag("my_template.html")
def my_tag(a, b, *args, **kwargs):
warning = kwargs['warning']
profile = kwargs['profile']
warning = kwargs["warning"]
profile = kwargs["profile"]
...
return ...
@ -678,6 +682,7 @@ object::
from django import template
def do_current_time(parser, token):
try:
# split_contents() knows not to split quoted strings.
@ -737,6 +742,7 @@ Continuing the above example, we need to define ``CurrentTimeNode``::
import datetime
from django import template
class CurrentTimeNode(template.Node):
def __init__(self, format_string):
self.format_string = format_string
@ -788,17 +794,18 @@ The ``__init__`` method for the ``Context`` class takes a parameter called
from django.template import Context
def render(self, context):
# ...
new_context = Context({'var': obj}, autoescape=context.autoescape)
new_context = Context({"var": obj}, autoescape=context.autoescape)
# ... Do something with new_context ...
This is not a very common situation, but it's useful if you're rendering a
template yourself. For example::
def render(self, context):
t = context.template.engine.get_template('small_fragment.html')
return t.render(Context({'var': obj}, autoescape=context.autoescape))
t = context.template.engine.get_template("small_fragment.html")
return t.render(Context({"var": obj}, autoescape=context.autoescape))
If we had neglected to pass in the current ``context.autoescape`` value to our
new ``Context`` in this example, the results would have *always* been
@ -834,6 +841,7 @@ A naive implementation of ``CycleNode`` might look something like this::
import itertools
from django import template
class CycleNode(template.Node):
def __init__(self, cyclevars):
self.cycle_iter = itertools.cycle(cyclevars)
@ -897,7 +905,7 @@ Finally, register the tag with your module's ``Library`` instance, as explained
in :ref:`writing custom template tags<howto-writing-custom-template-tags>`
above. Example::
register.tag('current_time', do_current_time)
register.tag("current_time", do_current_time)
The ``tag()`` method takes two arguments:
@ -912,6 +920,7 @@ As with filter registration, it is also possible to use this as a decorator::
def do_current_time(parser, token):
...
@register.tag
def shout(parser, token):
...
@ -949,6 +958,7 @@ Now your tag should begin to look like this::
from django import template
def do_format_time(parser, token):
try:
# split_contents() knows not to split quoted strings.
@ -980,7 +990,7 @@ be resolved, and then call ``variable.resolve(context)``. So, for example::
actual_date = self.date_to_be_formatted.resolve(context)
return actual_date.strftime(self.format_string)
except template.VariableDoesNotExist:
return ''
return ""
Variable resolution will throw a ``VariableDoesNotExist`` exception if it
cannot resolve the string passed to it in the current context of the page.
@ -1000,12 +1010,14 @@ outputting it::
import datetime
from django import template
class CurrentTimeNode2(template.Node):
def __init__(self, format_string):
self.format_string = format_string
def render(self, context):
context['current_time'] = datetime.datetime.now().strftime(self.format_string)
return ''
context["current_time"] = datetime.datetime.now().strftime(self.format_string)
return ""
Note that ``render()`` returns the empty string. ``render()`` should always
return string output. If all the template tag does is set a variable,
@ -1041,13 +1053,16 @@ class, like so::
import re
class CurrentTimeNode3(template.Node):
def __init__(self, format_string, var_name):
self.format_string = format_string
self.var_name = var_name
def render(self, context):
context[self.var_name] = datetime.datetime.now().strftime(self.format_string)
return ''
return ""
def do_current_time(parser, token):
# This version uses a regular expression to parse tag contents.
@ -1058,7 +1073,7 @@ class, like so::
raise template.TemplateSyntaxError(
"%r tag requires arguments" % token.contents.split()[0]
)
m = re.search(r'(.*?) as (\w+)', arg)
m = re.search(r"(.*?) as (\w+)", arg)
if not m:
raise template.TemplateSyntaxError("%r tag had invalid arguments" % tag_name)
format_string, var_name = m.groups()
@ -1087,13 +1102,14 @@ compilation function.
Here's how a simplified ``{% comment %}`` tag might be implemented::
def do_comment(parser, token):
nodelist = parser.parse(('endcomment',))
nodelist = parser.parse(("endcomment",))
parser.delete_first_token()
return CommentNode()
class CommentNode(template.Node):
def render(self, context):
return ''
return ""
.. note::
The actual implementation of :ttag:`{% comment %}<comment>` is slightly
@ -1140,13 +1156,15 @@ As in the previous example, we'll use ``parser.parse()``. But this time, we
pass the resulting ``nodelist`` to the ``Node``::
def do_upper(parser, token):
nodelist = parser.parse(('endupper',))
nodelist = parser.parse(("endupper",))
parser.delete_first_token()
return UpperNode(nodelist)
class UpperNode(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
output = self.nodelist.render(context)
return output.upper()

View file

@ -69,4 +69,5 @@ To apply ASGI middleware, or to embed Django in another ASGI application, you
can wrap Django's ``application`` object in the ``asgi.py`` file. For example::
from some_asgi_library import AmazingMiddleware
application = AmazingMiddleware(application)

View file

@ -52,19 +52,21 @@ Instead of hardcoding the secret key in your settings module, consider loading
it from an environment variable::
import os
SECRET_KEY = os.environ['SECRET_KEY']
SECRET_KEY = os.environ["SECRET_KEY"]
or from a file::
with open('/etc/secret_key.txt') as f:
with open("/etc/secret_key.txt") as f:
SECRET_KEY = f.read().strip()
If rotating secret keys, you may use :setting:`SECRET_KEY_FALLBACKS`::
import os
SECRET_KEY = os.environ['CURRENT_SECRET_KEY']
SECRET_KEY = os.environ["CURRENT_SECRET_KEY"]
SECRET_KEY_FALLBACKS = [
os.environ['OLD_SECRET_KEY'],
os.environ["OLD_SECRET_KEY"],
]
Ensure that old secret keys are removed from ``SECRET_KEY_FALLBACKS`` in a

View file

@ -84,11 +84,12 @@ function::
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings"
from django.contrib.auth.handlers.modwsgi import check_password
from django.core.handlers.wsgi import WSGIHandler
application = WSGIHandler()

View file

@ -76,6 +76,7 @@ object. For instance you could add these lines at the bottom of
:file:`wsgi.py`::
from helloworld.wsgi import HelloWorldApplication
application = HelloWorldApplication(application)
You could also replace the Django WSGI application with a custom WSGI

View file

@ -81,9 +81,10 @@ You can tell Django to stop reporting particular 404s by tweaking the
regular expression objects. For example::
import re
IGNORABLE_404_URLS = [
re.compile(r'\.(php|cgi)$'),
re.compile(r'^/phpmyadmin/'),
re.compile(r"\.(php|cgi)$"),
re.compile(r"^/phpmyadmin/"),
]
In this example, a 404 to any URL ending with ``.php`` or ``.cgi`` will *not* be
@ -93,10 +94,11 @@ The following example shows how to exclude some conventional URLs that browsers
crawlers often request::
import re
IGNORABLE_404_URLS = [
re.compile(r'^/apple-touch-icon.*\.png$'),
re.compile(r'^/favicon\.ico$'),
re.compile(r'^/robots\.txt$'),
re.compile(r"^/apple-touch-icon.*\.png$"),
re.compile(r"^/favicon\.ico$"),
re.compile(r"^/robots\.txt$"),
]
(Note that these are regular expressions, so we put a backslash in front of
@ -158,7 +160,8 @@ filtered out of error reports in a production environment (that is, where
from django.views.decorators.debug import sensitive_variables
@sensitive_variables('user', 'pw', 'cc')
@sensitive_variables("user", "pw", "cc")
def process_info(user):
pw = user.pass_word
cc = user.credit_card_number
@ -185,7 +188,7 @@ filtered out of error reports in a production environment (that is, where
at the top of the decorator chain. This way it will also hide the
function argument as it gets passed through the other decorators::
@sensitive_variables('user', 'pw', 'cc')
@sensitive_variables("user", "pw", "cc")
@some_decorator
@another_decorator
def process_info(user):
@ -201,13 +204,14 @@ filtered out of error reports in a production environment (that is, where
from django.views.decorators.debug import sensitive_post_parameters
@sensitive_post_parameters('pass_word', 'credit_card_number')
@sensitive_post_parameters("pass_word", "credit_card_number")
def record_user_profile(request):
UserProfile.create(
user=request.user,
password=request.POST['pass_word'],
credit_card=request.POST['credit_card_number'],
name=request.POST['name'],
password=request.POST["pass_word"],
credit_card=request.POST["credit_card_number"],
name=request.POST["name"],
)
...
@ -248,7 +252,7 @@ override or customize this default behavior for your entire site, you need to
define your own filter class and tell Django to use it via the
:setting:`DEFAULT_EXCEPTION_REPORTER_FILTER` setting::
DEFAULT_EXCEPTION_REPORTER_FILTER = 'path.to.your.CustomExceptionReporterFilter'
DEFAULT_EXCEPTION_REPORTER_FILTER = "path.to.your.CustomExceptionReporterFilter"
You may also control in a more granular way which filter to use within any
given view by setting the ``HttpRequest``s ``exception_reporter_filter``
@ -281,7 +285,7 @@ following attributes and methods:
import re
re.compile(r'API|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE', flags=re.IGNORECASE)
re.compile(r"API|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE", flags=re.IGNORECASE)
.. versionchanged:: 4.2
@ -311,7 +315,7 @@ If you need to customize error reports beyond filtering you may specify a
custom error reporter class by defining the
:setting:`DEFAULT_EXCEPTION_REPORTER` setting::
DEFAULT_EXCEPTION_REPORTER = 'path.to.your.CustomExceptionReporter'
DEFAULT_EXCEPTION_REPORTER = "path.to.your.CustomExceptionReporter"
The exception reporter is responsible for compiling the exception report data,
and formatting it as text or HTML appropriately. (The exception reporter uses

View file

@ -58,9 +58,10 @@ each table's creation, modification, and deletion::
class Person(models.Model):
id = models.IntegerField(primary_key=True)
first_name = models.CharField(max_length=70)
class Meta:
managed = False
db_table = 'CENSUS_PERSONS'
managed = False
db_table = "CENSUS_PERSONS"
If you do want to allow Django to manage the table's lifecycle, you'll need to
change the :attr:`~django.db.models.Options.managed` option above to ``True``

View file

@ -41,7 +41,7 @@ And then in a function, for example in a view, send a record to the logger::
def some_view(request):
...
if some_risky_state:
logger.warning('Platform is running at risk')
logger.warning("Platform is running at risk")
When this code is executed, a :py:class:`~logging.LogRecord` containing that
message will be sent to the logger. If you're using Django's default logging
@ -51,7 +51,7 @@ The ``WARNING`` level used in the example above is one of several
:ref:`logging severity levels <topic-logging-parts-loggers>`: ``DEBUG``,
``INFO``, ``WARNING``, ``ERROR``, ``CRITICAL``. So, another example might be::
logger.critical('Payment system is not responding')
logger.critical("Payment system is not responding")
.. important::
@ -99,8 +99,8 @@ Create a ``LOGGING`` dictionary
In your ``settings.py``::
LOGGING = {
'version': 1, # the dictConfig format version
'disable_existing_loggers': False, # retain the default loggers
"version": 1, # the dictConfig format version
"disable_existing_loggers": False, # retain the default loggers
}
It nearly always makes sense to retain and extend the default logging
@ -118,10 +118,10 @@ file ``general.log`` (at the project root):
LOGGING = {
# ...
'handlers': {
'file': {
'class': 'logging.FileHandler',
'filename': 'general.log',
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": "general.log",
},
},
}
@ -138,9 +138,9 @@ messages of all levels). Using the example above, adding:
:emphasize-lines: 4
{
'class': 'logging.FileHandler',
'filename': 'general.log',
'level': 'DEBUG',
"class": "logging.FileHandler",
"filename": "general.log",
"level": "DEBUG",
}
would define a handler configuration that only accepts records of level
@ -157,10 +157,10 @@ example:
LOGGING = {
# ...
'loggers': {
'': {
'level': 'DEBUG',
'handlers': ['file'],
"loggers": {
"": {
"level": "DEBUG",
"handlers": ["file"],
},
},
}
@ -178,7 +178,7 @@ between loggers and handlers is many-to-many.
If you execute::
logger.debug('Attempting to connect to API')
logger.debug("Attempting to connect to API")
in your code, you will find that message in the file ``general.log`` in the
root of the project.
@ -196,14 +196,14 @@ formatters named ``verbose`` and ``simple``:
LOGGING = {
# ...
'formatters': {
'verbose': {
'format': '{name} {levelname} {asctime} {module} {process:d} {thread:d} {message}',
'style': '{',
"formatters": {
"verbose": {
"format": "{name} {levelname} {asctime} {module} {process:d} {thread:d} {message}",
"style": "{",
},
'simple': {
'format': '{levelname} {message}',
'style': '{',
"simple": {
"format": "{levelname} {message}",
"style": "{",
},
},
}
@ -220,11 +220,11 @@ dictionary referring to the formatter by name, for example:
.. code-block:: python
:emphasize-lines: 5
'handlers': {
'file': {
'class': 'logging.FileHandler',
'filename': 'general.log',
'formatter': 'verbose',
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": "general.log",
"formatter": "verbose",
},
}
@ -254,10 +254,8 @@ A logger mapping named ``my_app.views`` will capture records from this logger:
LOGGING = {
# ...
'loggers': {
'my_app.views': {
...
},
"loggers": {
"my_app.views": {...},
},
}
@ -270,16 +268,14 @@ from loggers anywhere within the ``my_app`` namespace (including
LOGGING = {
# ...
'loggers': {
'my_app': {
...
},
"loggers": {
"my_app": {...},
},
}
You can also define logger namespacing explicitly::
logger = logging.getLogger('project.payment')
logger = logging.getLogger("project.payment")
and set up logger mappings accordingly.
@ -298,16 +294,16 @@ To manage this behavior, set the propagation key on the mappings you define::
LOGGING = {
# ...
'loggers': {
'my_app': {
"loggers": {
"my_app": {
# ...
},
'my_app.views': {
"my_app.views": {
# ...
},
'my_app.views.private': {
"my_app.views.private": {
# ...
'propagate': False,
"propagate": False,
},
},
}
@ -333,7 +329,7 @@ For example, you could set an environment variable ``DJANGO_LOG_LEVEL``
appropriately in your development and staging environments, and make use of it
in a logger mapping thus::
'level': os.getenv('DJANGO_LOG_LEVEL', 'WARNING')
"level": os.getenv("DJANGO_LOG_LEVEL", "WARNING")
\- so that unless the environment specifies a lower log level, this
configuration will only forward records of severity ``WARNING`` and above to

View file

@ -18,16 +18,17 @@ Here's an example::
import csv
from django.http import HttpResponse
def some_view(request):
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(
content_type='text/csv',
headers={'Content-Disposition': 'attachment; filename="somefilename.csv"'},
content_type="text/csv",
headers={"Content-Disposition": 'attachment; filename="somefilename.csv"'},
)
writer = csv.writer(response)
writer.writerow(['First row', 'Foo', 'Bar', 'Baz'])
writer.writerow(['Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"])
writer.writerow(["First row", "Foo", "Bar", "Baz"])
writer.writerow(["Second row", "A", "B", "C", '"Testing"', "Here's a quote"])
return response
@ -72,14 +73,17 @@ the assembly and transmission of a large CSV file::
from django.http import StreamingHttpResponse
class Echo:
"""An object that implements just the write method of the file-like
interface.
"""
def write(self, value):
"""Write the value by returning it, instead of storing in a buffer."""
return value
def some_streaming_csv_view(request):
"""A view that streams a large CSV file."""
# Generate a sequence of rows. The range is based on the maximum number of
@ -91,7 +95,7 @@ the assembly and transmission of a large CSV file::
return StreamingHttpResponse(
(writer.writerow(row) for row in rows),
content_type="text/csv",
headers={'Content-Disposition': 'attachment; filename="somefilename.csv"'},
headers={"Content-Disposition": 'attachment; filename="somefilename.csv"'},
)
Using the template system
@ -109,22 +113,23 @@ Here's an example, which generates the same CSV file as above::
from django.http import HttpResponse
from django.template import loader
def some_view(request):
# Create the HttpResponse object with the appropriate CSV header.
response = HttpResponse(
content_type='text/csv',
headers={'Content-Disposition': 'attachment; filename="somefilename.csv"'},
content_type="text/csv",
headers={"Content-Disposition": 'attachment; filename="somefilename.csv"'},
)
# The data is hard-coded here, but you could load it from a database or
# some other source.
csv_data = (
('First row', 'Foo', 'Bar', 'Baz'),
('Second row', 'A', 'B', 'C', '"Testing"', "Here's a quote"),
("First row", "Foo", "Bar", "Baz"),
("Second row", "A", "B", "C", '"Testing"', "Here's a quote"),
)
t = loader.get_template('my_template_name.txt')
c = {'data': csv_data}
t = loader.get_template("my_template_name.txt")
c = {"data": csv_data}
response.write(t.render(c))
return response

View file

@ -52,6 +52,7 @@ Here's a "Hello World" example::
from django.http import FileResponse
from reportlab.pdfgen import canvas
def some_view(request):
# Create a file-like buffer to receive PDF data.
buffer = io.BytesIO()
@ -70,7 +71,7 @@ Here's a "Hello World" example::
# FileResponse sets the Content-Disposition header so that browsers
# present the option to save the file.
buffer.seek(0)
return FileResponse(buffer, as_attachment=True, filename='hello.pdf')
return FileResponse(buffer, as_attachment=True, filename="hello.pdf")
The code and comments should be self-explanatory, but a few things deserve a
mention:

View file

@ -33,15 +33,15 @@ called ``blog``, which provides the templates ``blog/post.html`` and
INSTALLED_APPS = [
...,
'blog',
"blog",
...,
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
# ...
},
]
@ -78,7 +78,7 @@ First, make sure your template settings are checking inside app directories::
TEMPLATES = [
{
# ...
'APP_DIRS': True,
"APP_DIRS": True,
# ...
},
]

View file

@ -16,7 +16,7 @@ Configuring static files
#. In your settings file, define :setting:`STATIC_URL`, for example::
STATIC_URL = 'static/'
STATIC_URL = "static/"
#. In your templates, use the :ttag:`static` template tag to build the URL for
the given relative path using the configured ``staticfiles``
@ -54,7 +54,7 @@ settings file where Django will also look for static files. For example::
STATICFILES_DIRS = [
BASE_DIR / "static",
'/var/www/static/',
"/var/www/static/",
]
See the documentation for the :setting:`STATICFILES_FINDERS` setting for

View file

@ -21,13 +21,14 @@ attribute::
from django.db import migrations
def forwards(apps, schema_editor):
if schema_editor.connection.alias != 'default':
if schema_editor.connection.alias != "default":
return
# Your migration code goes here
class Migration(migrations.Migration):
class Migration(migrations.Migration):
dependencies = [
# Dependencies to other migrations
]
@ -43,28 +44,28 @@ method of database routers as ``**hints``:
:caption: ``myapp/dbrouters.py``
class MyRouter:
def allow_migrate(self, db, app_label, model_name=None, **hints):
if 'target_db' in hints:
return db == hints['target_db']
if "target_db" in hints:
return db == hints["target_db"]
return True
Then, to leverage this in your migrations, do the following::
from django.db import migrations
def forwards(apps, schema_editor):
# Your migration code goes here
...
class Migration(migrations.Migration):
class Migration(migrations.Migration):
dependencies = [
# Dependencies to other migrations
]
operations = [
migrations.RunPython(forwards, hints={'target_db': 'default'}),
migrations.RunPython(forwards, hints={"target_db": "default"}),
]
If your ``RunPython`` or ``RunSQL`` operation only affects one model, it's good
@ -104,16 +105,16 @@ the respective field according to your needs.
from django.db import migrations, models
import uuid
class Migration(migrations.Migration):
class Migration(migrations.Migration):
dependencies = [
('myapp', '0005_populate_uuid_values'),
("myapp", "0005_populate_uuid_values"),
]
operations = [
migrations.AlterField(
model_name='mymodel',
name='uuid',
model_name="mymodel",
name="uuid",
field=models.UUIDField(default=uuid.uuid4, unique=True),
),
]
@ -125,15 +126,14 @@ the respective field according to your needs.
:caption: ``0004_add_uuid_field.py``
class Migration(migrations.Migration):
dependencies = [
('myapp', '0003_auto_20150129_1705'),
("myapp", "0003_auto_20150129_1705"),
]
operations = [
migrations.AddField(
model_name='mymodel',
name='uuid',
model_name="mymodel",
name="uuid",
field=models.UUIDField(default=uuid.uuid4, unique=True),
),
]
@ -155,16 +155,17 @@ the respective field according to your needs.
from django.db import migrations
import uuid
def gen_uuid(apps, schema_editor):
MyModel = apps.get_model('myapp', 'MyModel')
MyModel = apps.get_model("myapp", "MyModel")
for row in MyModel.objects.all():
row.uuid = uuid.uuid4()
row.save(update_fields=['uuid'])
row.save(update_fields=["uuid"])
class Migration(migrations.Migration):
dependencies = [
('myapp', '0004_add_uuid_field'),
("myapp", "0004_add_uuid_field"),
]
operations = [
@ -190,6 +191,7 @@ a transaction by setting the ``atomic`` attribute to ``False``::
from django.db import migrations
class Migration(migrations.Migration):
atomic = False
@ -205,14 +207,16 @@ smaller batches::
from django.db import migrations, transaction
def gen_uuid(apps, schema_editor):
MyModel = apps.get_model('myapp', 'MyModel')
MyModel = apps.get_model("myapp", "MyModel")
while MyModel.objects.filter(uuid__isnull=True).exists():
with transaction.atomic():
for row in MyModel.objects.filter(uuid__isnull=True)[:1000]:
row.uuid = uuid.uuid4()
row.save()
class Migration(migrations.Migration):
atomic = False
@ -241,10 +245,10 @@ The ``dependencies`` property is declared like this::
from django.db import migrations
class Migration(migrations.Migration):
class Migration(migrations.Migration):
dependencies = [
('myapp', '0123_the_previous_migration'),
("myapp", "0123_the_previous_migration"),
]
Usually this will be enough, but from time to time you may need to
@ -259,7 +263,7 @@ the ``run_before`` attribute on your ``Migration`` class::
...
run_before = [
('third_party_app', '0001_do_awesome'),
("third_party_app", "0001_do_awesome"),
]
Prefer using ``dependencies`` over ``run_before`` when possible. You should
@ -288,30 +292,32 @@ Here's a sample migration:
from django.apps import apps as global_apps
from django.db import migrations
def forwards(apps, schema_editor):
try:
OldModel = apps.get_model('old_app', 'OldModel')
OldModel = apps.get_model("old_app", "OldModel")
except LookupError:
# The old app isn't installed.
return
NewModel = apps.get_model('new_app', 'NewModel')
NewModel = apps.get_model("new_app", "NewModel")
NewModel.objects.bulk_create(
NewModel(new_attribute=old_object.old_attribute)
for old_object in OldModel.objects.all()
)
class Migration(migrations.Migration):
operations = [
migrations.RunPython(forwards, migrations.RunPython.noop),
]
dependencies = [
('myapp', '0123_the_previous_migration'),
('new_app', '0001_initial'),
("myapp", "0123_the_previous_migration"),
("new_app", "0001_initial"),
]
if global_apps.is_installed('old_app'):
dependencies.append(('old_app', '0001_initial'))
if global_apps.is_installed("old_app"):
dependencies.append(("old_app", "0001_initial"))
Also consider what you want to happen when the migration is unapplied. You
could either do nothing (as in the example above) or remove some or all of the
@ -345,7 +351,7 @@ For example, if we had a ``Book`` model with a ``ManyToManyField`` linking to
class Migration(migrations.Migration):
dependencies = [
('core', '0001_initial'),
("core", "0001_initial"),
]
operations = [
@ -354,52 +360,52 @@ For example, if we had a ``Book`` model with a ``ManyToManyField`` linking to
# Old table name from checking with sqlmigrate, new table
# name from AuthorBook._meta.db_table.
migrations.RunSQL(
sql='ALTER TABLE core_book_authors RENAME TO core_authorbook',
reverse_sql='ALTER TABLE core_authorbook RENAME TO core_book_authors',
sql="ALTER TABLE core_book_authors RENAME TO core_authorbook",
reverse_sql="ALTER TABLE core_authorbook RENAME TO core_book_authors",
),
],
state_operations=[
migrations.CreateModel(
name='AuthorBook',
name="AuthorBook",
fields=[
(
'id',
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
verbose_name="ID",
),
),
(
'author',
"author",
models.ForeignKey(
on_delete=django.db.models.deletion.DO_NOTHING,
to='core.Author',
to="core.Author",
),
),
(
'book',
"book",
models.ForeignKey(
on_delete=django.db.models.deletion.DO_NOTHING,
to='core.Book',
to="core.Book",
),
),
],
),
migrations.AlterField(
model_name='book',
name='authors',
model_name="book",
name="authors",
field=models.ManyToManyField(
to='core.Author',
through='core.AuthorBook',
to="core.Author",
through="core.AuthorBook",
),
),
],
),
migrations.AddField(
model_name='authorbook',
name='is_primary',
model_name="authorbook",
name="is_primary",
field=models.BooleanField(default=False),
),
]