mirror of
https://github.com/django/django.git
synced 2025-12-10 03:10:10 +00:00
Fixed #34140 -- Reformatted code blocks in docs with blacken-docs.
This commit is contained in:
parent
6015bab80e
commit
14459f80ee
193 changed files with 5797 additions and 4481 deletions
|
|
@ -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::
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
-----------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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``
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
# ...
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue