summaryrefslogtreecommitdiff
path: root/docs/howto
diff options
context:
space:
mode:
authordjango-bot <ops@djangoproject.com>2023-02-28 20:53:28 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-03-01 13:03:56 +0100
commit14459f80ee3a9e005989db37c26fd13bb6d2fab2 (patch)
treeeb62429ed696ed3a5389f3a676aecfc6d15a99cc /docs/howto
parent6015bab80e28aef2669f6fac53423aa65f70cb08 (diff)
Fixed #34140 -- Reformatted code blocks in docs with blacken-docs.
Diffstat (limited to 'docs/howto')
-rw-r--r--docs/howto/auth-remote-user.txt13
-rw-r--r--docs/howto/csrf.txt7
-rw-r--r--docs/howto/custom-file-storage.txt3
-rw-r--r--docs/howto/custom-lookups.txt35
-rw-r--r--docs/howto/custom-management-commands.txt26
-rw-r--r--docs/howto/custom-model-fields.txt47
-rw-r--r--docs/howto/custom-template-backend.txt48
-rw-r--r--docs/howto/custom-template-tags.txt96
-rw-r--r--docs/howto/deployment/asgi/index.txt1
-rw-r--r--docs/howto/deployment/checklist.txt10
-rw-r--r--docs/howto/deployment/wsgi/apache-auth.txt3
-rw-r--r--docs/howto/deployment/wsgi/index.txt1
-rw-r--r--docs/howto/error-reporting.txt32
-rw-r--r--docs/howto/legacy-databases.txt5
-rw-r--r--docs/howto/logging.txt82
-rw-r--r--docs/howto/outputting-csv.txt27
-rw-r--r--docs/howto/outputting-pdf.txt3
-rw-r--r--docs/howto/overriding-templates.txt10
-rw-r--r--docs/howto/static-files/index.txt4
-rw-r--r--docs/howto/writing-migrations.txt96
20 files changed, 305 insertions, 244 deletions
diff --git a/docs/howto/auth-remote-user.txt b/docs/howto/auth-remote-user.txt
index 20bd84d055..19b25432fe 100644
--- a/docs/howto/auth-remote-user.txt
+++ b/docs/howto/auth-remote-user.txt
@@ -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::
diff --git a/docs/howto/csrf.txt b/docs/howto/csrf.txt
index 3f3271454b..07f2e20a1c 100644
--- a/docs/howto/csrf.txt
+++ b/docs/howto/csrf.txt
@@ -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
-----------------------------------------------------
diff --git a/docs/howto/custom-file-storage.txt b/docs/howto/custom-file-storage.txt
index 47abe3e7fd..de44a1d938 100644
--- a/docs/howto/custom-file-storage.txt
+++ b/docs/howto/custom-file-storage.txt
@@ -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"]
diff --git a/docs/howto/custom-lookups.txt b/docs/howto/custom-lookups.txt
index 3736a995ae..61ec9295eb 100644
--- a/docs/howto/custom-lookups.txt
+++ b/docs/howto/custom-lookups.txt
@@ -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:
diff --git a/docs/howto/custom-management-commands.txt b/docs/howto/custom-management-commands.txt
index 8fd168d150..8bdfb1e38b 100644
--- a/docs/howto/custom-management-commands.txt
+++ b/docs/howto/custom-management-commands.txt
@@ -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
diff --git a/docs/howto/custom-model-fields.txt b/docs/howto/custom-model-fields.txt
index 15ddb65af8..fa5c4389d7 100644
--- a/docs/howto/custom-model-fields.txt
+++ b/docs/howto/custom-model-fields.txt
@@ -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
diff --git a/docs/howto/custom-template-backend.txt b/docs/howto/custom-template-backend.txt
index e74524b830..85e8591cbd 100644
--- a/docs/howto/custom-template-backend.txt
+++ b/docs/howto/custom-template-backend.txt
@@ -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:
diff --git a/docs/howto/custom-template-tags.txt b/docs/howto/custom-template-tags.txt
index 8ff469a5d6..c7909c8a4b 100644
--- a/docs/howto/custom-template-tags.txt
+++ b/docs/howto/custom-template-tags.txt
@@ -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()
diff --git a/docs/howto/deployment/asgi/index.txt b/docs/howto/deployment/asgi/index.txt
index 1bd04b1fdf..6015554350 100644
--- a/docs/howto/deployment/asgi/index.txt
+++ b/docs/howto/deployment/asgi/index.txt
@@ -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)
diff --git a/docs/howto/deployment/checklist.txt b/docs/howto/deployment/checklist.txt
index 6f98a2230e..75c9735e86 100644
--- a/docs/howto/deployment/checklist.txt
+++ b/docs/howto/deployment/checklist.txt
@@ -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
diff --git a/docs/howto/deployment/wsgi/apache-auth.txt b/docs/howto/deployment/wsgi/apache-auth.txt
index 2225b8591a..0629b785c5 100644
--- a/docs/howto/deployment/wsgi/apache-auth.txt
+++ b/docs/howto/deployment/wsgi/apache-auth.txt
@@ -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()
diff --git a/docs/howto/deployment/wsgi/index.txt b/docs/howto/deployment/wsgi/index.txt
index fae2d69980..502a253866 100644
--- a/docs/howto/deployment/wsgi/index.txt
+++ b/docs/howto/deployment/wsgi/index.txt
@@ -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
diff --git a/docs/howto/error-reporting.txt b/docs/howto/error-reporting.txt
index b808a0a981..95adfce755 100644
--- a/docs/howto/error-reporting.txt
+++ b/docs/howto/error-reporting.txt
@@ -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
diff --git a/docs/howto/legacy-databases.txt b/docs/howto/legacy-databases.txt
index 6204c12e50..5730a8a059 100644
--- a/docs/howto/legacy-databases.txt
+++ b/docs/howto/legacy-databases.txt
@@ -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``
diff --git a/docs/howto/logging.txt b/docs/howto/logging.txt
index d990dd1b83..149b8bb83b 100644
--- a/docs/howto/logging.txt
+++ b/docs/howto/logging.txt
@@ -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
diff --git a/docs/howto/outputting-csv.txt b/docs/howto/outputting-csv.txt
index 6966466921..8e4bd8108c 100644
--- a/docs/howto/outputting-csv.txt
+++ b/docs/howto/outputting-csv.txt
@@ -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
diff --git a/docs/howto/outputting-pdf.txt b/docs/howto/outputting-pdf.txt
index fd56b96716..83426c1448 100644
--- a/docs/howto/outputting-pdf.txt
+++ b/docs/howto/outputting-pdf.txt
@@ -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:
diff --git a/docs/howto/overriding-templates.txt b/docs/howto/overriding-templates.txt
index f5980db3cc..f636948a20 100644
--- a/docs/howto/overriding-templates.txt
+++ b/docs/howto/overriding-templates.txt
@@ -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,
# ...
},
]
diff --git a/docs/howto/static-files/index.txt b/docs/howto/static-files/index.txt
index 2f82cf821d..b4cfd03df7 100644
--- a/docs/howto/static-files/index.txt
+++ b/docs/howto/static-files/index.txt
@@ -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
diff --git a/docs/howto/writing-migrations.txt b/docs/howto/writing-migrations.txt
index 24c47058e3..2c52eccbad 100644
--- a/docs/howto/writing-migrations.txt
+++ b/docs/howto/writing-migrations.txt
@@ -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):
+ 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),
),
]