diff options
| author | django-bot <ops@djangoproject.com> | 2023-02-28 20:53:28 +0100 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-03-01 13:03:56 +0100 |
| commit | 14459f80ee3a9e005989db37c26fd13bb6d2fab2 (patch) | |
| tree | eb62429ed696ed3a5389f3a676aecfc6d15a99cc /docs/howto | |
| parent | 6015bab80e28aef2669f6fac53423aa65f70cb08 (diff) | |
Fixed #34140 -- Reformatted code blocks in docs with blacken-docs.
Diffstat (limited to 'docs/howto')
| -rw-r--r-- | docs/howto/auth-remote-user.txt | 13 | ||||
| -rw-r--r-- | docs/howto/csrf.txt | 7 | ||||
| -rw-r--r-- | docs/howto/custom-file-storage.txt | 3 | ||||
| -rw-r--r-- | docs/howto/custom-lookups.txt | 35 | ||||
| -rw-r--r-- | docs/howto/custom-management-commands.txt | 26 | ||||
| -rw-r--r-- | docs/howto/custom-model-fields.txt | 47 | ||||
| -rw-r--r-- | docs/howto/custom-template-backend.txt | 48 | ||||
| -rw-r--r-- | docs/howto/custom-template-tags.txt | 96 | ||||
| -rw-r--r-- | docs/howto/deployment/asgi/index.txt | 1 | ||||
| -rw-r--r-- | docs/howto/deployment/checklist.txt | 10 | ||||
| -rw-r--r-- | docs/howto/deployment/wsgi/apache-auth.txt | 3 | ||||
| -rw-r--r-- | docs/howto/deployment/wsgi/index.txt | 1 | ||||
| -rw-r--r-- | docs/howto/error-reporting.txt | 32 | ||||
| -rw-r--r-- | docs/howto/legacy-databases.txt | 5 | ||||
| -rw-r--r-- | docs/howto/logging.txt | 82 | ||||
| -rw-r--r-- | docs/howto/outputting-csv.txt | 27 | ||||
| -rw-r--r-- | docs/howto/outputting-pdf.txt | 3 | ||||
| -rw-r--r-- | docs/howto/overriding-templates.txt | 10 | ||||
| -rw-r--r-- | docs/howto/static-files/index.txt | 4 | ||||
| -rw-r--r-- | docs/howto/writing-migrations.txt | 96 |
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), ), ] |
