summaryrefslogtreecommitdiff
path: root/docs/ref
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/ref
parent6015bab80e28aef2669f6fac53423aa65f70cb08 (diff)
downloaddjango-14459f80ee3a9e005989db37c26fd13bb6d2fab2.tar.gz
Fixed #34140 -- Reformatted code blocks in docs with blacken-docs.
Diffstat (limited to 'docs/ref')
-rw-r--r--docs/ref/applications.txt16
-rw-r--r--docs/ref/class-based-views/base.txt34
-rw-r--r--docs/ref/class-based-views/generic-date-based.txt64
-rw-r--r--docs/ref/class-based-views/generic-display.txt12
-rw-r--r--docs/ref/class-based-views/generic-editing.txt20
-rw-r--r--docs/ref/class-based-views/index.txt2
-rw-r--r--docs/ref/class-based-views/mixins-multiple-object.txt2
-rw-r--r--docs/ref/class-based-views/mixins-simple.txt5
-rw-r--r--docs/ref/clickjacking.txt7
-rw-r--r--docs/ref/contrib/admin/actions.txt111
-rw-r--r--docs/ref/contrib/admin/admindocs.txt9
-rw-r--r--docs/ref/contrib/admin/filters.txt34
-rw-r--r--docs/ref/contrib/admin/index.txt333
-rw-r--r--docs/ref/contrib/contenttypes.txt34
-rw-r--r--docs/ref/contrib/flatpages.txt43
-rw-r--r--docs/ref/contrib/gis/db-api.txt45
-rw-r--r--docs/ref/contrib/gis/feeds.txt6
-rw-r--r--docs/ref/contrib/gis/forms-api.txt4
-rw-r--r--docs/ref/contrib/gis/functions.txt17
-rw-r--r--docs/ref/contrib/gis/gdal.txt179
-rw-r--r--docs/ref/contrib/gis/geoip2.txt10
-rw-r--r--docs/ref/contrib/gis/geoquerysets.txt26
-rw-r--r--docs/ref/contrib/gis/geos.txt61
-rw-r--r--docs/ref/contrib/gis/install/postgis.txt7
-rw-r--r--docs/ref/contrib/gis/install/spatialite.txt2
-rw-r--r--docs/ref/contrib/gis/layermapping.txt27
-rw-r--r--docs/ref/contrib/gis/measure.txt20
-rw-r--r--docs/ref/contrib/gis/model-api.txt8
-rw-r--r--docs/ref/contrib/gis/serializers.txt32
-rw-r--r--docs/ref/contrib/gis/testing.txt18
-rw-r--r--docs/ref/contrib/gis/tutorial.txt118
-rw-r--r--docs/ref/contrib/messages.txt46
-rw-r--r--docs/ref/contrib/postgres/aggregates.txt36
-rw-r--r--docs/ref/contrib/postgres/constraints.txt36
-rw-r--r--docs/ref/contrib/postgres/expressions.txt4
-rw-r--r--docs/ref/contrib/postgres/fields.txt170
-rw-r--r--docs/ref/contrib/postgres/forms.txt42
-rw-r--r--docs/ref/contrib/postgres/indexes.txt12
-rw-r--r--docs/ref/contrib/postgres/lookups.txt2
-rw-r--r--docs/ref/contrib/postgres/operations.txt15
-rw-r--r--docs/ref/contrib/postgres/search.txt106
-rw-r--r--docs/ref/contrib/redirects.txt8
-rw-r--r--docs/ref/contrib/sitemaps.txt99
-rw-r--r--docs/ref/contrib/sites.txt38
-rw-r--r--docs/ref/contrib/staticfiles.txt14
-rw-r--r--docs/ref/contrib/syndication.txt97
-rw-r--r--docs/ref/csrf.txt5
-rw-r--r--docs/ref/databases.txt86
-rw-r--r--docs/ref/django-admin.txt18
-rw-r--r--docs/ref/files/file.txt4
-rw-r--r--docs/ref/forms/api.txt219
-rw-r--r--docs/ref/forms/fields.txt102
-rw-r--r--docs/ref/forms/renderers.txt3
-rw-r--r--docs/ref/forms/validation.txt66
-rw-r--r--docs/ref/forms/widgets.txt71
-rw-r--r--docs/ref/logging.txt151
-rw-r--r--docs/ref/middleware.txt1
-rw-r--r--docs/ref/migration-operations.txt28
-rw-r--r--docs/ref/models/class.txt1
-rw-r--r--docs/ref/models/conditional-expressions.txt120
-rw-r--r--docs/ref/models/constraints.txt16
-rw-r--r--docs/ref/models/database-functions.txt416
-rw-r--r--docs/ref/models/expressions.txt187
-rw-r--r--docs/ref/models/fields.txt158
-rw-r--r--docs/ref/models/indexes.txt6
-rw-r--r--docs/ref/models/instances.txt101
-rw-r--r--docs/ref/models/lookups.txt6
-rw-r--r--docs/ref/models/meta.txt6
-rw-r--r--docs/ref/models/options.txt34
-rw-r--r--docs/ref/models/querysets.txt368
-rw-r--r--docs/ref/models/relations.txt18
-rw-r--r--docs/ref/request-response.txt109
-rw-r--r--docs/ref/settings.txt150
-rw-r--r--docs/ref/signals.txt5
-rw-r--r--docs/ref/template-response.txt13
-rw-r--r--docs/ref/templates/api.txt199
-rw-r--r--docs/ref/templates/builtins.txt54
-rw-r--r--docs/ref/unicode.txt17
-rw-r--r--docs/ref/urlresolvers.txt23
-rw-r--r--docs/ref/urls.txt20
-rw-r--r--docs/ref/utils.txt62
-rw-r--r--docs/ref/validators.txt7
-rw-r--r--docs/ref/views.txt11
83 files changed, 2741 insertions, 2151 deletions
diff --git a/docs/ref/applications.txt b/docs/ref/applications.txt
index 916c309edd..00bf71239c 100644
--- a/docs/ref/applications.txt
+++ b/docs/ref/applications.txt
@@ -14,7 +14,7 @@ This registry is called :attr:`~django.apps.apps` and it's available in
.. code-block:: pycon
>>> from django.apps import apps
- >>> apps.get_app_config('admin').verbose_name
+ >>> apps.get_app_config("admin").verbose_name
'Administration'
Projects and applications
@@ -77,7 +77,7 @@ configuration class to specify it explicitly::
INSTALLED_APPS = [
...,
- 'polls.apps.PollsAppConfig',
+ "polls.apps.PollsAppConfig",
...,
]
@@ -91,8 +91,9 @@ would provide a proper name for the admin::
from django.apps import AppConfig
+
class RockNRollConfig(AppConfig):
- name = 'rock_n_roll'
+ name = "rock_n_roll"
verbose_name = "Rock ’n’ roll"
``RockNRollConfig`` will be loaded automatically when :setting:`INSTALLED_APPS`
@@ -134,13 +135,15 @@ configuration::
from rock_n_roll.apps import RockNRollConfig
+
class JazzManoucheConfig(RockNRollConfig):
verbose_name = "Jazz Manouche"
+
# anthology/settings.py
INSTALLED_APPS = [
- 'anthology.apps.JazzManoucheConfig',
+ "anthology.apps.JazzManoucheConfig",
# ...
]
@@ -289,10 +292,11 @@ Methods
def ready(self):
# importing model classes
from .models import MyModel # or...
- MyModel = self.get_model('MyModel')
+
+ MyModel = self.get_model("MyModel")
# registering signals with the model's string label
- pre_save.connect(receiver, sender='app_label.MyModel')
+ pre_save.connect(receiver, sender="app_label.MyModel")
.. warning::
diff --git a/docs/ref/class-based-views/base.txt b/docs/ref/class-based-views/base.txt
index 812e6d53fe..b1260093c1 100644
--- a/docs/ref/class-based-views/base.txt
+++ b/docs/ref/class-based-views/base.txt
@@ -34,10 +34,10 @@ MRO is an acronym for Method Resolution Order.
from django.http import HttpResponse
from django.views import View
- class MyView(View):
+ class MyView(View):
def get(self, request, *args, **kwargs):
- return HttpResponse('Hello, World!')
+ return HttpResponse("Hello, World!")
**Example urls.py**::
@@ -46,7 +46,7 @@ MRO is an acronym for Method Resolution Order.
from myapp.views import MyView
urlpatterns = [
- path('mine/', MyView.as_view(), name='my-view'),
+ path("mine/", MyView.as_view(), name="my-view"),
]
**Attributes**
@@ -57,7 +57,7 @@ MRO is an acronym for Method Resolution Order.
Default::
- ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
+ ["get", "post", "put", "patch", "delete", "head", "options", "trace"]
**Methods**
@@ -150,13 +150,13 @@ MRO is an acronym for Method Resolution Order.
from articles.models import Article
- class HomePageView(TemplateView):
+ class HomePageView(TemplateView):
template_name = "home.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context['latest_articles'] = Article.objects.all()[:5]
+ context["latest_articles"] = Article.objects.all()[:5]
return context
**Example urls.py**::
@@ -166,7 +166,7 @@ MRO is an acronym for Method Resolution Order.
from myapp.views import HomePageView
urlpatterns = [
- path('', HomePageView.as_view(), name='home'),
+ path("", HomePageView.as_view(), name="home"),
]
**Context**
@@ -213,14 +213,14 @@ MRO is an acronym for Method Resolution Order.
from articles.models import Article
- class ArticleCounterRedirectView(RedirectView):
+ class ArticleCounterRedirectView(RedirectView):
permanent = False
query_string = True
- pattern_name = 'article-detail'
+ pattern_name = "article-detail"
def get_redirect_url(self, *args, **kwargs):
- article = get_object_or_404(Article, pk=kwargs['pk'])
+ article = get_object_or_404(Article, pk=kwargs["pk"])
article.update_counter()
return super().get_redirect_url(*args, **kwargs)
@@ -232,9 +232,17 @@ MRO is an acronym for Method Resolution Order.
from article.views import ArticleCounterRedirectView, ArticleDetailView
urlpatterns = [
- path('counter/<int:pk>/', ArticleCounterRedirectView.as_view(), name='article-counter'),
- path('details/<int:pk>/', ArticleDetailView.as_view(), name='article-detail'),
- path('go-to-django/', RedirectView.as_view(url='https://www.djangoproject.com/'), name='go-to-django'),
+ path(
+ "counter/<int:pk>/",
+ ArticleCounterRedirectView.as_view(),
+ name="article-counter",
+ ),
+ path("details/<int:pk>/", ArticleDetailView.as_view(), name="article-detail"),
+ path(
+ "go-to-django/",
+ RedirectView.as_view(url="https://www.djangoproject.com/"),
+ name="go-to-django",
+ ),
]
**Attributes**
diff --git a/docs/ref/class-based-views/generic-date-based.txt b/docs/ref/class-based-views/generic-date-based.txt
index 59d41ae3d2..7f6bc5630d 100644
--- a/docs/ref/class-based-views/generic-date-based.txt
+++ b/docs/ref/class-based-views/generic-date-based.txt
@@ -15,12 +15,13 @@ views for displaying drilldown pages for date-based data.
from django.db import models
from django.urls import reverse
+
class Article(models.Model):
title = models.CharField(max_length=200)
pub_date = models.DateField()
def get_absolute_url(self):
- return reverse('article-detail', kwargs={'pk': self.pk})
+ return reverse("article-detail", kwargs={"pk": self.pk})
``ArchiveIndexView``
====================
@@ -69,9 +70,11 @@ views for displaying drilldown pages for date-based data.
from myapp.models import Article
urlpatterns = [
- path('archive/',
- ArchiveIndexView.as_view(model=Article, date_field="pub_date"),
- name="article_archive"),
+ path(
+ "archive/",
+ ArchiveIndexView.as_view(model=Article, date_field="pub_date"),
+ name="article_archive",
+ ),
]
**Example myapp/article_archive.html**:
@@ -154,6 +157,7 @@ views for displaying drilldown pages for date-based data.
from myapp.models import Article
+
class ArticleYearArchiveView(YearArchiveView):
queryset = Article.objects.all()
date_field = "pub_date"
@@ -167,9 +171,7 @@ views for displaying drilldown pages for date-based data.
from myapp.views import ArticleYearArchiveView
urlpatterns = [
- path('<int:year>/',
- ArticleYearArchiveView.as_view(),
- name="article_year_archive"),
+ path("<int:year>/", ArticleYearArchiveView.as_view(), name="article_year_archive"),
]
**Example myapp/article_archive_year.html**:
@@ -247,6 +249,7 @@ views for displaying drilldown pages for date-based data.
from myapp.models import Article
+
class ArticleMonthArchiveView(MonthArchiveView):
queryset = Article.objects.all()
date_field = "pub_date"
@@ -260,13 +263,17 @@ views for displaying drilldown pages for date-based data.
urlpatterns = [
# Example: /2012/08/
- path('<int:year>/<int:month>/',
- ArticleMonthArchiveView.as_view(month_format='%m'),
- name="archive_month_numeric"),
+ path(
+ "<int:year>/<int:month>/",
+ ArticleMonthArchiveView.as_view(month_format="%m"),
+ name="archive_month_numeric",
+ ),
# Example: /2012/aug/
- path('<int:year>/<str:month>/',
- ArticleMonthArchiveView.as_view(),
- name="archive_month"),
+ path(
+ "<int:year>/<str:month>/",
+ ArticleMonthArchiveView.as_view(),
+ name="archive_month",
+ ),
]
**Example myapp/article_archive_month.html**:
@@ -350,6 +357,7 @@ views for displaying drilldown pages for date-based data.
from myapp.models import Article
+
class ArticleWeekArchiveView(WeekArchiveView):
queryset = Article.objects.all()
date_field = "pub_date"
@@ -364,9 +372,11 @@ views for displaying drilldown pages for date-based data.
urlpatterns = [
# Example: /2012/week/23/
- path('<int:year>/week/<int:week>/',
- ArticleWeekArchiveView.as_view(),
- name="archive_week"),
+ path(
+ "<int:year>/week/<int:week>/",
+ ArticleWeekArchiveView.as_view(),
+ name="archive_week",
+ ),
]
**Example myapp/article_archive_week.html**:
@@ -463,6 +473,7 @@ views for displaying drilldown pages for date-based data.
from myapp.models import Article
+
class ArticleDayArchiveView(DayArchiveView):
queryset = Article.objects.all()
date_field = "pub_date"
@@ -476,9 +487,11 @@ views for displaying drilldown pages for date-based data.
urlpatterns = [
# Example: /2012/nov/10/
- path('<int:year>/<str:month>/<int:day>/',
- ArticleDayArchiveView.as_view(),
- name="archive_day"),
+ path(
+ "<int:year>/<str:month>/<int:day>/",
+ ArticleDayArchiveView.as_view(),
+ name="archive_day",
+ ),
]
**Example myapp/article_archive_day.html**:
@@ -536,6 +549,7 @@ views for displaying drilldown pages for date-based data.
from myapp.models import Article
+
class ArticleTodayArchiveView(TodayArchiveView):
queryset = Article.objects.all()
date_field = "pub_date"
@@ -548,9 +562,7 @@ views for displaying drilldown pages for date-based data.
from myapp.views import ArticleTodayArchiveView
urlpatterns = [
- path('today/',
- ArticleTodayArchiveView.as_view(),
- name="archive_today"),
+ path("today/", ArticleTodayArchiveView.as_view(), name="archive_today"),
]
.. admonition:: Where is the example template for ``TodayArchiveView``?
@@ -597,9 +609,11 @@ views for displaying drilldown pages for date-based data.
from django.views.generic.dates import DateDetailView
urlpatterns = [
- path('<int:year>/<str:month>/<int:day>/<int:pk>/',
- DateDetailView.as_view(model=Article, date_field="pub_date"),
- name="archive_date_detail"),
+ path(
+ "<int:year>/<str:month>/<int:day>/<int:pk>/",
+ DateDetailView.as_view(model=Article, date_field="pub_date"),
+ name="archive_date_detail",
+ ),
]
**Example myapp/article_detail.html**:
diff --git a/docs/ref/class-based-views/generic-display.txt b/docs/ref/class-based-views/generic-display.txt
index 625a43fa0c..731197da4b 100644
--- a/docs/ref/class-based-views/generic-display.txt
+++ b/docs/ref/class-based-views/generic-display.txt
@@ -44,13 +44,13 @@ many projects they are typically the most commonly used views.
from articles.models import Article
- class ArticleDetailView(DetailView):
+ class ArticleDetailView(DetailView):
model = Article
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context['now'] = timezone.now()
+ context["now"] = timezone.now()
return context
**Example myapp/urls.py**::
@@ -60,7 +60,7 @@ many projects they are typically the most commonly used views.
from article.views import ArticleDetailView
urlpatterns = [
- path('<slug:slug>/', ArticleDetailView.as_view(), name='article-detail'),
+ path("<slug:slug>/", ArticleDetailView.as_view(), name="article-detail"),
]
**Example myapp/article_detail.html**:
@@ -133,14 +133,14 @@ many projects they are typically the most commonly used views.
from articles.models import Article
- class ArticleListView(ListView):
+ class ArticleListView(ListView):
model = Article
paginate_by = 100 # if pagination is desired
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context['now'] = timezone.now()
+ context["now"] = timezone.now()
return context
**Example myapp/urls.py**::
@@ -150,7 +150,7 @@ many projects they are typically the most commonly used views.
from article.views import ArticleListView
urlpatterns = [
- path('', ArticleListView.as_view(), name='article-list'),
+ path("", ArticleListView.as_view(), name="article-list"),
]
**Example myapp/article_list.html**:
diff --git a/docs/ref/class-based-views/generic-editing.txt b/docs/ref/class-based-views/generic-editing.txt
index 84a8a4dda0..9bd543bdfc 100644
--- a/docs/ref/class-based-views/generic-editing.txt
+++ b/docs/ref/class-based-views/generic-editing.txt
@@ -24,11 +24,12 @@ editing content:
from django.db import models
from django.urls import reverse
+
class Author(models.Model):
name = models.CharField(max_length=200)
def get_absolute_url(self):
- return reverse('author-detail', kwargs={'pk': self.pk})
+ return reverse("author-detail", kwargs={"pk": self.pk})
``FormView``
============
@@ -52,6 +53,7 @@ editing content:
from django import forms
+
class ContactForm(forms.Form):
name = forms.CharField()
message = forms.CharField(widget=forms.Textarea)
@@ -65,10 +67,11 @@ editing content:
from myapp.forms import ContactForm
from django.views.generic.edit import FormView
+
class ContactFormView(FormView):
- template_name = 'contact.html'
+ template_name = "contact.html"
form_class = ContactForm
- success_url = '/thanks/'
+ success_url = "/thanks/"
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
@@ -141,9 +144,10 @@ editing content:
from django.views.generic.edit import CreateView
from myapp.models import Author
+
class AuthorCreateView(CreateView):
model = Author
- fields = ['name']
+ fields = ["name"]
**Example myapp/author_form.html**:
@@ -220,10 +224,11 @@ editing content:
from django.views.generic.edit import UpdateView
from myapp.models import Author
+
class AuthorUpdateView(UpdateView):
model = Author
- fields = ['name']
- template_name_suffix = '_update_form'
+ fields = ["name"]
+ template_name_suffix = "_update_form"
**Example myapp/author_update_form.html**:
@@ -307,9 +312,10 @@ editing content:
from django.views.generic.edit import DeleteView
from myapp.models import Author
+
class AuthorDeleteView(DeleteView):
model = Author
- success_url = reverse_lazy('author-list')
+ success_url = reverse_lazy("author-list")
**Example myapp/author_confirm_delete.html**:
diff --git a/docs/ref/class-based-views/index.txt b/docs/ref/class-based-views/index.txt
index 5187000385..0c2f20aee5 100644
--- a/docs/ref/class-based-views/index.txt
+++ b/docs/ref/class-based-views/index.txt
@@ -26,7 +26,7 @@ A class-based view is deployed into a URL pattern using the
:meth:`~django.views.generic.base.View.as_view()` classmethod::
urlpatterns = [
- path('view/', MyView.as_view(size=42)),
+ path("view/", MyView.as_view(size=42)),
]
.. admonition:: Thread safety with view arguments
diff --git a/docs/ref/class-based-views/mixins-multiple-object.txt b/docs/ref/class-based-views/mixins-multiple-object.txt
index 5049314d7c..4c6a1c5caa 100644
--- a/docs/ref/class-based-views/mixins-multiple-object.txt
+++ b/docs/ref/class-based-views/mixins-multiple-object.txt
@@ -15,7 +15,7 @@ Multiple object mixins
* Use the ``page`` parameter in the URLconf. For example, this is what
your URLconf might look like::
- path('objects/page<int:page>/', PaginatedView.as_view()),
+ path("objects/page<int:page>/", PaginatedView.as_view()),
* Pass the page number via the ``page`` query-string parameter. For
example, a URL would look like this:
diff --git a/docs/ref/class-based-views/mixins-simple.txt b/docs/ref/class-based-views/mixins-simple.txt
index 7a9542447b..bbd0875e75 100644
--- a/docs/ref/class-based-views/mixins-simple.txt
+++ b/docs/ref/class-based-views/mixins-simple.txt
@@ -16,7 +16,8 @@ Simple mixins
:meth:`~django.views.generic.base.View.as_view`. Example usage::
from django.views.generic import TemplateView
- TemplateView.as_view(extra_context={'title': 'Custom Title'})
+
+ TemplateView.as_view(extra_context={"title": "Custom Title"})
**Methods**
@@ -27,7 +28,7 @@ Simple mixins
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context['number'] = random.randrange(1, 100)
+ context["number"] = random.randrange(1, 100)
return context
The template context of all class-based generic views include a
diff --git a/docs/ref/clickjacking.txt b/docs/ref/clickjacking.txt
index 6f505e2fae..f9bec591a7 100644
--- a/docs/ref/clickjacking.txt
+++ b/docs/ref/clickjacking.txt
@@ -59,7 +59,7 @@ To set the same ``X-Frame-Options`` value for all responses in your site, put
MIDDLEWARE = [
...,
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ "django.middleware.clickjacking.XFrameOptionsMiddleware",
...,
]
@@ -70,7 +70,7 @@ By default, the middleware will set the ``X-Frame-Options`` header to
``DENY`` for every outgoing ``HttpResponse``. If you want any other value for
this header instead, set the :setting:`X_FRAME_OPTIONS` setting::
- X_FRAME_OPTIONS = 'SAMEORIGIN'
+ X_FRAME_OPTIONS = "SAMEORIGIN"
When using the middleware there may be some views where you do **not** want the
``X-Frame-Options`` header set. For those cases, you can use a view decorator
@@ -79,6 +79,7 @@ that tells the middleware not to set the header::
from django.http import HttpResponse
from django.views.decorators.clickjacking import xframe_options_exempt
+
@xframe_options_exempt
def ok_to_load_in_a_frame(request):
return HttpResponse("This page is safe to load in a frame on any site.")
@@ -99,10 +100,12 @@ decorators::
from django.views.decorators.clickjacking import xframe_options_deny
from django.views.decorators.clickjacking import xframe_options_sameorigin
+
@xframe_options_deny
def view_one(request):
return HttpResponse("I won't display in any frame!")
+
@xframe_options_sameorigin
def view_two(request):
return HttpResponse("Display in a frame if it's from the same origin as me.")
diff --git a/docs/ref/contrib/admin/actions.txt b/docs/ref/contrib/admin/actions.txt
index 56e8d7feae..37c5be7ace 100644
--- a/docs/ref/contrib/admin/actions.txt
+++ b/docs/ref/contrib/admin/actions.txt
@@ -48,11 +48,12 @@ news application with an ``Article`` model::
from django.db import models
STATUS_CHOICES = [
- ('d', 'Draft'),
- ('p', 'Published'),
- ('w', 'Withdrawn'),
+ ("d", "Draft"),
+ ("p", "Published"),
+ ("w", "Withdrawn"),
]
+
class Article(models.Model):
title = models.CharField(max_length=100)
body = models.TextField()
@@ -83,7 +84,7 @@ Our publish-these-articles function won't need the :class:`ModelAdmin` or the
request object, but we will use the queryset::
def make_published(modeladmin, request, queryset):
- queryset.update(status='p')
+ queryset.update(status="p")
.. note::
@@ -107,9 +108,10 @@ function::
...
- @admin.action(description='Mark selected stories as published')
+
+ @admin.action(description="Mark selected stories as published")
def make_published(modeladmin, request, queryset):
- queryset.update(status='p')
+ queryset.update(status="p")
.. note::
@@ -129,15 +131,18 @@ the action and its registration would look like::
from django.contrib import admin
from myapp.models import Article
- @admin.action(description='Mark selected stories as published')
+
+ @admin.action(description="Mark selected stories as published")
def make_published(modeladmin, request, queryset):
- queryset.update(status='p')
+ queryset.update(status="p")
+
class ArticleAdmin(admin.ModelAdmin):
- list_display = ['title', 'status']
- ordering = ['title']
+ list_display = ["title", "status"]
+ ordering = ["title"]
actions = [make_published]
+
admin.site.register(Article, ArticleAdmin)
That code will give us an admin change list that looks something like this:
@@ -176,11 +181,11 @@ You can do it like this::
class ArticleAdmin(admin.ModelAdmin):
...
- actions = ['make_published']
+ actions = ["make_published"]
- @admin.action(description='Mark selected stories as published')
+ @admin.action(description="Mark selected stories as published")
def make_published(self, request, queryset):
- queryset.update(status='p')
+ queryset.update(status="p")
Notice first that we've moved ``make_published`` into a method and renamed the
``modeladmin`` parameter to ``self``, and second that we've now put the string
@@ -199,16 +204,22 @@ that the action was successful::
from django.contrib import messages
from django.utils.translation import ngettext
+
class ArticleAdmin(admin.ModelAdmin):
...
def make_published(self, request, queryset):
- updated = queryset.update(status='p')
- self.message_user(request, ngettext(
- '%d story was successfully marked as published.',
- '%d stories were successfully marked as published.',
- updated,
- ) % updated, messages.SUCCESS)
+ updated = queryset.update(status="p")
+ self.message_user(
+ request,
+ ngettext(
+ "%d story was successfully marked as published.",
+ "%d stories were successfully marked as published.",
+ updated,
+ )
+ % updated,
+ messages.SUCCESS,
+ )
This make the action match what the admin itself does after successfully
performing an action:
@@ -231,6 +242,7 @@ dump some selected objects as JSON::
from django.core import serializers
from django.http import HttpResponse
+
def export_as_json(modeladmin, request, queryset):
response = HttpResponse(content_type="application/json")
serializers.serialize("json", queryset, stream=response)
@@ -249,13 +261,17 @@ that redirects to your custom export view::
from django.contrib.contenttypes.models import ContentType
from django.http import HttpResponseRedirect
+
def export_selected_objects(modeladmin, request, queryset):
- selected = queryset.values_list('pk', flat=True)
+ selected = queryset.values_list("pk", flat=True)
ct = ContentType.objects.get_for_model(queryset.model)
- return HttpResponseRedirect('/export/?ct=%s&ids=%s' % (
- ct.pk,
- ','.join(str(pk) for pk in selected),
- ))
+ return HttpResponseRedirect(
+ "/export/?ct=%s&ids=%s"
+ % (
+ ct.pk,
+ ",".join(str(pk) for pk in selected),
+ )
+ )
As you can see, the action is rather short; all the complex logic would belong
in your export view. This would need to deal with objects of any type, hence
@@ -285,7 +301,7 @@ Making actions available site-wide
<disabling-admin-actions>` -- by passing a second argument to
:meth:`AdminSite.add_action()`::
- admin.site.add_action(export_selected_objects, 'export_selected')
+ admin.site.add_action(export_selected_objects, "export_selected")
.. _disabling-admin-actions:
@@ -307,7 +323,7 @@ Disabling a site-wide action
For example, you can use this method to remove the built-in "delete selected
objects" action::
- admin.site.disable_action('delete_selected')
+ admin.site.disable_action("delete_selected")
Once you've done the above, that action will no longer be available
site-wide.
@@ -316,16 +332,18 @@ Disabling a site-wide action
particular model, list it explicitly in your ``ModelAdmin.actions`` list::
# Globally disable delete selected
- admin.site.disable_action('delete_selected')
+ admin.site.disable_action("delete_selected")
+
# This ModelAdmin will not have delete_selected available
class SomeModelAdmin(admin.ModelAdmin):
- actions = ['some_other_action']
+ actions = ["some_other_action"]
...
+
# This one will
class AnotherModelAdmin(admin.ModelAdmin):
- actions = ['delete_selected', 'a_third_action']
+ actions = ["delete_selected", "a_third_action"]
...
@@ -360,9 +378,9 @@ Conditionally enabling or disabling actions
def get_actions(self, request):
actions = super().get_actions(request)
- if request.user.username[0].upper() != 'J':
- if 'delete_selected' in actions:
- del actions['delete_selected']
+ if request.user.username[0].upper() != "J":
+ if "delete_selected" in actions:
+ del actions["delete_selected"]
return actions
.. _admin-action-permissions:
@@ -374,9 +392,9 @@ Actions may limit their availability to users with specific permissions by
wrapping the action function with the :func:`~django.contrib.admin.action`
decorator and passing the ``permissions`` argument::
- @admin.action(permissions=['change'])
+ @admin.action(permissions=["change"])
def make_published(modeladmin, request, queryset):
- queryset.update(status='p')
+ queryset.update(status="p")
The ``make_published()`` action will only be available to users that pass the
:meth:`.ModelAdmin.has_change_permission` check.
@@ -399,18 +417,19 @@ For example::
from django.contrib import admin
from django.contrib.auth import get_permission_codename
+
class ArticleAdmin(admin.ModelAdmin):
- actions = ['make_published']
+ actions = ["make_published"]
- @admin.action(permissions=['publish'])
+ @admin.action(permissions=["publish"])
def make_published(self, request, queryset):
- queryset.update(status='p')
+ queryset.update(status="p")
def has_publish_permission(self, request):
"""Does the user have the publish permission?"""
opts = self.opts
- codename = get_permission_codename('publish', opts)
- return request.user.has_perm('%s.%s' % (opts.app_label, codename))
+ codename = get_permission_codename("publish", opts)
+ return request.user.has_perm("%s.%s" % (opts.app_label, codename))
The ``action`` decorator
========================
@@ -422,19 +441,21 @@ The ``action`` decorator
:attr:`~django.contrib.admin.ModelAdmin.actions`::
@admin.action(
- permissions=['publish'],
- description='Mark selected stories as published',
+ permissions=["publish"],
+ description="Mark selected stories as published",
)
def make_published(self, request, queryset):
- queryset.update(status='p')
+ queryset.update(status="p")
This is equivalent to setting some attributes (with the original, longer
names) on the function directly::
def make_published(self, request, queryset):
- queryset.update(status='p')
- make_published.allowed_permissions = ['publish']
- make_published.short_description = 'Mark selected stories as published'
+ queryset.update(status="p")
+
+
+ make_published.allowed_permissions = ["publish"]
+ make_published.short_description = "Mark selected stories as published"
Use of this decorator is not compulsory to make an action function, but it
can be useful to use it without arguments as a marker in your source to
diff --git a/docs/ref/contrib/admin/admindocs.txt b/docs/ref/contrib/admin/admindocs.txt
index 5a95e101ed..cc121a7bed 100644
--- a/docs/ref/contrib/admin/admindocs.txt
+++ b/docs/ref/contrib/admin/admindocs.txt
@@ -62,11 +62,13 @@ A model with useful documentation might look like this::
Stores a single blog entry, related to :model:`blog.Blog` and
:model:`auth.User`.
"""
+
slug = models.SlugField(help_text="A short label, generally used in URLs.")
author = models.ForeignKey(
User,
models.SET_NULL,
- blank=True, null=True,
+ blank=True,
+ null=True,
)
blog = models.ForeignKey(Blog, models.CASCADE)
...
@@ -92,6 +94,7 @@ For example::
from myapp.models import MyModel
+
def my_view(request, slug):
"""
Display an individual :model:`myapp.MyModel`.
@@ -105,8 +108,8 @@ For example::
:template:`myapp/my_template.html`
"""
- context = {'mymodel': MyModel.objects.get(slug=slug)}
- return render(request, 'myapp/my_template.html', context)
+ context = {"mymodel": MyModel.objects.get(slug=slug)}
+ return render(request, "myapp/my_template.html", context)
Template tags and filters reference
===================================
diff --git a/docs/ref/contrib/admin/filters.txt b/docs/ref/contrib/admin/filters.txt
index a3d7bfc9cd..ca8881a645 100644
--- a/docs/ref/contrib/admin/filters.txt
+++ b/docs/ref/contrib/admin/filters.txt
@@ -33,13 +33,13 @@ Each specified field should be either a ``BooleanField``, ``CharField``,
``ManyToManyField``, for example::
class PersonAdmin(admin.ModelAdmin):
- list_filter = ['is_staff', 'company']
+ list_filter = ["is_staff", "company"]
Field names in ``list_filter`` can also span relations
using the ``__`` lookup, for example::
class PersonAdmin(admin.UserAdmin):
- list_filter = ['company__name']
+ list_filter = ["company__name"]
Using a ``SimpleListFilter``
============================
@@ -54,13 +54,14 @@ and ``parameter_name`` attributes, and override the ``lookups`` and
from django.contrib import admin
from django.utils.translation import gettext_lazy as _
+
class DecadeBornListFilter(admin.SimpleListFilter):
# Human-readable title which will be displayed in the
# right admin sidebar just above the filter options.
- title = _('decade born')
+ title = _("decade born")
# Parameter for the filter that will be used in the URL query.
- parameter_name = 'decade'
+ parameter_name = "decade"
def lookups(self, request, model_admin):
"""
@@ -71,8 +72,8 @@ and ``parameter_name`` attributes, and override the ``lookups`` and
in the right sidebar.
"""
return [
- ('80s', _('in the eighties')),
- ('90s', _('in the nineties')),
+ ("80s", _("in the eighties")),
+ ("90s", _("in the nineties")),
]
def queryset(self, request, queryset):
@@ -83,17 +84,18 @@ and ``parameter_name`` attributes, and override the ``lookups`` and
"""
# Compare the requested value (either '80s' or '90s')
# to decide how to filter the queryset.
- if self.value() == '80s':
+ if self.value() == "80s":
return queryset.filter(
birthday__gte=date(1980, 1, 1),
birthday__lte=date(1989, 12, 31),
)
- if self.value() == '90s':
+ if self.value() == "90s":
return queryset.filter(
birthday__gte=date(1990, 1, 1),
birthday__lte=date(1999, 12, 31),
)
+
class PersonAdmin(admin.ModelAdmin):
list_filter = [DecadeBornListFilter]
@@ -103,7 +105,6 @@ and ``parameter_name`` attributes, and override the ``lookups`` and
and ``queryset`` methods, for example::
class AuthDecadeBornListFilter(DecadeBornListFilter):
-
def lookups(self, request, model_admin):
if request.user.is_superuser:
return super().lookups(request, model_admin)
@@ -117,7 +118,6 @@ and ``parameter_name`` attributes, and override the ``lookups`` and
available data::
class AdvancedDecadeBornListFilter(DecadeBornListFilter):
-
def lookups(self, request, model_admin):
"""
Only show the lookups if there actually is
@@ -128,12 +128,12 @@ and ``parameter_name`` attributes, and override the ``lookups`` and
birthday__gte=date(1980, 1, 1),
birthday__lte=date(1989, 12, 31),
).exists():
- yield ('80s', _('in the eighties'))
+ yield ("80s", _("in the eighties"))
if qs.filter(
birthday__gte=date(1990, 1, 1),
birthday__lte=date(1999, 12, 31),
).exists():
- yield ('90s', _('in the nineties'))
+ yield ("90s", _("in the nineties"))
Using a field name and an explicit ``FieldListFilter``
======================================================
@@ -145,7 +145,7 @@ field name and the second element is a class inheriting from
class PersonAdmin(admin.ModelAdmin):
list_filter = [
- ('is_staff', admin.BooleanFieldListFilter),
+ ("is_staff", admin.BooleanFieldListFilter),
]
Here the ``is_staff`` field will use the ``BooleanFieldListFilter``. Specifying
@@ -160,7 +160,7 @@ that relation using ``RelatedOnlyFieldListFilter``::
class BookAdmin(admin.ModelAdmin):
list_filter = [
- ('author', admin.RelatedOnlyFieldListFilter),
+ ("author", admin.RelatedOnlyFieldListFilter),
]
Assuming ``author`` is a ``ForeignKey`` to a ``User`` model, this will
@@ -173,7 +173,7 @@ allows to store::
class BookAdmin(admin.ModelAdmin):
list_filter = [
- ('title', admin.EmptyFieldListFilter),
+ ("title", admin.EmptyFieldListFilter),
]
By defining a filter using the ``__in`` lookup, it is possible to filter for
@@ -186,10 +186,10 @@ the separator::
class FilterWithCustomSeparator(admin.FieldListFilter):
# custom list separator that should be used to separate values.
- list_separator = '|'
+ list_separator = "|"
def __init__(self, field, request, params, model, model_admin, field_path):
- self.lookup_kwarg = '%s__in' % field_path
+ self.lookup_kwarg = "%s__in" % field_path
super().__init__(field, request, params, model, model_admin, field_path)
def expected_parameters(self):
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index fcc4f795eb..67007baef2 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -89,8 +89,11 @@ Other topics
from django.contrib import admin
from myapp.models import Author
+
class AuthorAdmin(admin.ModelAdmin):
pass
+
+
admin.site.register(Author, AuthorAdmin)
.. admonition:: Do you need a ``ModelAdmin`` object at all?
@@ -117,6 +120,7 @@ The ``register`` decorator
from django.contrib import admin
from .models import Author
+
@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
pass
@@ -129,6 +133,7 @@ The ``register`` decorator
from .models import Author, Editor, Reader
from myproject.admin_site import custom_admin_site
+
@admin.register(Author, Reader, Editor, site=custom_admin_site)
class PersonAdmin(admin.ModelAdmin):
pass
@@ -185,8 +190,9 @@ subclass::
from django.contrib import admin
+
class AuthorAdmin(admin.ModelAdmin):
- date_hierarchy = 'pub_date'
+ date_hierarchy = "pub_date"
.. attribute:: ModelAdmin.actions
@@ -214,12 +220,12 @@ subclass::
Example::
- date_hierarchy = 'pub_date'
+ date_hierarchy = "pub_date"
You can also specify a field on a related model using the ``__`` lookup,
for example::
- date_hierarchy = 'author__pub_date'
+ date_hierarchy = "author__pub_date"
This will intelligently populate itself based on available data,
e.g. if all the dates are in one month, it'll show the day-level
@@ -240,18 +246,20 @@ subclass::
from django.contrib import admin
+
class AuthorAdmin(admin.ModelAdmin):
- empty_value_display = '-empty-'
+ empty_value_display = "-empty-"
You can also override ``empty_value_display`` for all admin pages with
:attr:`AdminSite.empty_value_display`, or for specific fields like this::
from django.contrib import admin
+
class AuthorAdmin(admin.ModelAdmin):
- list_display = ['name', 'title', 'view_birth_date']
+ list_display = ["name", "title", "view_birth_date"]
- @admin.display(empty_value='???')
+ @admin.display(empty_value="???")
def view_birth_date(self, obj):
return obj.birth_date
@@ -264,6 +272,7 @@ subclass::
from django.db import models
+
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3)
@@ -275,11 +284,13 @@ subclass::
from django.contrib import admin
+
class AuthorAdmin(admin.ModelAdmin):
- fields = ['name', 'title']
+ fields = ["name", "title"]
+
class AuthorAdmin(admin.ModelAdmin):
- exclude = ['birth_date']
+ exclude = ["birth_date"]
Since the Author model only has three fields, ``name``, ``title``, and
``birth_date``, the forms resulting from the above declarations will
@@ -294,7 +305,7 @@ subclass::
:class:`django.contrib.flatpages.models.FlatPage` model as follows::
class FlatPageAdmin(admin.ModelAdmin):
- fields = ['url', 'title', 'content']
+ fields = ["url", "title", "content"]
In the above example, only the fields ``url``, ``title`` and ``content``
will be displayed, sequentially, in the form. ``fields`` can contain
@@ -314,7 +325,7 @@ subclass::
own line::
class FlatPageAdmin(admin.ModelAdmin):
- fields = [('url', 'title'), 'content']
+ fields = [("url", "title"), "content"]
.. admonition:: Note
@@ -345,15 +356,22 @@ subclass::
from django.contrib import admin
+
class FlatPageAdmin(admin.ModelAdmin):
fieldsets = [
- (None, {
- 'fields': ['url', 'title', 'content', 'sites'],
- }),
- ('Advanced options', {
- 'classes': ['collapse'],
- 'fields': ['registration_required', 'template_name'],
- }),
+ (
+ None,
+ {
+ "fields": ["url", "title", "content", "sites"],
+ },
+ ),
+ (
+ "Advanced options",
+ {
+ "classes": ["collapse"],
+ "fields": ["registration_required", "template_name"],
+ },
+ ),
]
This results in an admin page that looks like:
@@ -374,7 +392,7 @@ subclass::
Example::
{
- 'fields': ['first_name', 'last_name', 'address', 'city', 'state'],
+ "fields": ["first_name", "last_name", "address", "city", "state"],
}
As with the :attr:`~ModelAdmin.fields` option, to display multiple
@@ -383,7 +401,7 @@ subclass::
the same line::
{
- 'fields': [('first_name', 'last_name'), 'address', 'city', 'state'],
+ "fields": [("first_name", "last_name"), "address", "city", "state"],
}
``fields`` can contain values defined in
@@ -399,7 +417,7 @@ subclass::
Example::
{
- 'classes': ['wide', 'extrapretty'],
+ "classes": ["wide", "extrapretty"],
}
Two useful classes defined by the default admin site stylesheet are
@@ -471,14 +489,15 @@ subclass::
from django.contrib import admin
from myapp.models import Person
- class PersonForm(forms.ModelForm):
+ class PersonForm(forms.ModelForm):
class Meta:
model = Person
- exclude = ['name']
+ exclude = ["name"]
+
class PersonAdmin(admin.ModelAdmin):
- exclude = ['age']
+ exclude = ["age"]
form = PersonForm
In the above example, the "age" field will be excluded but the "name"
@@ -504,9 +523,10 @@ subclass::
from myapp.models import MyModel
from myapp.widgets import RichTextEditorWidget
+
class MyModelAdmin(admin.ModelAdmin):
formfield_overrides = {
- models.TextField: {'widget': RichTextEditorWidget},
+ models.TextField: {"widget": RichTextEditorWidget},
}
Note that the key in the dictionary is the actual field class, *not* a
@@ -540,7 +560,7 @@ subclass::
Example::
- list_display = ['first_name', 'last_name']
+ list_display = ["first_name", "last_name"]
If you don't set ``list_display``, the admin site will display a single
column that displays the ``__str__()`` representation of each object.
@@ -552,14 +572,15 @@ subclass::
* The name of a model field. For example::
class PersonAdmin(admin.ModelAdmin):
- list_display = ['first_name', 'last_name']
+ list_display = ["first_name", "last_name"]
* A callable that accepts one argument, the model instance. For example::
- @admin.display(description='Name')
+ @admin.display(description="Name")
def upper_case_name(obj):
return f"{obj.first_name} {obj.last_name}".upper()
+
class PersonAdmin(admin.ModelAdmin):
list_display = [upper_case_name]
@@ -567,9 +588,9 @@ subclass::
the model instance. For example::
class PersonAdmin(admin.ModelAdmin):
- list_display = ['upper_case_name']
+ list_display = ["upper_case_name"]
- @admin.display(description='Name')
+ @admin.display(description="Name")
def upper_case_name(self, obj):
return f"{obj.first_name} {obj.last_name}".upper()
@@ -579,17 +600,19 @@ subclass::
from django.contrib import admin
from django.db import models
+
class Person(models.Model):
name = models.CharField(max_length=50)
birthday = models.DateField()
- @admin.display(description='Birth decade')
+ @admin.display(description="Birth decade")
def decade_born_in(self):
decade = self.birthday.year // 10 * 10
- return f'{decade}’s'
+ return f"{decade}’s"
+
class PersonAdmin(admin.ModelAdmin):
- list_display = ['name', 'decade_born_in']
+ list_display = ["name", "decade_born_in"]
A few special cases to note about ``list_display``:
@@ -616,6 +639,7 @@ subclass::
from django.db import models
from django.utils.html import format_html
+
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
@@ -630,8 +654,9 @@ subclass::
self.last_name,
)
+
class PersonAdmin(admin.ModelAdmin):
- list_display = ['first_name', 'last_name', 'colored_name']
+ list_display = ["first_name", "last_name", "colored_name"]
* As some examples have already demonstrated, when using a callable, a
model method, or a ``ModelAdmin`` method, you can customize the column's
@@ -645,21 +670,21 @@ subclass::
from django.contrib import admin
- admin.site.empty_value_display = '(None)'
+ admin.site.empty_value_display = "(None)"
You can also use :attr:`ModelAdmin.empty_value_display`::
class PersonAdmin(admin.ModelAdmin):
- empty_value_display = 'unknown'
+ empty_value_display = "unknown"
Or on a field level::
class PersonAdmin(admin.ModelAdmin):
- list_display = ['name', 'birth_date_view']
+ list_display = ["name", "birth_date_view"]
- @admin.display(empty_value='unknown')
+ @admin.display(empty_value="unknown")
def birth_date_view(self, obj):
- return obj.birth_date
+ return obj.birth_date
* If the string given is a method of the model, ``ModelAdmin`` or a
callable that returns ``True``, ``False``, or ``None``, Django will
@@ -670,6 +695,7 @@ subclass::
from django.contrib import admin
from django.db import models
+
class Person(models.Model):
first_name = models.CharField(max_length=50)
birthday = models.DateField()
@@ -678,13 +704,14 @@ subclass::
def born_in_fifties(self):
return 1950 <= self.birthday.year < 1960
+
class PersonAdmin(admin.ModelAdmin):
- list_display = ['name', 'born_in_fifties']
+ list_display = ["name", "born_in_fifties"]
* The ``__str__()`` method is just as valid in ``list_display`` as any
other model method, so it's perfectly OK to do this::
- list_display = ['__str__', 'some_other_field']
+ list_display = ["__str__", "some_other_field"]
* Usually, elements of ``list_display`` that aren't actual database
fields can't be used in sorting (because Django does all the sorting
@@ -699,11 +726,12 @@ subclass::
from django.db import models
from django.utils.html import format_html
+
class Person(models.Model):
first_name = models.CharField(max_length=50)
color_code = models.CharField(max_length=6)
- @admin.display(ordering='first_name')
+ @admin.display(ordering="first_name")
def colored_first_name(self):
return format_html(
'<span style="color: #{};">{}</span>',
@@ -711,8 +739,9 @@ subclass::
self.first_name,
)
+
class PersonAdmin(admin.ModelAdmin):
- list_display = ['first_name', 'colored_first_name']
+ list_display = ["first_name", "colored_first_name"]
The above will tell Django to order by the ``first_name`` field when
trying to sort by ``colored_first_name`` in the admin.
@@ -721,7 +750,7 @@ subclass::
hyphen prefix on the field name. Using the above example, this would look
like::
- @admin.display(ordering='-first_name')
+ @admin.display(ordering="-first_name")
def colored_first_name(self):
...
@@ -733,10 +762,11 @@ subclass::
title = models.CharField(max_length=255)
author = models.ForeignKey(Person, on_delete=models.CASCADE)
+
class BlogAdmin(admin.ModelAdmin):
- list_display = ['title', 'author', 'author_first_name']
+ list_display = ["title", "author", "author_first_name"]
- @admin.display(ordering='author__first_name')
+ @admin.display(ordering="author__first_name")
def author_first_name(self, obj):
return obj.author.first_name
@@ -746,13 +776,14 @@ subclass::
from django.db.models import Value
from django.db.models.functions import Concat
+
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
- @admin.display(ordering=Concat('first_name', Value(' '), 'last_name'))
+ @admin.display(ordering=Concat("first_name", Value(" "), "last_name"))
def full_name(self):
- return self.first_name + ' ' + self.last_name
+ return self.first_name + " " + self.last_name
* Elements of ``list_display`` can also be properties
::
@@ -763,14 +794,15 @@ subclass::
@property
@admin.display(
- ordering='last_name',
- description='Full name of the person',
+ ordering="last_name",
+ description="Full name of the person",
)
def full_name(self):
- return self.first_name + ' ' + self.last_name
+ return self.first_name + " " + self.last_name
+
class PersonAdmin(admin.ModelAdmin):
- list_display = ['full_name']
+ list_display = ["full_name"]
Note that ``@property`` must be above ``@display``. If you're using the
old way -- setting the display-related attributes directly rather than
@@ -779,9 +811,11 @@ subclass::
must be used::
def my_property(self):
- return self.first_name + ' ' + self.last_name
+ return self.first_name + " " + self.last_name
+
+
my_property.short_description = "Full name of the person"
- my_property.admin_order_field = 'last_name'
+ my_property.admin_order_field = "last_name"
full_name = property(my_property)
@@ -823,13 +857,13 @@ subclass::
linked on the change list page::
class PersonAdmin(admin.ModelAdmin):
- list_display = ['first_name', 'last_name', 'birthday']
- list_display_links = ['first_name', 'last_name']
+ list_display = ["first_name", "last_name", "birthday"]
+ list_display_links = ["first_name", "last_name"]
In this example, the change list page grid will have no links::
class AuditEntryAdmin(admin.ModelAdmin):
- list_display = ['timestamp', 'message']
+ list_display = ["timestamp", "message"]
list_display_links = None
.. _admin-list-editable:
@@ -896,7 +930,7 @@ subclass::
``select_related`` as parameters. For example::
class ArticleAdmin(admin.ModelAdmin):
- list_select_related = ['author', 'category']
+ list_select_related = ["author", "category"]
will call ``select_related('author', 'category')``.
@@ -1013,11 +1047,12 @@ subclass::
``question_text`` field and ordered by the ``date_created`` field::
class QuestionAdmin(admin.ModelAdmin):
- ordering = ['date_created']
- search_fields = ['question_text']
+ ordering = ["date_created"]
+ search_fields = ["question_text"]
+
class ChoiceAdmin(admin.ModelAdmin):
- autocomplete_fields = ['question']
+ autocomplete_fields = ["question"]
.. admonition:: Performance considerations for large datasets
@@ -1084,18 +1119,19 @@ subclass::
from django.utils.html import format_html_join
from django.utils.safestring import mark_safe
+
class PersonAdmin(admin.ModelAdmin):
- readonly_fields = ['address_report']
+ readonly_fields = ["address_report"]
# description functions like a model field's verbose_name
- @admin.display(description='Address')
+ @admin.display(description="Address")
def address_report(self, instance):
# assuming get_full_address() returns a list of strings
# for each line of the address and you want to separate each
# line by a linebreak
return format_html_join(
- mark_safe('<br>'),
- '{}',
+ mark_safe("<br>"),
+ "{}",
((line,) for line in instance.get_full_address()),
) or mark_safe("<span class='errors'>I can't determine this address.</span>")
@@ -1139,13 +1175,13 @@ subclass::
``TextField``. You can also perform a related lookup on a ``ForeignKey`` or
``ManyToManyField`` with the lookup API "follow" notation::
- search_fields = ['foreign_key__related_fieldname']
+ search_fields = ["foreign_key__related_fieldname"]
For example, if you have a blog entry with an author, the following
definition would enable searching blog entries by the email address of the
author::
- search_fields = ['user__email']
+ search_fields = ["user__email"]
When somebody does a search in the admin search box, Django splits the
search query into words and returns all objects that contain each of the
@@ -1235,6 +1271,7 @@ subclass::
from django.contrib import admin
+
class PersonAdmin(admin.ModelAdmin):
view_on_site = False
@@ -1244,10 +1281,11 @@ subclass::
from django.contrib import admin
from django.urls import reverse
+
class PersonAdmin(admin.ModelAdmin):
def view_on_site(self, obj):
- url = reverse('person-detail', kwargs={'slug': obj.slug})
- return 'https://example.com' + url
+ url = reverse("person-detail", kwargs={"slug": obj.slug})
+ return "https://example.com" + url
Custom template options
~~~~~~~~~~~~~~~~~~~~~~~
@@ -1312,6 +1350,7 @@ templates used by the :class:`ModelAdmin` views:
from django.contrib import admin
+
class ArticleAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
obj.user = request.user
@@ -1359,12 +1398,11 @@ templates used by the :class:`ModelAdmin` views:
to the :attr:`ordering` attribute. For example::
class PersonAdmin(admin.ModelAdmin):
-
def get_ordering(self, request):
if request.user.is_superuser:
- return ['name', 'rank']
+ return ["name", "rank"]
else:
- return ['name']
+ return ["name"]
.. method:: ModelAdmin.get_search_results(request, queryset, search_term)
@@ -1385,12 +1423,14 @@ templates used by the :class:`ModelAdmin` views:
For example, to search by ``name`` and ``age``, you could use::
class PersonAdmin(admin.ModelAdmin):
- list_display = ['name', 'age']
- search_fields = ['name']
+ list_display = ["name", "age"]
+ search_fields = ["name"]
def get_search_results(self, request, queryset, search_term):
queryset, may_have_duplicates = super().get_search_results(
- request, queryset, search_term,
+ request,
+ queryset,
+ search_term,
)
try:
search_term_as_int = int(search_term)
@@ -1501,9 +1541,8 @@ templates used by the :class:`ModelAdmin` views:
For example, to prevent one or more columns from being sortable::
class PersonAdmin(admin.ModelAdmin):
-
def get_sortable_by(self, request):
- return {*self.get_list_display(request)} - {'rank'}
+ return {*self.get_list_display(request)} - {"rank"}
.. method:: ModelAdmin.get_inline_instances(request, obj=None)
@@ -1543,21 +1582,20 @@ templates used by the :class:`ModelAdmin` views:
from django.template.response import TemplateResponse
from django.urls import path
+
class MyModelAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super().get_urls()
- my_urls = [
- path('my_view/', self.admin_site.admin_view(self.my_view))
- ]
+ my_urls = [path("my_view/", self.admin_site.admin_view(self.my_view))]
return my_urls + urls
def my_view(self, request):
# ...
context = dict(
- # Include common variables for rendering the admin template.
- self.admin_site.each_context(request),
- # Anything else you want in the context...
- key=value,
+ # Include common variables for rendering the admin template.
+ self.admin_site.each_context(request),
+ # Anything else you want in the context...
+ key=value,
)
return TemplateResponse(request, "sometemplate.html", context)
@@ -1597,7 +1635,7 @@ templates used by the :class:`ModelAdmin` views:
performed, you can pass a ``cacheable=True`` argument to
``AdminSite.admin_view()``::
- path('my_view/', self.admin_site.admin_view(self.my_view, cacheable=True))
+ path("my_view/", self.admin_site.admin_view(self.my_view, cacheable=True))
``ModelAdmin`` views have ``model_admin`` attributes. Other
``AdminSite`` views have ``admin_site`` attributes.
@@ -1615,7 +1653,7 @@ templates used by the :class:`ModelAdmin` views:
class MyModelAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
if request.user.is_superuser:
- kwargs['form'] = MySuperuserForm
+ kwargs["form"] = MySuperuserForm
return super().get_form(request, obj, **kwargs)
You may also return a custom :class:`~django.forms.ModelForm` class
@@ -1660,7 +1698,8 @@ templates used by the :class:`ModelAdmin` views:
class CountryAdminForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['capital'].queryset = self.instance.cities.all()
+ self.fields["capital"].queryset = self.instance.cities.all()
+
class CountryAdmin(admin.ModelAdmin):
form = CountryAdminForm
@@ -1691,12 +1730,12 @@ templates used by the :class:`ModelAdmin` views:
class MyModelAdmin(admin.ModelAdmin):
def formfield_for_choice_field(self, db_field, request, **kwargs):
if db_field.name == "status":
- kwargs['choices'] = [
- ('accepted', 'Accepted'),
- ('denied', 'Denied'),
+ kwargs["choices"] = [
+ ("accepted", "Accepted"),
+ ("denied", "Denied"),
]
if request.user.is_superuser:
- kwargs['choices'].append(('ready', 'Ready for deployment'))
+ kwargs["choices"].append(("ready", "Ready for deployment"))
return super().formfield_for_choice_field(db_field, request, **kwargs)
.. admonition:: Note
@@ -1721,9 +1760,11 @@ templates used by the :class:`ModelAdmin` views:
from django import forms
+
class MyForm(forms.ModelForm):
pass
+
class MyModelAdmin(admin.ModelAdmin):
def get_changelist_form(self, request, **kwargs):
return MyForm
@@ -1746,12 +1787,14 @@ templates used by the :class:`ModelAdmin` views:
from django.forms import BaseModelFormSet
+
class MyAdminFormSet(BaseModelFormSet):
pass
+
class MyModelAdmin(admin.ModelAdmin):
def get_changelist_formset(self, request, **kwargs):
- kwargs['formset'] = MyAdminFormSet
+ kwargs["formset"] = MyAdminFormSet
return super().get_changelist_formset(request, **kwargs)
.. method:: ModelAdmin.lookup_allowed(lookup, value)
@@ -1898,7 +1941,7 @@ templates used by the :class:`ModelAdmin` views:
def get_formset_kwargs(self, request, obj, inline, prefix):
return {
**super().get_formset_kwargs(request, obj, inline, prefix),
- 'form_kwargs': {'request': request},
+ "form_kwargs": {"request": request},
}
You can also use it to set ``initial`` for formset forms.
@@ -1914,7 +1957,7 @@ templates used by the :class:`ModelAdmin` views:
``{'fieldname': 'fieldval'}``::
def get_changeform_initial_data(self, request):
- return {'name': 'custom_initial_value'}
+ return {"name": "custom_initial_value"}
.. method:: ModelAdmin.get_deleted_objects(objs, request)
@@ -1982,19 +2025,21 @@ example, the change view is overridden so that the rendered template is
provided some extra mapping data that would not otherwise be available::
class MyModelAdmin(admin.ModelAdmin):
-
# A template for a very customized change view:
- change_form_template = 'admin/myapp/extras/openstreetmap_change_form.html'
+ change_form_template = "admin/myapp/extras/openstreetmap_change_form.html"
def get_osm_info(self):
# ...
pass
- def change_view(self, request, object_id, form_url='', extra_context=None):
+ def change_view(self, request, object_id, form_url="", extra_context=None):
extra_context = extra_context or {}
- extra_context['osm_data'] = self.get_osm_info()
+ extra_context["osm_data"] = self.get_osm_info()
return super().change_view(
- request, object_id, form_url, extra_context=extra_context,
+ request,
+ object_id,
+ form_url,
+ extra_context=extra_context,
)
These views return :class:`~django.template.response.TemplateResponse`
@@ -2100,21 +2145,25 @@ information.
from django.db import models
+
class Author(models.Model):
- name = models.CharField(max_length=100)
+ name = models.CharField(max_length=100)
+
class Book(models.Model):
- author = models.ForeignKey(Author, on_delete=models.CASCADE)
- title = models.CharField(max_length=100)
+ author = models.ForeignKey(Author, on_delete=models.CASCADE)
+ title = models.CharField(max_length=100)
You can edit the books authored by an author on the author page. You add
inlines to a model by specifying them in a ``ModelAdmin.inlines``::
from django.contrib import admin
+
class BookInline(admin.TabularInline):
model = Book
+
class AuthorAdmin(admin.ModelAdmin):
inlines = [
BookInline,
@@ -2347,9 +2396,14 @@ Take this model for instance::
from django.db import models
+
class Friendship(models.Model):
- to_person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name="friends")
- from_person = models.ForeignKey(Person, on_delete=models.CASCADE, related_name="from_friends")
+ to_person = models.ForeignKey(
+ Person, on_delete=models.CASCADE, related_name="friends"
+ )
+ from_person = models.ForeignKey(
+ Person, on_delete=models.CASCADE, related_name="from_friends"
+ )
If you wanted to display an inline on the ``Person`` admin add/change pages
you need to explicitly define the foreign key since it is unable to do so
@@ -2358,10 +2412,12 @@ automatically::
from django.contrib import admin
from myapp.models import Friendship
+
class FriendshipInline(admin.TabularInline):
model = Friendship
fk_name = "to_person"
+
class PersonAdmin(admin.ModelAdmin):
inlines = [
FriendshipInline,
@@ -2382,31 +2438,36 @@ Suppose we have the following models::
from django.db import models
+
class Person(models.Model):
name = models.CharField(max_length=128)
+
class Group(models.Model):
name = models.CharField(max_length=128)
- members = models.ManyToManyField(Person, related_name='groups')
+ members = models.ManyToManyField(Person, related_name="groups")
If you want to display many-to-many relations using an inline, you can do
so by defining an ``InlineModelAdmin`` object for the relationship::
from django.contrib import admin
+
class MembershipInline(admin.TabularInline):
model = Group.members.through
+
class PersonAdmin(admin.ModelAdmin):
inlines = [
MembershipInline,
]
+
class GroupAdmin(admin.ModelAdmin):
inlines = [
MembershipInline,
]
- exclude = ['members']
+ exclude = ["members"]
There are two features worth noting in this example.
@@ -2446,12 +2507,15 @@ we can do this with inline admin models. Suppose we have the following models::
from django.db import models
+
class Person(models.Model):
name = models.CharField(max_length=128)
+
class Group(models.Model):
name = models.CharField(max_length=128)
- members = models.ManyToManyField(Person, through='Membership')
+ members = models.ManyToManyField(Person, through="Membership")
+
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
@@ -2475,6 +2539,7 @@ Now create admin views for the ``Person`` and ``Group`` models::
class PersonAdmin(admin.ModelAdmin):
inlines = [MembershipInline]
+
class GroupAdmin(admin.ModelAdmin):
inlines = [MembershipInline]
@@ -2497,12 +2562,14 @@ you have the following models::
from django.contrib.contenttypes.fields import GenericForeignKey
from django.db import models
+
class Image(models.Model):
image = models.ImageField(upload_to="images")
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
+
class Product(models.Model):
name = models.CharField(max_length=100)
@@ -2521,14 +2588,17 @@ any other inline. In your ``admin.py`` for this example app::
from myapp.models import Image, Product
+
class ImageInline(GenericTabularInline):
model = Image
+
class ProductAdmin(admin.ModelAdmin):
inlines = [
ImageInline,
]
+
admin.site.register(Product, ProductAdmin)
See the :doc:`contenttypes documentation </ref/contrib/contenttypes>` for more
@@ -2920,7 +2990,7 @@ In this example, we register the default ``AdminSite`` instance
from django.urls import path
urlpatterns = [
- path('admin/', admin.site.urls),
+ path("admin/", admin.site.urls),
]
.. _customizing-adminsite:
@@ -2942,10 +3012,12 @@ to reference your :class:`AdminSite` subclass.
from .models import MyModel
+
class MyAdminSite(admin.AdminSite):
- site_header = 'Monty Python administration'
+ site_header = "Monty Python administration"
- admin_site = MyAdminSite(name='myadmin')
+
+ admin_site = MyAdminSite(name="myadmin")
admin_site.register(MyModel)
@@ -2957,7 +3029,7 @@ to reference your :class:`AdminSite` subclass.
from myapp.admin import admin_site
urlpatterns = [
- path('myadmin/', admin_site.urls),
+ path("myadmin/", admin_site.urls),
]
Note that you may not want autodiscovery of ``admin`` modules when using your
@@ -2981,6 +3053,7 @@ returns a site instance.
from django.contrib import admin
+
class MyAdminSite(admin.AdminSite):
...
@@ -2989,15 +3062,16 @@ returns a site instance.
from django.contrib.admin.apps import AdminConfig
+
class MyAdminConfig(AdminConfig):
- default_site = 'myproject.admin.MyAdminSite'
+ default_site = "myproject.admin.MyAdminSite"
.. code-block:: python
:caption: ``myproject/settings.py``
INSTALLED_APPS = [
# ...
- 'myproject.apps.MyAdminConfig', # replaces 'django.contrib.admin'
+ "myproject.apps.MyAdminConfig", # replaces 'django.contrib.admin'
# ...
]
@@ -3020,8 +3094,8 @@ respectively::
from myproject.admin import advanced_site, basic_site
urlpatterns = [
- path('basic-admin/', basic_site.urls),
- path('advanced-admin/', advanced_site.urls),
+ path("basic-admin/", basic_site.urls),
+ path("advanced-admin/", advanced_site.urls),
]
``AdminSite`` instances take a single argument to their constructor, their
@@ -3058,24 +3132,24 @@ your URLconf. Specifically, add these four patterns::
from django.contrib.auth import views as auth_views
path(
- 'admin/password_reset/',
+ "admin/password_reset/",
auth_views.PasswordResetView.as_view(),
- name='admin_password_reset',
+ name="admin_password_reset",
),
path(
- 'admin/password_reset/done/',
+ "admin/password_reset/done/",
auth_views.PasswordResetDoneView.as_view(),
- name='password_reset_done',
+ name="password_reset_done",
),
path(
- 'reset/<uidb64>/<token>/',
+ "reset/<uidb64>/<token>/",
auth_views.PasswordResetConfirmView.as_view(),
- name='password_reset_confirm',
+ name="password_reset_confirm",
),
path(
- 'reset/done/',
+ "reset/done/",
auth_views.PasswordResetCompleteView.as_view(),
- name='password_reset_complete',
+ name="password_reset_complete",
),
(This assumes you've added the admin at ``admin/`` and requires that you put
@@ -3210,7 +3284,7 @@ call:
>>> from django.urls import reverse
>>> c = Choice.objects.get(...)
- >>> change_url = reverse('admin:polls_choice_change', args=(c.id,))
+ >>> change_url = reverse("admin:polls_choice_change", args=(c.id,))
This will find the first registered instance of the admin application
(whatever the instance name), and resolve to the view for changing
@@ -3223,7 +3297,7 @@ if you specifically wanted the admin view from the admin instance named
.. code-block:: pycon
- >>> change_url = reverse('admin:polls_choice_change', args=(c.id,), current_app='custom')
+ >>> change_url = reverse("admin:polls_choice_change", args=(c.id,), current_app="custom")
For more details, see the documentation on :ref:`reversing namespaced URLs
<topics-http-reversing-url-namespaces>`.
@@ -3254,8 +3328,8 @@ The ``display`` decorator
@admin.display(
boolean=True,
- ordering='-publish_date',
- description='Is Published?',
+ ordering="-publish_date",
+ description="Is Published?",
)
def is_published(self, obj):
return obj.publish_date is not None
@@ -3265,9 +3339,11 @@ The ``display`` decorator
def is_published(self, obj):
return obj.publish_date is not None
+
+
is_published.boolean = True
- is_published.admin_order_field = '-publish_date'
- is_published.short_description = 'Is Published?'
+ is_published.admin_order_field = "-publish_date"
+ is_published.short_description = "Is Published?"
Also note that the ``empty_value`` decorator parameter maps to the
``empty_value_display`` attribute assigned directly to the function. It
@@ -3306,6 +3382,7 @@ The ``staff_member_required`` decorator
from django.contrib.admin.views.decorators import staff_member_required
+
@staff_member_required
def my_view(request):
...
diff --git a/docs/ref/contrib/contenttypes.txt b/docs/ref/contrib/contenttypes.txt
index dcea4e2d2f..c2e448329e 100644
--- a/docs/ref/contrib/contenttypes.txt
+++ b/docs/ref/contrib/contenttypes.txt
@@ -126,7 +126,7 @@ For example, we could look up the
.. code-block:: pycon
>>> from django.contrib.contenttypes.models import ContentType
- >>> user_type = ContentType.objects.get(app_label='auth', model='user')
+ >>> user_type = ContentType.objects.get(app_label="auth", model="user")
>>> user_type
<ContentType: user>
@@ -138,7 +138,7 @@ to the ``User`` model class:
>>> user_type.model_class()
<class 'django.contrib.auth.models.User'>
- >>> user_type.get_object_for_this_type(username='Guido')
+ >>> user_type.get_object_for_this_type(username="Guido")
<User: Guido>
Together,
@@ -252,11 +252,12 @@ For example, it could be used for a tagging system like so::
from django.contrib.contenttypes.models import ContentType
from django.db import models
+
class TaggedItem(models.Model):
tag = models.SlugField()
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
- content_object = GenericForeignKey('content_type', 'object_id')
+ content_object = GenericForeignKey("content_type", "object_id")
def __str__(self):
return self.tag
@@ -351,8 +352,8 @@ creating a ``TaggedItem``:
.. code-block:: pycon
>>> from django.contrib.auth.models import User
- >>> guido = User.objects.get(username='Guido')
- >>> t = TaggedItem(content_object=guido, tag='bdfl')
+ >>> guido = User.objects.get(username="Guido")
+ >>> t = TaggedItem(content_object=guido, tag="bdfl")
>>> t.save()
>>> t.content_object
<User: Guido>
@@ -400,6 +401,7 @@ a "reverse" generic relationship to enable an additional API. For example::
from django.contrib.contenttypes.fields import GenericRelation
from django.db import models
+
class Bookmark(models.Model):
url = models.URLField()
tags = GenericRelation(TaggedItem)
@@ -409,11 +411,11 @@ be used to retrieve their associated ``TaggedItems``:
.. code-block:: pycon
- >>> b = Bookmark(url='https://www.djangoproject.com/')
+ >>> b = Bookmark(url="https://www.djangoproject.com/")
>>> b.save()
- >>> t1 = TaggedItem(content_object=b, tag='django')
+ >>> t1 = TaggedItem(content_object=b, tag="django")
>>> t1.save()
- >>> t2 = TaggedItem(content_object=b, tag='python')
+ >>> t2 = TaggedItem(content_object=b, tag="python")
>>> t2.save()
>>> b.tags.all()
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>
@@ -423,9 +425,9 @@ relationships:
.. code-block:: pycon
- >>> t3 = TaggedItem(tag='Web development')
+ >>> t3 = TaggedItem(tag="Web development")
>>> b.tags.add(t3, bulk=False)
- >>> b.tags.create(tag='Web framework')
+ >>> b.tags.create(tag="Web framework")
<TaggedItem: Web framework>
>>> b.tags.all()
<QuerySet [<TaggedItem: django>, <TaggedItem: python>, <TaggedItem: Web development>, <TaggedItem: Web framework>]>
@@ -457,7 +459,7 @@ instance:
Defining :class:`~django.contrib.contenttypes.fields.GenericRelation` with
``related_query_name`` set allows querying from the related object::
- tags = GenericRelation(TaggedItem, related_query_name='bookmark')
+ tags = GenericRelation(TaggedItem, related_query_name="bookmark")
This enables filtering, ordering, and other query operations on ``Bookmark``
from ``TaggedItem``:
@@ -465,7 +467,7 @@ from ``TaggedItem``:
.. code-block:: pycon
>>> # Get all tags belonging to bookmarks containing `django` in the url
- >>> TaggedItem.objects.filter(bookmark__url__contains='django')
+ >>> TaggedItem.objects.filter(bookmark__url__contains="django")
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>
If you don't add the ``related_query_name``, you can do the same types of
@@ -473,7 +475,7 @@ lookups manually:
.. code-block:: pycon
- >>> bookmarks = Bookmark.objects.filter(url__contains='django')
+ >>> bookmarks = Bookmark.objects.filter(url__contains="django")
>>> bookmark_type = ContentType.objects.get_for_model(Bookmark)
>>> TaggedItem.objects.filter(content_type__pk=bookmark_type.id, object_id__in=bookmarks)
<QuerySet [<TaggedItem: django>, <TaggedItem: python>]>
@@ -491,8 +493,8 @@ referred to above used fields named ``content_type_fk`` and
tags = GenericRelation(
TaggedItem,
- content_type_field='content_type_fk',
- object_id_field='object_primary_key',
+ content_type_field="content_type_fk",
+ object_id_field="object_primary_key",
)
Note also, that if you delete an object that has a
@@ -519,7 +521,7 @@ can find out how many tags all the bookmarks have:
.. code-block:: pycon
- >>> Bookmark.objects.aggregate(Count('tags'))
+ >>> Bookmark.objects.aggregate(Count("tags"))
{'tags__count': 3}
.. module:: django.contrib.contenttypes.forms
diff --git a/docs/ref/contrib/flatpages.txt b/docs/ref/contrib/flatpages.txt
index edaf7382ba..d68257bfd1 100644
--- a/docs/ref/contrib/flatpages.txt
+++ b/docs/ref/contrib/flatpages.txt
@@ -42,7 +42,7 @@ Then either:
3. Add an entry in your URLconf. For example::
urlpatterns = [
- path('pages/', include('django.contrib.flatpages.urls')),
+ path("pages/", include("django.contrib.flatpages.urls")),
]
or:
@@ -69,7 +69,7 @@ There are several ways to include the flat pages in your URLconf. You can
dedicate a particular path to flat pages::
urlpatterns = [
- path('pages/', include('django.contrib.flatpages.urls')),
+ path("pages/", include("django.contrib.flatpages.urls")),
]
You can also set it up as a "catchall" pattern. In this case, it is important
@@ -79,7 +79,7 @@ to place the pattern at the end of the other urlpatterns::
# Your other patterns here
urlpatterns += [
- re_path(r'^(?P<url>.*/)$', views.flatpage),
+ re_path(r"^(?P<url>.*/)$", views.flatpage),
]
.. warning::
@@ -95,8 +95,8 @@ tag::
from django.contrib.flatpages import views
urlpatterns += [
- path('about-us/', views.flatpage, {'url': '/about-us/'}, name='about'),
- path('license/', views.flatpage, {'url': '/license/'}, name='license'),
+ path("about-us/", views.flatpage, {"url": "/about-us/"}, name="about"),
+ path("license/", views.flatpage, {"url": "/license/"}, name="license"),
]
Using the middleware
@@ -183,20 +183,25 @@ registering a custom ``ModelAdmin`` for ``FlatPage``::
from django.contrib.flatpages.models import FlatPage
from django.utils.translation import gettext_lazy as _
+
# Define a new FlatPageAdmin
class FlatPageAdmin(FlatPageAdmin):
fieldsets = [
- (None, {'fields': ['url', 'title', 'content', 'sites']}),
- (_('Advanced options'), {
- 'classes': ['collapse'],
- 'fields': [
- 'enable_comments',
- 'registration_required',
- 'template_name',
- ],
- }),
+ (None, {"fields": ["url", "title", "content", "sites"]}),
+ (
+ _("Advanced options"),
+ {
+ "classes": ["collapse"],
+ "fields": [
+ "enable_comments",
+ "registration_required",
+ "template_name",
+ ],
+ },
+ ),
]
+
# Re-register FlatPageAdmin
admin.site.unregister(FlatPage)
admin.site.register(FlatPage, FlatPageAdmin)
@@ -344,9 +349,11 @@ Here's an example of a URLconf using :class:`FlatPageSitemap`::
urlpatterns = [
# ...
-
# the sitemap
- path('sitemap.xml', sitemap,
- {'sitemaps': {'flatpages': FlatPageSitemap}},
- name='django.contrib.sitemaps.views.sitemap'),
+ path(
+ "sitemap.xml",
+ sitemap,
+ {"sitemaps": {"flatpages": FlatPageSitemap}},
+ name="django.contrib.sitemaps.views.sitemap",
+ ),
]
diff --git a/docs/ref/contrib/gis/db-api.txt b/docs/ref/contrib/gis/db-api.txt
index 42dfbdde76..df1d3847e6 100644
--- a/docs/ref/contrib/gis/db-api.txt
+++ b/docs/ref/contrib/gis/db-api.txt
@@ -42,7 +42,7 @@ model):
.. code-block:: pycon
>>> from zipcode.models import Zipcode
- >>> z = Zipcode(code=77096, poly='POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))')
+ >>> z = Zipcode(code=77096, poly="POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))")
>>> z.save()
:class:`~django.contrib.gis.geos.GEOSGeometry` objects may also be used to save geometric models:
@@ -50,7 +50,7 @@ model):
.. code-block:: pycon
>>> from django.contrib.gis.geos import GEOSGeometry
- >>> poly = GEOSGeometry('POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))')
+ >>> poly = GEOSGeometry("POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))")
>>> z = Zipcode(code=77096, poly=poly)
>>> z.save()
@@ -61,11 +61,15 @@ transform procedure:
.. code-block:: pycon
- >>> poly_3084 = GEOSGeometry('POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))', srid=3084) # SRID 3084 is 'NAD83(HARN) / Texas Centric Lambert Conformal'
+ >>> poly_3084 = GEOSGeometry(
+ ... "POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))", srid=3084
+ ... ) # SRID 3084 is 'NAD83(HARN) / Texas Centric Lambert Conformal'
>>> z = Zipcode(code=78212, poly=poly_3084)
>>> z.save()
>>> from django.db import connection
- >>> print(connection.queries[-1]['sql']) # printing the last SQL statement executed (requires DEBUG=True)
+ >>> print(
+ ... connection.queries[-1]["sql"]
+ ... ) # printing the last SQL statement executed (requires DEBUG=True)
INSERT INTO "geoapp_zipcode" ("code", "poly") VALUES (78212, ST_Transform(ST_GeomFromWKB('\\001 ... ', 3084), 4326))
Thus, geometry parameters may be passed in using the ``GEOSGeometry`` object, WKT
@@ -93,7 +97,7 @@ Here is an example of how to create a raster object from a raster file
.. code-block:: pycon
>>> from elevation.models import Elevation
- >>> dem = Elevation(name='Volcano', rast='/path/to/raster/volcano.tif')
+ >>> dem = Elevation(name="Volcano", rast="/path/to/raster/volcano.tif")
>>> dem.save()
:class:`~django.contrib.gis.gdal.GDALRaster` objects may also be used to save
@@ -102,9 +106,17 @@ raster models:
.. code-block:: pycon
>>> from django.contrib.gis.gdal import GDALRaster
- >>> rast = GDALRaster({'width': 10, 'height': 10, 'name': 'Canyon', 'srid': 4326,
- ... 'scale': [0.1, -0.1], 'bands': [{"data": range(100)}]})
- >>> dem = Elevation(name='Canyon', rast=rast)
+ >>> rast = GDALRaster(
+ ... {
+ ... "width": 10,
+ ... "height": 10,
+ ... "name": "Canyon",
+ ... "srid": 4326,
+ ... "scale": [0.1, -0.1],
+ ... "bands": [{"data": range(100)}],
+ ... }
+ ... )
+ >>> dem = Elevation(name="Canyon", rast=rast)
>>> dem.save()
Note that this equivalent to:
@@ -112,9 +124,15 @@ Note that this equivalent to:
.. code-block:: pycon
>>> dem = Elevation.objects.create(
- ... name='Canyon',
- ... rast={'width': 10, 'height': 10, 'name': 'Canyon', 'srid': 4326,
- ... 'scale': [0.1, -0.1], 'bands': [{"data": range(100)}]},
+ ... name="Canyon",
+ ... rast={
+ ... "width": 10,
+ ... "height": 10,
+ ... "name": "Canyon",
+ ... "srid": 4326,
+ ... "scale": [0.1, -0.1],
+ ... "bands": [{"data": range(100)}],
+ ... },
... )
.. _spatial-lookups-intro:
@@ -270,6 +288,7 @@ For example, let's say we have a ``SouthTexasCity`` model (from the
from django.contrib.gis.db import models
+
class SouthTexasCity(models.Model):
name = models.CharField(max_length=30)
# A projected coordinate system (only valid for South Texas!)
@@ -281,10 +300,10 @@ Then distance queries may be performed as follows:
.. code-block:: pycon
>>> from django.contrib.gis.geos import GEOSGeometry
- >>> from django.contrib.gis.measure import D # ``D`` is a shortcut for ``Distance``
+ >>> from django.contrib.gis.measure import D # ``D`` is a shortcut for ``Distance``
>>> from geoapp.models import SouthTexasCity
# Distances will be calculated from this point, which does not have to be projected.
- >>> pnt = GEOSGeometry('POINT(-96.876369 29.905320)', srid=4326)
+ >>> pnt = GEOSGeometry("POINT(-96.876369 29.905320)", srid=4326)
# If numeric parameter, units of field (meters in this case) are assumed.
>>> qs = SouthTexasCity.objects.filter(point__distance_lte=(pnt, 7000))
# Find all Cities within 7 km, > 20 miles away, and > 100 chains away (an obscure unit)
diff --git a/docs/ref/contrib/gis/feeds.txt b/docs/ref/contrib/gis/feeds.txt
index 644391f9c6..d22c728b5f 100644
--- a/docs/ref/contrib/gis/feeds.txt
+++ b/docs/ref/contrib/gis/feeds.txt
@@ -33,8 +33,8 @@ API Reference
from django.contrib.gis.feeds import Feed
- class MyFeed(Feed):
+ class MyFeed(Feed):
# First, as a class attribute.
geometry = ...
item_geometry = ...
@@ -60,10 +60,9 @@ API Reference
to represent a point or a box. For example::
class ZipcodeFeed(Feed):
-
def geometry(self, obj):
# Can also return: `obj.poly`, and `obj.poly.centroid`.
- return obj.poly.extent # tuple like: (X0, Y0, X1, Y1).
+ return obj.poly.extent # tuple like: (X0, Y0, X1, Y1).
.. method:: item_geometry(item)
@@ -72,7 +71,6 @@ API Reference
bounding box. For example::
class ZipcodeFeed(Feed):
-
def item_geometry(self, obj):
# Returns the polygon.
return obj.poly
diff --git a/docs/ref/contrib/gis/forms-api.txt b/docs/ref/contrib/gis/forms-api.txt
index bb0893df76..11e1bc77f4 100644
--- a/docs/ref/contrib/gis/forms-api.txt
+++ b/docs/ref/contrib/gis/forms-api.txt
@@ -134,9 +134,9 @@ widget. For example::
from django.contrib.gis import forms
+
class MyGeoForm(forms.Form):
- point = forms.PointField(widget=
- forms.OSMWidget(attrs={'display_raw': True}))
+ point = forms.PointField(widget=forms.OSMWidget(attrs={"display_raw": True}))
Widget classes
--------------
diff --git a/docs/ref/contrib/gis/functions.txt b/docs/ref/contrib/gis/functions.txt
index 755050f076..31af52bb4e 100644
--- a/docs/ref/contrib/gis/functions.txt
+++ b/docs/ref/contrib/gis/functions.txt
@@ -13,7 +13,7 @@ Example:
.. code-block:: pycon
>>> from django.contrib.gis.db.models.functions import Length
- >>> Track.objects.annotate(length=Length('line')).filter(length__gt=100)
+ >>> Track.objects.annotate(length=Length("line")).filter(length__gt=100)
Not all backends support all functions, so refer to the documentation of each
function to see if your database backend supports the function you want to use.
@@ -67,7 +67,7 @@ Example:
.. code-block:: pycon
- >>> City.objects.annotate(json=AsGeoJSON('point')).get(name='Chicago').json
+ >>> City.objects.annotate(json=AsGeoJSON("point")).get(name="Chicago").json
{"type":"Point","coordinates":[-87.65018,41.85039]}
===================== =====================================================
@@ -102,7 +102,7 @@ Example:
.. code-block:: pycon
- >>> qs = Zipcode.objects.annotate(gml=AsGML('poly'))
+ >>> qs = Zipcode.objects.annotate(gml=AsGML("poly"))
>>> print(qs[0].gml)
<gml:Polygon srsName="EPSG:4326"><gml:OuterBoundaryIs>-147.78711,70.245363 ...
-147.78711,70.245363</gml:OuterBoundaryIs></gml:Polygon>
@@ -133,7 +133,7 @@ Example:
.. code-block:: pycon
- >>> qs = Zipcode.objects.annotate(kml=AsKML('poly'))
+ >>> qs = Zipcode.objects.annotate(kml=AsKML("poly"))
>>> print(qs[0].kml)
<Polygon><outerBoundaryIs><LinearRing><coordinates>-103.04135,36.217596,0 ...
-103.04135,36.217596,0</coordinates></LinearRing></outerBoundaryIs></Polygon>
@@ -188,7 +188,7 @@ Example:
.. code-block:: pycon
- >>> bytes(City.objects.annotate(wkb=AsWKB('point')).get(name='Chelyabinsk').wkb)
+ >>> bytes(City.objects.annotate(wkb=AsWKB("point")).get(name="Chelyabinsk").wkb)
b'\x01\x01\x00\x00\x00]3\xf9f\x9b\x91K@\x00X\x1d9\xd2\xb9N@'
``AsWKT``
@@ -207,7 +207,7 @@ Example:
.. code-block:: pycon
- >>> City.objects.annotate(wkt=AsWKT('point')).get(name='Chelyabinsk').wkt
+ >>> City.objects.annotate(wkt=AsWKT("point")).get(name="Chelyabinsk").wkt
'POINT (55.137555 61.451728)'
``Azimuth``
@@ -306,9 +306,10 @@ queryset is calculated:
.. code-block:: pycon
>>> from django.contrib.gis.db.models.functions import Distance
- >>> pnt = AustraliaCity.objects.get(name='Hobart').point
- >>> for city in AustraliaCity.objects.annotate(distance=Distance('point', pnt)):
+ >>> pnt = AustraliaCity.objects.get(name="Hobart").point
+ >>> for city in AustraliaCity.objects.annotate(distance=Distance("point", pnt)):
... print(city.name, city.distance)
+ ...
Wollongong 990071.220408 m
Shellharbour 972804.613941 m
Thirroul 1002334.36351 m
diff --git a/docs/ref/contrib/gis/gdal.txt b/docs/ref/contrib/gis/gdal.txt
index 6dfa2b4e48..eb48b774e1 100644
--- a/docs/ref/contrib/gis/gdal.txt
+++ b/docs/ref/contrib/gis/gdal.txt
@@ -82,10 +82,10 @@ each feature in that layer.
.. code-block:: pycon
>>> from django.contrib.gis.gdal import DataSource
- >>> ds = DataSource('/path/to/your/cities.shp')
+ >>> ds = DataSource("/path/to/your/cities.shp")
>>> ds.name
'/path/to/your/cities.shp'
- >>> ds.layer_count # This file only contains one layer
+ >>> ds.layer_count # This file only contains one layer
1
.. attribute:: layer_count
@@ -248,13 +248,13 @@ __ https://gdal.org/drivers/vector/
None
>>> print(len(layer))
3
- >>> [feat.get('Name') for feat in layer]
+ >>> [feat.get("Name") for feat in layer]
['Pueblo', 'Lawrence', 'Houston']
- >>> ks_extent = (-102.051, 36.99, -94.59, 40.00) # Extent for state of Kansas
+ >>> ks_extent = (-102.051, 36.99, -94.59, 40.00) # Extent for state of Kansas
>>> layer.spatial_filter = ks_extent
>>> len(layer)
1
- >>> [feat.get('Name') for feat in layer]
+ >>> [feat.get("Name") for feat in layer]
['Lawrence']
>>> layer.spatial_filter = None
>>> len(layer)
@@ -267,7 +267,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> layer.get_fields('Name')
+ >>> layer.get_fields("Name")
['Pueblo', 'Lawrence', 'Houston']
.. method:: get_geoms(geos=False)
@@ -321,7 +321,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city.get('Population')
+ >>> city.get("Population")
102121
.. attribute:: geom_type
@@ -371,7 +371,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city.index('Population')
+ >>> city.index("Population")
1
``Field``
@@ -385,7 +385,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city['Name'].name
+ >>> city["Name"].name
'Name'
.. attribute:: type
@@ -395,7 +395,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city['Density'].type
+ >>> city["Density"].type
2
.. attribute:: type_name
@@ -404,7 +404,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city['Name'].type_name
+ >>> city["Name"].type_name
'String'
.. attribute:: value
@@ -415,7 +415,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city['Population'].value
+ >>> city["Population"].value
102121
.. attribute:: width
@@ -424,7 +424,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city['Name'].width
+ >>> city["Name"].width
80
.. attribute:: precision
@@ -434,7 +434,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city['Density'].precision
+ >>> city["Density"].precision
15
.. method:: as_double()
@@ -443,7 +443,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city['Density'].as_double()
+ >>> city["Density"].as_double()
874.7
.. method:: as_int()
@@ -452,7 +452,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city['Population'].as_int()
+ >>> city["Population"].as_int()
102121
.. method:: as_string()
@@ -461,7 +461,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city['Name'].as_string()
+ >>> city["Name"].as_string()
'Pueblo'
.. method:: as_datetime()
@@ -470,7 +470,7 @@ __ https://gdal.org/drivers/vector/
.. code-block:: pycon
- >>> city['Created'].as_datetime()
+ >>> city["Created"].as_datetime()
(c_long(1999), c_long(5), c_long(23), c_long(0), c_long(0), c_long(0), c_long(0))
``Driver``
@@ -501,7 +501,7 @@ coordinate transformation:
.. code-block:: pycon
>>> from django.contrib.gis.gdal import OGRGeometry
- >>> polygon = OGRGeometry('POLYGON((0 0, 5 0, 5 5, 0 5))')
+ >>> polygon = OGRGeometry("POLYGON((0 0, 5 0, 5 5, 0 5))")
.. class:: OGRGeometry(geom_input, srs=None)
@@ -650,7 +650,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('POINT(1 2)').gml
+ >>> OGRGeometry("POINT(1 2)").gml
'<gml:Point><gml:coordinates>1,2</gml:coordinates></gml:Point>'
.. attribute:: hex
@@ -659,7 +659,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('POINT(1 2)').hex
+ >>> OGRGeometry("POINT(1 2)").hex
'0101000000000000000000F03F0000000000000040'
.. attribute:: json
@@ -668,7 +668,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('POINT(1 2)').json
+ >>> OGRGeometry("POINT(1 2)").json
'{ "type": "Point", "coordinates": [ 1.000000, 2.000000 ] }'
.. attribute:: kml
@@ -682,7 +682,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('POINT(1 2)').wkb_size
+ >>> OGRGeometry("POINT(1 2)").wkb_size
21
.. attribute:: wkb
@@ -708,7 +708,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> triangle = OGRGeometry('LINEARRING (0 0,0 1,1 0)')
+ >>> triangle = OGRGeometry("LINEARRING (0 0,0 1,1 0)")
>>> triangle.close_rings()
>>> triangle.wkt
'LINEARRING (0 0,0 1,1 0,0 0)'
@@ -800,9 +800,9 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('POINT (1 2)').tuple
+ >>> OGRGeometry("POINT (1 2)").tuple
(1.0, 2.0)
- >>> OGRGeometry('LINESTRING (1 2,3 4)').tuple
+ >>> OGRGeometry("LINESTRING (1 2,3 4)").tuple
((1.0, 2.0), (3.0, 4.0))
.. attribute:: coords
@@ -817,7 +817,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('POINT (1 2)').x
+ >>> OGRGeometry("POINT (1 2)").x
1.0
.. attribute:: y
@@ -826,7 +826,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('POINT (1 2)').y
+ >>> OGRGeometry("POINT (1 2)").y
2.0
.. attribute:: z
@@ -836,7 +836,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('POINT (1 2 3)').z
+ >>> OGRGeometry("POINT (1 2 3)").z
3.0
.. class:: LineString
@@ -847,7 +847,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('LINESTRING (1 2,3 4)').x
+ >>> OGRGeometry("LINESTRING (1 2,3 4)").x
[1.0, 3.0]
.. attribute:: y
@@ -856,7 +856,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('LINESTRING (1 2,3 4)').y
+ >>> OGRGeometry("LINESTRING (1 2,3 4)").y
[2.0, 4.0]
.. attribute:: z
@@ -866,7 +866,7 @@ coordinate transformation:
.. code-block:: pycon
- >>> OGRGeometry('LINESTRING (1 2 3,4 5 6)').z
+ >>> OGRGeometry("LINESTRING (1 2 3,4 5 6)").z
[3.0, 6.0]
@@ -903,10 +903,10 @@ coordinate transformation:
.. code-block:: pycon
>>> from django.contrib.gis.gdal import OGRGeomType
- >>> gt1 = OGRGeomType(3) # Using an integer for the type
- >>> gt2 = OGRGeomType('Polygon') # Using a string
- >>> gt3 = OGRGeomType('POLYGON') # It's case-insensitive
- >>> print(gt1 == 3, gt1 == 'Polygon') # Equivalence works w/non-OGRGeomType objects
+ >>> gt1 = OGRGeomType(3) # Using an integer for the type
+ >>> gt2 = OGRGeomType("Polygon") # Using a string
+ >>> gt3 = OGRGeomType("POLYGON") # It's case-insensitive
+ >>> print(gt1 == 3, gt1 == "Polygon") # Equivalence works w/non-OGRGeomType objects
True True
.. attribute:: name
@@ -1001,12 +1001,13 @@ Coordinate System Objects
.. code-block:: pycon
- >>> wgs84 = SpatialReference('WGS84') # shorthand string
- >>> wgs84 = SpatialReference(4326) # EPSG code
- >>> wgs84 = SpatialReference('EPSG:4326') # EPSG string
- >>> proj = '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs '
- >>> wgs84 = SpatialReference(proj) # PROJ string
- >>> wgs84 = SpatialReference("""GEOGCS["WGS 84",
+ >>> wgs84 = SpatialReference("WGS84") # shorthand string
+ >>> wgs84 = SpatialReference(4326) # EPSG code
+ >>> wgs84 = SpatialReference("EPSG:4326") # EPSG string
+ >>> proj = "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs "
+ >>> wgs84 = SpatialReference(proj) # PROJ string
+ >>> wgs84 = SpatialReference(
+ ... """GEOGCS["WGS 84",
... DATUM["WGS_1984",
... SPHEROID["WGS 84",6378137,298.257223563,
... AUTHORITY["EPSG","7030"]],
@@ -1015,7 +1016,8 @@ Coordinate System Objects
... AUTHORITY["EPSG","8901"]],
... UNIT["degree",0.01745329251994328,
... AUTHORITY["EPSG","9122"]],
- ... AUTHORITY["EPSG","4326"]]""") # OGC WKT
+ ... AUTHORITY["EPSG","4326"]]"""
+ ... ) # OGC WKT
.. method:: __getitem__(target)
@@ -1026,20 +1028,20 @@ Coordinate System Objects
.. code-block:: pycon
>>> wkt = 'GEOGCS["WGS 84", DATUM["WGS_1984, ... AUTHORITY["EPSG","4326"]]'
- >>> srs = SpatialReference(wkt) # could also use 'WGS84', or 4326
- >>> print(srs['GEOGCS'])
+ >>> srs = SpatialReference(wkt) # could also use 'WGS84', or 4326
+ >>> print(srs["GEOGCS"])
WGS 84
- >>> print(srs['DATUM'])
+ >>> print(srs["DATUM"])
WGS_1984
- >>> print(srs['AUTHORITY'])
+ >>> print(srs["AUTHORITY"])
EPSG
- >>> print(srs['AUTHORITY', 1]) # The authority value
+ >>> print(srs["AUTHORITY", 1]) # The authority value
4326
- >>> print(srs['TOWGS84', 4]) # the fourth value in this wkt
+ >>> print(srs["TOWGS84", 4]) # the fourth value in this wkt
0
- >>> print(srs['UNIT|AUTHORITY']) # For the units authority, have to use the pipe symbol.
+ >>> print(srs["UNIT|AUTHORITY"]) # For the units authority, have to use the pipe symbol.
EPSG
- >>> print(srs['UNIT|AUTHORITY', 1]) # The authority value for the units
+ >>> print(srs["UNIT|AUTHORITY", 1]) # The authority value for the units
9122
.. method:: attr_value(target, index=0)
@@ -1188,10 +1190,11 @@ coordinate transformation repeatedly on different geometries:
.. code-block:: pycon
- >>> ct = CoordTransform(SpatialReference('WGS84'), SpatialReference('NAD83'))
+ >>> ct = CoordTransform(SpatialReference("WGS84"), SpatialReference("NAD83"))
>>> for feat in layer:
- ... geom = feat.geom # getting clone of feature geometry
- ... geom.transform(ct) # transforming
+ ... geom = feat.geom # getting clone of feature geometry
+ ... geom.transform(ct) # transforming
+ ...
.. _raster-data-source-objects:
@@ -1366,8 +1369,8 @@ blue.
tuple of six coefficients which map pixel/line coordinates into
georeferenced space using the following relationship::
- Xgeo = GT(0) + Xpixel*GT(1) + Yline*GT(2)
- Ygeo = GT(3) + Xpixel*GT(4) + Yline*GT(5)
+ Xgeo = GT(0) + Xpixel * GT(1) + Yline * GT(2)
+ Ygeo = GT(3) + Xpixel * GT(4) + Yline * GT(5)
The same values can be retrieved by accessing the :attr:`origin`
(indices 0 and 3), :attr:`scale` (indices 1 and 5) and :attr:`skew`
@@ -1843,21 +1846,23 @@ Key Default Usage
.. code-block:: pycon
- >>> GDALRaster({
- ... 'driver': 'GTiff',
- ... 'name': '/path/to/new/file.tif',
- ... 'srid': 4326,
- ... 'width': 255,
- ... 'height': 255,
- ... 'nr_of_bands': 1,
- ... 'papsz_options': {
- ... 'compress': 'packbits',
- ... 'pixeltype': 'signedbyte',
- ... 'tiled': 'yes',
- ... 'blockxsize': 23,
- ... 'blockysize': 23,
- ... }
- ... })
+ >>> GDALRaster(
+ ... {
+ ... "driver": "GTiff",
+ ... "name": "/path/to/new/file.tif",
+ ... "srid": 4326,
+ ... "width": 255,
+ ... "height": 255,
+ ... "nr_of_bands": 1,
+ ... "papsz_options": {
+ ... "compress": "packbits",
+ ... "pixeltype": "signedbyte",
+ ... "tiled": "yes",
+ ... "blockxsize": 23,
+ ... "blockysize": 23,
+ ... },
+ ... }
+ ... )
__ https://gdal.org/drivers/raster/gtiff.html
@@ -1913,7 +1918,7 @@ For instance:
# Read a raster as a file object from a remote source.
>>> from urllib.request import urlopen
- >>> dat = urlopen('http://example.com/raster.tif').read()
+ >>> dat = urlopen("http://example.com/raster.tif").read()
# Instantiate a raster from the bytes object.
>>> rst = GDALRaster(dat)
# The name starts with /vsimem/, indicating that the raster lives in the
@@ -1934,15 +1939,19 @@ Here's how to create a raster and return it as a file in an
.. code-block:: pycon
>>> from django.http import HttpResponse
- >>> rst = GDALRaster({
- ... 'name': '/vsimem/temporarymemfile',
- ... 'driver': 'tif',
- ... 'width': 6, 'height': 6, 'srid': 3086,
- ... 'origin': [500000, 400000],
- ... 'scale': [100, -100],
- ... 'bands': [{'data': range(36), 'nodata_value': 99}]
- ... })
- >>> HttpResponse(rast.vsi_buffer, 'image/tiff')
+ >>> rst = GDALRaster(
+ ... {
+ ... "name": "/vsimem/temporarymemfile",
+ ... "driver": "tif",
+ ... "width": 6,
+ ... "height": 6,
+ ... "srid": 3086,
+ ... "origin": [500000, 400000],
+ ... "scale": [100, -100],
+ ... "bands": [{"data": range(36), "nodata_value": 99}],
+ ... }
+ ... )
+ >>> HttpResponse(rast.vsi_buffer, "image/tiff")
Using other Virtual Filesystems
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1967,9 +1976,9 @@ directly access compressed files using the ``/vsizip/``, ``/vsigzip/``, or
.. code-block:: pycon
>>> from django.contrib.gis.gdal import GDALRaster
- >>> rst = GDALRaster('/vsizip/path/to/your/file.zip/path/to/raster.tif')
- >>> rst = GDALRaster('/vsigzip/path/to/your/file.gz')
- >>> rst = GDALRaster('/vsitar/path/to/your/file.tar/path/to/raster.tif')
+ >>> rst = GDALRaster("/vsizip/path/to/your/file.zip/path/to/raster.tif")
+ >>> rst = GDALRaster("/vsigzip/path/to/your/file.gz")
+ >>> rst = GDALRaster("/vsitar/path/to/your/file.tar/path/to/raster.tif")
Network rasters
^^^^^^^^^^^^^^^
@@ -1983,7 +1992,7 @@ To access a public raster file with no authentication, you can use
.. code-block:: pycon
>>> from django.contrib.gis.gdal import GDALRaster
- >>> rst = GDALRaster('/vsicurl/https://example.com/raster.tif')
+ >>> rst = GDALRaster("/vsicurl/https://example.com/raster.tif")
>>> rst.name
'/vsicurl/https://example.com/raster.tif'
diff --git a/docs/ref/contrib/gis/geoip2.txt b/docs/ref/contrib/gis/geoip2.txt
index e3d27555ec..414a4efe9c 100644
--- a/docs/ref/contrib/gis/geoip2.txt
+++ b/docs/ref/contrib/gis/geoip2.txt
@@ -37,9 +37,9 @@ Here is an example of its usage:
>>> from django.contrib.gis.geoip2 import GeoIP2
>>> g = GeoIP2()
- >>> g.country('google.com')
+ >>> g.country("google.com")
{'country_code': 'US', 'country_name': 'United States'}
- >>> g.city('72.14.207.99')
+ >>> g.city("72.14.207.99")
{'city': 'Mountain View',
'continent_code': 'NA',
'continent_name': 'North America',
@@ -52,11 +52,11 @@ Here is an example of its usage:
'postal_code': '94043',
'region': 'CA',
'time_zone': 'America/Los_Angeles'}
- >>> g.lat_lon('salon.com')
+ >>> g.lat_lon("salon.com")
(39.0437, -77.4875)
- >>> g.lon_lat('uh.edu')
+ >>> g.lon_lat("uh.edu")
(-95.4342, 29.834)
- >>> g.geos('24.124.1.80').wkt
+ >>> g.geos("24.124.1.80").wkt
'POINT (-97 38)'
API Reference
diff --git a/docs/ref/contrib/gis/geoquerysets.txt b/docs/ref/contrib/gis/geoquerysets.txt
index b13ae1c8af..4d4c0c7de9 100644
--- a/docs/ref/contrib/gis/geoquerysets.txt
+++ b/docs/ref/contrib/gis/geoquerysets.txt
@@ -428,7 +428,7 @@ Geometry example::
# A tuple lookup parameter is used to specify the geometry and
# the intersection pattern (the pattern here is for 'contains').
- Zipcode.objects.filter(poly__relate=(geom, 'T*T***FF*'))
+ Zipcode.objects.filter(poly__relate=(geom, "T*T***FF*"))
PostGIS and MariaDB SQL equivalent:
@@ -444,8 +444,8 @@ SpatiaLite SQL equivalent:
Raster example::
- Zipcode.objects.filter(poly__relate=(rast, 1, 'T*T***FF*'))
- Zipcode.objects.filter(rast__2__relate=(rast, 1, 'T*T***FF*'))
+ Zipcode.objects.filter(poly__relate=(rast, 1, "T*T***FF*"))
+ Zipcode.objects.filter(rast__2__relate=(rast, 1, "T*T***FF*"))
PostGIS SQL equivalent:
@@ -466,7 +466,7 @@ strings are case-insensitive.
Example::
- Zipcode.objects.filter(poly__relate=(geom, 'anyinteract'))
+ Zipcode.objects.filter(poly__relate=(geom, "anyinteract"))
Oracle SQL equivalent:
@@ -863,7 +863,7 @@ Example:
.. code-block:: pycon
>>> from django.contrib.gis.db.models import Extent, Union
- >>> WorldBorder.objects.aggregate(Extent('mpoly'), Union('mpoly'))
+ >>> WorldBorder.objects.aggregate(Extent("mpoly"), Union("mpoly"))
``Collect``
~~~~~~~~~~~
@@ -894,8 +894,8 @@ Example:
.. code-block:: pycon
- >>> qs = City.objects.filter(name__in=('Houston', 'Dallas')).aggregate(Extent('poly'))
- >>> print(qs['poly__extent'])
+ >>> qs = City.objects.filter(name__in=("Houston", "Dallas")).aggregate(Extent("poly"))
+ >>> print(qs["poly__extent"])
(-96.8016128540039, 29.7633724212646, -95.3631439208984, 32.782058715820)
``Extent3D``
@@ -913,8 +913,8 @@ Example:
.. code-block:: pycon
- >>> qs = City.objects.filter(name__in=('Houston', 'Dallas')).aggregate(Extent3D('poly'))
- >>> print(qs['poly__extent3d'])
+ >>> qs = City.objects.filter(name__in=("Houston", "Dallas")).aggregate(Extent3D("poly"))
+ >>> print(qs["poly__extent3d"])
(-96.8016128540039, 29.7633724212646, 0, -95.3631439208984, 32.782058715820, 0)
``MakeLine``
@@ -932,8 +932,8 @@ Example:
.. code-block:: pycon
- >>> qs = City.objects.filter(name__in=('Houston', 'Dallas')).aggregate(MakeLine('poly'))
- >>> print(qs['poly__makeline'])
+ >>> qs = City.objects.filter(name__in=("Houston", "Dallas")).aggregate(MakeLine("poly"))
+ >>> print(qs["poly__makeline"])
LINESTRING (-95.3631510000000020 29.7633739999999989, -96.8016109999999941 32.7820570000000018)
``Union``
@@ -959,7 +959,9 @@ Example:
.. code-block:: pycon
>>> u = Zipcode.objects.aggregate(Union(poly)) # This may take a long time.
- >>> u = Zipcode.objects.filter(poly__within=bbox).aggregate(Union(poly)) # A more sensible approach.
+ >>> u = Zipcode.objects.filter(poly__within=bbox).aggregate(
+ ... Union(poly)
+ ... ) # A more sensible approach.
.. rubric:: Footnotes
.. [#fnde9im] *See* `OpenGIS Simple Feature Specification For SQL <https://portal.ogc.org/files/?artifact_id=829>`_, at Ch. 2.1.13.2, p. 2-13 (The Dimensionally Extended Nine-Intersection Model).
diff --git a/docs/ref/contrib/gis/geos.txt b/docs/ref/contrib/gis/geos.txt
index 56089a3ffe..564d49bbb6 100644
--- a/docs/ref/contrib/gis/geos.txt
+++ b/docs/ref/contrib/gis/geos.txt
@@ -55,10 +55,16 @@ are examples of creating the same geometry from WKT, HEX, WKB, and GeoJSON:
.. code-block:: pycon
>>> from django.contrib.gis.geos import GEOSGeometry
- >>> pnt = GEOSGeometry('POINT(5 23)') # WKT
- >>> pnt = GEOSGeometry('010100000000000000000014400000000000003740') # HEX
- >>> pnt = GEOSGeometry(memoryview(b'\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x007@')) # WKB
- >>> pnt = GEOSGeometry('{ "type": "Point", "coordinates": [ 5.000000, 23.000000 ] }') # GeoJSON
+ >>> pnt = GEOSGeometry("POINT(5 23)") # WKT
+ >>> pnt = GEOSGeometry("010100000000000000000014400000000000003740") # HEX
+ >>> pnt = GEOSGeometry(
+ ... memoryview(
+ ... b"\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14@\x00\x00\x00\x00\x00\x007@"
+ ... )
+ ... ) # WKB
+ >>> pnt = GEOSGeometry(
+ ... '{ "type": "Point", "coordinates": [ 5.000000, 23.000000 ] }'
+ ... ) # GeoJSON
Another option is to use the constructor for the specific geometry type
that you wish to create. For example, a :class:`Point` object may be
@@ -74,7 +80,7 @@ All these constructors take the keyword argument ``srid``. For example:
.. code-block:: pycon
>>> from django.contrib.gis.geos import GEOSGeometry, LineString, Point
- >>> print(GEOSGeometry('POINT (0 0)', srid=4326))
+ >>> print(GEOSGeometry("POINT (0 0)", srid=4326))
SRID=4326;POINT (0 0)
>>> print(LineString((0, 0), (1, 1), srid=4326))
SRID=4326;LINESTRING (0 0, 1 1)
@@ -87,8 +93,8 @@ Finally, there is the :func:`fromfile` factory method which returns a
.. code-block:: pycon
>>> from django.contrib.gis.geos import fromfile
- >>> pnt = fromfile('/path/to/pnt.wkt')
- >>> pnt = fromfile(open('/path/to/pnt.wkt'))
+ >>> pnt = fromfile("/path/to/pnt.wkt")
+ >>> pnt = fromfile(open("/path/to/pnt.wkt"))
.. _geos-exceptions-in-logfile:
@@ -141,10 +147,10 @@ Whereas indexing on a :class:`Polygon` will return the ring
.. code-block:: pycon
>>> from django.contrib.gis.geos import Polygon
- >>> poly = Polygon( ((0.0, 0.0), (0.0, 50.0), (50.0, 50.0), (50.0, 0.0), (0.0, 0.0)) )
+ >>> poly = Polygon(((0.0, 0.0), (0.0, 50.0), (50.0, 50.0), (50.0, 0.0), (0.0, 0.0)))
>>> poly[0]
<LinearRing object at 0x1044395b0>
- >>> poly[0][-2] # second-to-last coordinate of external ring
+ >>> poly[0][-2] # second-to-last coordinate of external ring
(50.0, 0.0)
In addition, coordinates/components of the geometry may added or modified,
@@ -218,11 +224,11 @@ The ``srid`` parameter, if given, is set as the SRID of the created geometry if
.. code-block:: pycon
>>> from django.contrib.gis.geos import GEOSGeometry
- >>> GEOSGeometry('POINT EMPTY', srid=4326).ewkt
+ >>> GEOSGeometry("POINT EMPTY", srid=4326).ewkt
'SRID=4326;POINT EMPTY'
- >>> GEOSGeometry('SRID=4326;POINT EMPTY', srid=4326).ewkt
+ >>> GEOSGeometry("SRID=4326;POINT EMPTY", srid=4326).ewkt
'SRID=4326;POINT EMPTY'
- >>> GEOSGeometry('SRID=1;POINT EMPTY', srid=4326)
+ >>> GEOSGeometry("SRID=1;POINT EMPTY", srid=4326)
Traceback (most recent call last):
...
ValueError: Input geometry already has SRID: 1.
@@ -274,7 +280,7 @@ Properties
.. code-block:: pycon
- >>> pnt = GEOSGeometry('POINT(5 23)')
+ >>> pnt = GEOSGeometry("POINT(5 23)")
>>> pnt.geom_type
'Point'
@@ -749,8 +755,8 @@ Other Properties & Methods
.. code-block:: pycon
- >>> ls = LineString( ((0, 0), (1, 1)) )
- >>> ls = LineString( [Point(0, 0), Point(1, 1)] )
+ >>> ls = LineString(((0, 0), (1, 1)))
+ >>> ls = LineString([Point(0, 0), Point(1, 1)])
Empty ``LineString`` objects may be instantiated by passing no arguments
or an empty sequence. The following are equivalent:
@@ -823,6 +829,7 @@ Other Properties & Methods
>>> if poly_1.area > poly_2.area:
... pass
+ ...
.. _geos-geometry-collections:
@@ -840,7 +847,7 @@ Geometry Collections
.. code-block:: pycon
>>> mp = MultiPoint(Point(0, 0), Point(1, 1))
- >>> mp = MultiPoint( (Point(0, 0), Point(1, 1)) )
+ >>> mp = MultiPoint((Point(0, 0), Point(1, 1)))
``MultiLineString``
-------------------
@@ -877,8 +884,8 @@ Geometry Collections
.. code-block:: pycon
- >>> p1 = Polygon( ((0, 0), (0, 1), (1, 1), (0, 0)) )
- >>> p2 = Polygon( ((1, 1), (1, 2), (2, 2), (1, 1)) )
+ >>> p1 = Polygon(((0, 0), (0, 1), (1, 1), (0, 0)))
+ >>> p2 = Polygon(((1, 1), (1, 2), (2, 2), (1, 1)))
>>> mp = MultiPolygon(p1, p2)
>>> mp = MultiPolygon([p1, p2])
@@ -893,7 +900,7 @@ Geometry Collections
.. code-block:: pycon
- >>> poly = Polygon( ((0, 0), (0, 1), (1, 1), (0, 0)) )
+ >>> poly = Polygon(((0, 0), (0, 1), (1, 1), (0, 0)))
>>> gc = GeometryCollection(Point(0, 0), MultiPoint(Point(0, 0), Point(1, 1)), poly)
>>> gc = GeometryCollection((Point(0, 0), MultiPoint(Point(0, 0), Point(1, 1)), poly))
@@ -960,7 +967,7 @@ Geometry Factories
.. code-block:: pycon
>>> from django.contrib.gis.geos import fromfile
- >>> g = fromfile('/home/bob/geom.wkt')
+ >>> g = fromfile("/home/bob/geom.wkt")
.. function:: fromstr(string, srid=None)
@@ -978,7 +985,7 @@ Geometry Factories
.. code-block:: pycon
>>> from django.contrib.gis.geos import fromstr
- >>> pnt = fromstr('POINT(-90.5 29.5)', srid=4326)
+ >>> pnt = fromstr("POINT(-90.5 29.5)", srid=4326)
I/O Objects
===========
@@ -997,7 +1004,7 @@ and/or WKT input given to their ``read(geom)`` method.
>>> from django.contrib.gis.geos import WKBReader
>>> wkb_r = WKBReader()
- >>> wkb_r.read('0101000000000000000000F03F000000000000F03F')
+ >>> wkb_r.read("0101000000000000000000F03F000000000000F03F")
<Point object at 0x103a88910>
.. class:: WKTReader
@@ -1008,7 +1015,7 @@ and/or WKT input given to their ``read(geom)`` method.
>>> from django.contrib.gis.geos import WKTReader
>>> wkt_r = WKTReader()
- >>> wkt_r.read('POINT(1 1)')
+ >>> wkt_r.read("POINT(1 1)")
<Point object at 0x103a88b50>
Writer Objects
@@ -1099,9 +1106,9 @@ include the SRID value (in other words, EWKB).
>>> wkb_w.outdim
2
>>> pnt = Point(1, 1, 1)
- >>> wkb_w.write_hex(pnt) # By default, no Z value included:
+ >>> wkb_w.write_hex(pnt) # By default, no Z value included:
'0101000000000000000000F03F000000000000F03F'
- >>> wkb_w.outdim = 3 # Tell writer to include Z values
+ >>> wkb_w.outdim = 3 # Tell writer to include Z values
>>> wkb_w.write_hex(pnt)
'0101000080000000000000F03F000000000000F03F000000000000F03F'
@@ -1115,9 +1122,9 @@ include the SRID value (in other words, EWKB).
>>> from django.contrib.gis.geos import Point, WKBWriter
>>> wkb_w = WKBWriter()
>>> pnt = Point(1, 1, srid=4326)
- >>> wkb_w.write_hex(pnt) # By default, no SRID included:
+ >>> wkb_w.write_hex(pnt) # By default, no SRID included:
'0101000000000000000000F03F000000000000F03F'
- >>> wkb_w.srid = True # Tell writer to include SRID
+ >>> wkb_w.srid = True # Tell writer to include SRID
>>> wkb_w.write_hex(pnt)
'0101000020E6100000000000000000F03F000000000000F03F'
diff --git a/docs/ref/contrib/gis/install/postgis.txt b/docs/ref/contrib/gis/install/postgis.txt
index 5603c5e1c8..6af1f7e3fa 100644
--- a/docs/ref/contrib/gis/install/postgis.txt
+++ b/docs/ref/contrib/gis/install/postgis.txt
@@ -50,12 +50,9 @@ process. An alternative is to use a migration operation in your project::
from django.contrib.postgres.operations import CreateExtension
from django.db import migrations
- class Migration(migrations.Migration):
- operations = [
- CreateExtension('postgis'),
- ...
- ]
+ class Migration(migrations.Migration):
+ operations = [CreateExtension("postgis"), ...]
If you plan to use PostGIS raster functionality on PostGIS 3+, you should also
activate the ``postgis_raster`` extension. You can install the extension using
diff --git a/docs/ref/contrib/gis/install/spatialite.txt b/docs/ref/contrib/gis/install/spatialite.txt
index b4d6d25371..6606b8cff0 100644
--- a/docs/ref/contrib/gis/install/spatialite.txt
+++ b/docs/ref/contrib/gis/install/spatialite.txt
@@ -114,6 +114,6 @@ including SQLite, SpatiaLite, PROJ, and GEOS. Install them like this:
Finally, for GeoDjango to be able to find the SpatiaLite library, add the
following to your ``settings.py``::
- SPATIALITE_LIBRARY_PATH='/usr/local/lib/mod_spatialite.dylib'
+ SPATIALITE_LIBRARY_PATH = "/usr/local/lib/mod_spatialite.dylib"
.. _Homebrew: https://brew.sh/
diff --git a/docs/ref/contrib/gis/layermapping.txt b/docs/ref/contrib/gis/layermapping.txt
index 29ddf14b3d..e7971ca2b4 100644
--- a/docs/ref/contrib/gis/layermapping.txt
+++ b/docs/ref/contrib/gis/layermapping.txt
@@ -37,15 +37,15 @@ Example
.. code-block:: pycon
>>> from django.contrib.gis.gdal import DataSource
- >>> ds = DataSource('test_poly.shp')
+ >>> ds = DataSource("test_poly.shp")
>>> layer = ds[0]
- >>> print(layer.fields) # Exploring the fields in the layer, we only want the 'str' field.
+ >>> print(layer.fields) # Exploring the fields in the layer, we only want the 'str' field.
['float', 'int', 'str']
- >>> print(len(layer)) # getting the number of features in the layer (should be 3)
+ >>> print(len(layer)) # getting the number of features in the layer (should be 3)
3
- >>> print(layer.geom_type) # Should be 'Polygon'
+ >>> print(layer.geom_type) # Should be 'Polygon'
Polygon
- >>> print(layer.srs) # WGS84 in WKT
+ >>> print(layer.srs) # WGS84 in WKT
GEOGCS["GCS_WGS_1984",
DATUM["WGS_1984",
SPHEROID["WGS_1984",6378137,298.257223563]],
@@ -56,12 +56,13 @@ Example
from django.contrib.gis.db import models
+
class TestGeo(models.Model):
- name = models.CharField(max_length=25) # corresponds to the 'str' field
- poly = models.PolygonField(srid=4269) # we want our model in a different SRID
+ name = models.CharField(max_length=25) # corresponds to the 'str' field
+ poly = models.PolygonField(srid=4269) # we want our model in a different SRID
def __str__(self):
- return 'Name: %s' % self.name
+ return "Name: %s" % self.name
#. Use :class:`LayerMapping` to extract all the features and place them in the
database:
@@ -71,11 +72,11 @@ Example
>>> from django.contrib.gis.utils import LayerMapping
>>> from geoapp.models import TestGeo
>>> mapping = {
- ... 'name': 'str', # The 'name' model field maps to the 'str' layer field.
- ... 'poly': 'POLYGON', # For geometry fields use OGC name.
- ... } # The mapping is a dictionary
- >>> lm = LayerMapping(TestGeo, 'test_poly.shp', mapping)
- >>> lm.save(verbose=True) # Save the layermap, imports the data.
+ ... "name": "str", # The 'name' model field maps to the 'str' layer field.
+ ... "poly": "POLYGON", # For geometry fields use OGC name.
+ ... } # The mapping is a dictionary
+ >>> lm = LayerMapping(TestGeo, "test_poly.shp", mapping)
+ >>> lm.save(verbose=True) # Save the layermap, imports the data.
Saved: Name: 1
Saved: Name: 2
Saved: Name: 3
diff --git a/docs/ref/contrib/gis/measure.txt b/docs/ref/contrib/gis/measure.txt
index 8d87320d3b..ad02db87fa 100644
--- a/docs/ref/contrib/gis/measure.txt
+++ b/docs/ref/contrib/gis/measure.txt
@@ -24,7 +24,7 @@ instantiated in units of kilometers (``km``) and miles (``mi``):
>>> d1 = Distance(km=5)
>>> print(d1)
5.0 km
- >>> d2 = D(mi=5) # `D` is an alias for `Distance`
+ >>> d2 = D(mi=5) # `D` is an alias for `Distance`
>>> print(d2)
5.0 mi
@@ -33,9 +33,9 @@ distance quantity:
.. code-block:: pycon
- >>> print(d1.mi) # Converting 5 kilometers to miles
+ >>> print(d1.mi) # Converting 5 kilometers to miles
3.10685596119
- >>> print(d2.km) # Converting 5 miles to kilometers
+ >>> print(d2.km) # Converting 5 miles to kilometers
8.04672
Moreover, arithmetic operations may be performed between the distance
@@ -43,9 +43,9 @@ objects:
.. code-block:: pycon
- >>> print(d1 + d2) # Adding 5 miles to 5 kilometers
+ >>> print(d1 + d2) # Adding 5 miles to 5 kilometers
13.04672 km
- >>> print(d2 - d1) # Subtracting 5 kilometers from 5 miles
+ >>> print(d2 - d1) # Subtracting 5 kilometers from 5 miles
1.89314403881 mi
Two :class:`Distance` objects multiplied together will yield an :class:`Area`
@@ -53,7 +53,7 @@ object, which uses squared units of measure:
.. code-block:: pycon
- >>> a = d1 * d2 # Returns an Area object.
+ >>> a = d1 * d2 # Returns an Area object.
>>> print(a)
40.2336 sq_km
@@ -62,9 +62,9 @@ class method may be used:
.. code-block:: pycon
- >>> print(Distance.unit_attname('US Survey Foot'))
+ >>> print(Distance.unit_attname("US Survey Foot"))
survey_ft
- >>> print(Distance.unit_attname('centimeter'))
+ >>> print(Distance.unit_attname("centimeter"))
cm
.. _supported_units:
@@ -150,7 +150,7 @@ Measurement API
.. code-block:: pycon
- >>> Distance.unit_attname('Mile')
+ >>> Distance.unit_attname("Mile")
'mi'
.. class:: D
@@ -188,7 +188,7 @@ Measurement API
.. code-block:: pycon
- >>> Area.unit_attname('Kilometer')
+ >>> Area.unit_attname("Kilometer")
'sq_km'
.. class:: A
diff --git a/docs/ref/contrib/gis/model-api.txt b/docs/ref/contrib/gis/model-api.txt
index cd531ce785..e46d862707 100644
--- a/docs/ref/contrib/gis/model-api.txt
+++ b/docs/ref/contrib/gis/model-api.txt
@@ -11,10 +11,12 @@ of a `Digital Elevation Model`__ as our examples::
from django.contrib.gis.db import models
+
class Zipcode(models.Model):
code = models.CharField(max_length=5)
poly = models.PolygonField()
+
class Elevation(models.Model):
name = models.CharField(max_length=100)
rast = models.RasterField()
@@ -254,9 +256,9 @@ geography column to a geometry type in the query::
from django.contrib.gis.db.models import PointField
from django.db.models.functions import Cast
- Zipcode.objects.annotate(
- geom=Cast('geography_field', PointField())
- ).filter(geom__within=poly)
+ Zipcode.objects.annotate(geom=Cast("geography_field", PointField())).filter(
+ geom__within=poly
+ )
For more information, the PostGIS documentation contains a helpful section on
determining `when to use geography data type over geometry data type
diff --git a/docs/ref/contrib/gis/serializers.txt b/docs/ref/contrib/gis/serializers.txt
index 17886412a7..9f7ccd260d 100644
--- a/docs/ref/contrib/gis/serializers.txt
+++ b/docs/ref/contrib/gis/serializers.txt
@@ -40,31 +40,21 @@ Example::
from django.core.serializers import serialize
from my_app.models import City
- serialize('geojson', City.objects.all(),
- geometry_field='point',
- fields=['name'])
+ serialize("geojson", City.objects.all(), geometry_field="point", fields=["name"])
Would output::
{
- 'type': 'FeatureCollection',
- 'crs': {
- 'type': 'name',
- 'properties': {'name': 'EPSG:4326'}
- },
- 'features': [
- {
- 'type': 'Feature',
- 'id': 1,
- 'geometry': {
- 'type': 'Point',
- 'coordinates': [-87.650175, 41.850385]
- },
- 'properties': {
- 'name': 'Chicago'
- }
- }
- ]
+ "type": "FeatureCollection",
+ "crs": {"type": "name", "properties": {"name": "EPSG:4326"}},
+ "features": [
+ {
+ "type": "Feature",
+ "id": 1,
+ "geometry": {"type": "Point", "coordinates": [-87.650175, 41.850385]},
+ "properties": {"name": "Chicago"},
+ }
+ ],
}
When the ``fields`` parameter is not specified, the ``geojson`` serializer adds
diff --git a/docs/ref/contrib/gis/testing.txt b/docs/ref/contrib/gis/testing.txt
index 79d4779d18..75da181ee1 100644
--- a/docs/ref/contrib/gis/testing.txt
+++ b/docs/ref/contrib/gis/testing.txt
@@ -106,19 +106,19 @@ that can be used to run the entire Django test suite, including those
in :mod:`django.contrib.gis`::
DATABASES = {
- 'default': {
- 'ENGINE': 'django.contrib.gis.db.backends.postgis',
- 'NAME': 'geodjango',
- 'USER': 'geodjango',
+ "default": {
+ "ENGINE": "django.contrib.gis.db.backends.postgis",
+ "NAME": "geodjango",
+ "USER": "geodjango",
},
- 'other': {
- 'ENGINE': 'django.contrib.gis.db.backends.postgis',
- 'NAME': 'other',
- 'USER': 'geodjango',
+ "other": {
+ "ENGINE": "django.contrib.gis.db.backends.postgis",
+ "NAME": "other",
+ "USER": "geodjango",
},
}
- SECRET_KEY = 'django_tests_secret_key'
+ SECRET_KEY = "django_tests_secret_key"
Assuming the settings above were in a ``postgis.py`` file in the same
directory as ``runtests.py``, then all Django and GeoDjango tests would
diff --git a/docs/ref/contrib/gis/tutorial.txt b/docs/ref/contrib/gis/tutorial.txt
index 4e8f5f4bb0..d1c4cdb8e4 100644
--- a/docs/ref/contrib/gis/tutorial.txt
+++ b/docs/ref/contrib/gis/tutorial.txt
@@ -77,10 +77,10 @@ The ``geodjango`` project settings are stored in the ``geodjango/settings.py``
file. Edit the database connection settings to match your setup::
DATABASES = {
- 'default': {
- 'ENGINE': 'django.contrib.gis.db.backends.postgis',
- 'NAME': 'geodjango',
- 'USER': 'geo',
+ "default": {
+ "ENGINE": "django.contrib.gis.db.backends.postgis",
+ "NAME": "geodjango",
+ "USER": "geo",
},
}
@@ -89,14 +89,14 @@ In addition, modify the :setting:`INSTALLED_APPS` setting to include
and ``world`` (your newly created application)::
INSTALLED_APPS = [
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'django.contrib.gis',
- 'world',
+ "django.contrib.admin",
+ "django.contrib.auth",
+ "django.contrib.contenttypes",
+ "django.contrib.sessions",
+ "django.contrib.messages",
+ "django.contrib.staticfiles",
+ "django.contrib.gis",
+ "world",
]
Geographic Data
@@ -197,18 +197,19 @@ model to represent this data::
from django.contrib.gis.db import models
+
class WorldBorder(models.Model):
# Regular Django fields corresponding to the attributes in the
# world borders shapefile.
name = models.CharField(max_length=50)
area = models.IntegerField()
- pop2005 = models.IntegerField('Population 2005')
- fips = models.CharField('FIPS Code', max_length=2, null=True)
- iso2 = models.CharField('2 Digit ISO', max_length=2)
- iso3 = models.CharField('3 Digit ISO', max_length=3)
- un = models.IntegerField('United Nations Code')
- region = models.IntegerField('Region Code')
- subregion = models.IntegerField('Sub-Region Code')
+ pop2005 = models.IntegerField("Population 2005")
+ fips = models.CharField("FIPS Code", max_length=2, null=True)
+ iso2 = models.CharField("2 Digit ISO", max_length=2)
+ iso3 = models.CharField("3 Digit ISO", max_length=3)
+ un = models.IntegerField("United Nations Code")
+ region = models.IntegerField("Region Code")
+ subregion = models.IntegerField("Sub-Region Code")
lon = models.FloatField()
lat = models.FloatField()
@@ -327,7 +328,7 @@ you can determine its path using Python's :class:`pathlib.Path`:
>>> from pathlib import Path
>>> import world
- >>> world_shp = Path(world.__file__).resolve().parent / 'data' / 'TM_WORLD_BORDERS-0.3.shp'
+ >>> world_shp = Path(world.__file__).resolve().parent / "data" / "TM_WORLD_BORDERS-0.3.shp"
Now, open the world borders shapefile using GeoDjango's
:class:`~django.contrib.gis.gdal.DataSource` interface:
@@ -389,7 +390,7 @@ system associated with it. If it does, the ``srs`` attribute will return a
AXIS["Latitude",NORTH],
AXIS["Longitude",EAST],
AUTHORITY["EPSG","4326"]]
- >>> srs.proj # PROJ representation
+ >>> srs.proj # PROJ representation
'+proj=longlat +datum=WGS84 +no_defs'
This shapefile is in the popular WGS84 spatial reference
@@ -416,7 +417,7 @@ method):
.. code-block:: pycon
>>> for feat in lyr:
- ... print(feat.get('NAME'), feat.geom.num_points)
+ ... print(feat.get("NAME"), feat.geom.num_points)
...
Guernsey 18
Jersey 26
@@ -435,7 +436,7 @@ And individual features may be retrieved by their feature ID:
.. code-block:: pycon
>>> feat = lyr[234]
- >>> print(feat.get('NAME'))
+ >>> print(feat.get("NAME"))
San Marino
Boundary geometries may be exported as WKT and GeoJSON:
@@ -460,21 +461,22 @@ with the following code::
from .models import WorldBorder
world_mapping = {
- 'fips' : 'FIPS',
- 'iso2' : 'ISO2',
- 'iso3' : 'ISO3',
- 'un' : 'UN',
- 'name' : 'NAME',
- 'area' : 'AREA',
- 'pop2005' : 'POP2005',
- 'region' : 'REGION',
- 'subregion' : 'SUBREGION',
- 'lon' : 'LON',
- 'lat' : 'LAT',
- 'mpoly' : 'MULTIPOLYGON',
+ "fips": "FIPS",
+ "iso2": "ISO2",
+ "iso3": "ISO3",
+ "un": "UN",
+ "name": "NAME",
+ "area": "AREA",
+ "pop2005": "POP2005",
+ "region": "REGION",
+ "subregion": "SUBREGION",
+ "lon": "LON",
+ "lat": "LAT",
+ "mpoly": "MULTIPOLYGON",
}
- world_shp = Path(__file__).resolve().parent / 'data' / 'TM_WORLD_BORDERS-0.3.shp'
+ world_shp = Path(__file__).resolve().parent / "data" / "TM_WORLD_BORDERS-0.3.shp"
+
def run(verbose=True):
lm = LayerMapping(WorldBorder, world_shp, world_mapping, transform=False)
@@ -553,6 +555,7 @@ directly into the ``models.py`` of a GeoDjango application::
# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models
+
class WorldBorder(models.Model):
fips = models.CharField(max_length=2)
iso2 = models.CharField(max_length=2)
@@ -567,20 +570,21 @@ directly into the ``models.py`` of a GeoDjango application::
lat = models.FloatField()
geom = models.MultiPolygonField(srid=4326)
+
# Auto-generated `LayerMapping` dictionary for WorldBorder model
worldborders_mapping = {
- 'fips' : 'FIPS',
- 'iso2' : 'ISO2',
- 'iso3' : 'ISO3',
- 'un' : 'UN',
- 'name' : 'NAME',
- 'area' : 'AREA',
- 'pop2005' : 'POP2005',
- 'region' : 'REGION',
- 'subregion' : 'SUBREGION',
- 'lon' : 'LON',
- 'lat' : 'LAT',
- 'geom' : 'MULTIPOLYGON',
+ "fips": "FIPS",
+ "iso2": "ISO2",
+ "iso3": "ISO3",
+ "un": "UN",
+ "name": "NAME",
+ "area": "AREA",
+ "pop2005": "POP2005",
+ "region": "REGION",
+ "subregion": "SUBREGION",
+ "lon": "LON",
+ "lat": "LAT",
+ "geom": "MULTIPOLYGON",
}
Spatial Queries
@@ -600,7 +604,7 @@ Now, define a point of interest [#]_:
.. code-block:: pycon
- >>> pnt_wkt = 'POINT(-95.3385 29.7245)'
+ >>> pnt_wkt = "POINT(-95.3385 29.7245)"
The ``pnt_wkt`` string represents the point at -95.3385 degrees longitude,
29.7245 degrees latitude. The geometry is in a format known as
@@ -652,7 +656,7 @@ WKT that includes the SRID:
.. code-block:: pycon
- >>> pnt = GEOSGeometry('SRID=32140;POINT(954158.1 4215137.1)')
+ >>> pnt = GEOSGeometry("SRID=32140;POINT(954158.1 4215137.1)")
GeoDjango's ORM will automatically wrap geometry values
in transformation SQL, allowing the developer to work at a higher level
@@ -661,14 +665,14 @@ of abstraction:
.. code-block:: pycon
>>> qs = WorldBorder.objects.filter(mpoly__intersects=pnt)
- >>> print(qs.query) # Generating the SQL
+ >>> print(qs.query) # Generating the SQL
SELECT "world_worldborder"."id", "world_worldborder"."name", "world_worldborder"."area",
"world_worldborder"."pop2005", "world_worldborder"."fips", "world_worldborder"."iso2",
"world_worldborder"."iso3", "world_worldborder"."un", "world_worldborder"."region",
"world_worldborder"."subregion", "world_worldborder"."lon", "world_worldborder"."lat",
"world_worldborder"."mpoly" FROM "world_worldborder"
WHERE ST_Intersects("world_worldborder"."mpoly", ST_Transform(%s, 4326))
- >>> qs # printing evaluates the queryset
+ >>> qs # printing evaluates the queryset
<QuerySet [<WorldBorder: United States>]>
__ https://spatialreference.org/ref/epsg/32140/
@@ -701,14 +705,14 @@ formats:
.. code-block:: pycon
- >>> sm = WorldBorder.objects.get(name='San Marino')
+ >>> sm = WorldBorder.objects.get(name="San Marino")
>>> sm.mpoly
<MultiPolygon object at 0x24c6798>
- >>> sm.mpoly.wkt # WKT
+ >>> sm.mpoly.wkt # WKT
MULTIPOLYGON (((12.4157980000000006 43.9579540000000009, 12.4505540000000003 43.9797209999999978, ...
- >>> sm.mpoly.wkb # WKB (as Python binary buffer)
+ >>> sm.mpoly.wkb # WKB (as Python binary buffer)
<read-only buffer for 0x1fe2c70, size -1, offset 0 at 0x2564c40>
- >>> sm.mpoly.geojson # GeoJSON
+ >>> sm.mpoly.geojson # GeoJSON
'{ "type": "MultiPolygon", "coordinates": [ [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], ...
This includes access to all of the advanced geometric operations provided by
@@ -758,7 +762,7 @@ Next, edit your ``urls.py`` in the ``geodjango`` application folder as follows::
from django.urls import include, path
urlpatterns = [
- path('admin/', admin.site.urls),
+ path("admin/", admin.site.urls),
]
Create an admin user:
diff --git a/docs/ref/contrib/messages.txt b/docs/ref/contrib/messages.txt
index 403ad5649f..b4094c0c13 100644
--- a/docs/ref/contrib/messages.txt
+++ b/docs/ref/contrib/messages.txt
@@ -83,7 +83,7 @@ default storage class. If it isn't suitable to your needs, you can select
another storage class by setting :setting:`MESSAGE_STORAGE` to its full import
path, for example::
- MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
+ MESSAGE_STORAGE = "django.contrib.messages.storage.cookie.CookieStorage"
.. class:: storage.base.BaseStorage
@@ -147,9 +147,10 @@ you wish to change. As this extends the default tags, you only need to provide
tags for the levels you wish to override::
from django.contrib.messages import constants as messages
+
MESSAGE_TAGS = {
- messages.INFO: '',
- 50: 'critical',
+ messages.INFO: "",
+ 50: "critical",
}
Using messages in views and templates
@@ -163,16 +164,17 @@ Adding a message
To add a message, call::
from django.contrib import messages
- messages.add_message(request, messages.INFO, 'Hello world.')
+
+ messages.add_message(request, messages.INFO, "Hello world.")
Some shortcut methods provide a standard way to add messages with commonly
used tags (which are usually represented as HTML classes for the message)::
- messages.debug(request, '%s SQL statements were executed.' % count)
- messages.info(request, 'Three credits remain in your account.')
- messages.success(request, 'Profile details updated.')
- messages.warning(request, 'Your account expires in three days.')
- messages.error(request, 'Document deleted.')
+ messages.debug(request, "%s SQL statements were executed." % count)
+ messages.info(request, "Three credits remain in your account.")
+ messages.success(request, "Profile details updated.")
+ messages.warning(request, "Your account expires in three days.")
+ messages.error(request, "Document deleted.")
.. _message-displaying:
@@ -264,8 +266,9 @@ level constants and use them to create more customized user feedback, e.g.::
CRITICAL = 50
+
def my_view(request):
- messages.add_message(request, CRITICAL, 'A serious error occurred.')
+ messages.add_message(request, CRITICAL, "A serious error occurred.")
When creating custom message levels you should be careful to avoid overloading
existing levels. The values for the built-in levels are:
@@ -299,12 +302,12 @@ method::
# Change the messages level to ensure the debug message is added.
messages.set_level(request, messages.DEBUG)
- messages.debug(request, 'Test message...')
+ messages.debug(request, "Test message...")
# In another request, record only messages with a level of WARNING and higher
messages.set_level(request, messages.WARNING)
- messages.success(request, 'Your profile was updated.') # ignored
- messages.warning(request, 'Your account is about to expire.') # recorded
+ messages.success(request, "Your profile was updated.") # ignored
+ messages.warning(request, "Your account is about to expire.") # recorded
# Set the messages level back to default.
messages.set_level(request, None)
@@ -312,6 +315,7 @@ method::
Similarly, the current effective level can be retrieved with ``get_level``::
from django.contrib import messages
+
current_level = messages.get_level(request)
For more information on how the minimum recorded level functions, see
@@ -323,8 +327,8 @@ Adding extra message tags
For more direct control over message tags, you can optionally provide a string
containing extra tags to any of the add methods::
- messages.add_message(request, messages.INFO, 'Over 9000!', extra_tags='dragonball')
- messages.error(request, 'Email box full', extra_tags='email')
+ messages.add_message(request, messages.INFO, "Over 9000!", extra_tags="dragonball")
+ messages.error(request, "Email box full", extra_tags="email")
Extra tags are added before the default tag for that level and are space
separated.
@@ -339,10 +343,12 @@ if they don't want to, you may pass an additional keyword argument
example::
messages.add_message(
- request, messages.SUCCESS, 'Profile details updated.',
+ request,
+ messages.SUCCESS,
+ "Profile details updated.",
fail_silently=True,
)
- messages.info(request, 'Hello world.', fail_silently=True)
+ messages.info(request, "Hello world.", fail_silently=True)
.. note::
Setting ``fail_silently=True`` only hides the ``MessageFailure`` that would
@@ -369,9 +375,10 @@ Adding messages in class-based views
from django.views.generic.edit import CreateView
from myapp.models import Author
+
class AuthorCreateView(SuccessMessageMixin, CreateView):
model = Author
- success_url = '/success/'
+ success_url = "/success/"
success_message = "%(name)s was created successfully"
The cleaned data from the ``form`` is available for string interpolation using
@@ -386,9 +393,10 @@ method.
from django.views.generic.edit import CreateView
from myapp.models import ComplicatedModel
+
class ComplicatedCreateView(SuccessMessageMixin, CreateView):
model = ComplicatedModel
- success_url = '/success/'
+ success_url = "/success/"
success_message = "%(calculated_field)s was created successfully"
def get_success_message(self, cleaned_data):
diff --git a/docs/ref/contrib/postgres/aggregates.txt b/docs/ref/contrib/postgres/aggregates.txt
index c61d3424eb..2675a90af2 100644
--- a/docs/ref/contrib/postgres/aggregates.txt
+++ b/docs/ref/contrib/postgres/aggregates.txt
@@ -16,7 +16,7 @@ module. They are described in more detail in the `PostgreSQL docs
.. code-block:: pycon
- >>> SomeModel.objects.aggregate(arr=ArrayAgg('somefield'))
+ >>> SomeModel.objects.aggregate(arr=ArrayAgg("somefield"))
{'arr': [0, 1, 2]}
.. admonition:: Common aggregate options
@@ -49,10 +49,11 @@ General-purpose aggregation functions
Examples::
- 'some_field'
- '-some_field'
+ "some_field"
+ "-some_field"
from django.db.models import F
- F('some_field').desc()
+
+ F("some_field").desc()
.. versionchanged:: 5.0
@@ -103,7 +104,7 @@ General-purpose aggregation functions
>>> from django.db.models import Q
>>> from django.contrib.postgres.aggregates import BoolAnd
- >>> Comment.objects.aggregate(booland=BoolAnd('published'))
+ >>> Comment.objects.aggregate(booland=BoolAnd("published"))
{'booland': False}
>>> Comment.objects.aggregate(booland=BoolAnd(Q(rank__lt=100)))
{'booland': True}
@@ -127,7 +128,7 @@ General-purpose aggregation functions
>>> from django.db.models import Q
>>> from django.contrib.postgres.aggregates import BoolOr
- >>> Comment.objects.aggregate(boolor=BoolOr('published'))
+ >>> Comment.objects.aggregate(boolor=BoolOr("published"))
{'boolor': True}
>>> Comment.objects.aggregate(boolor=BoolOr(Q(rank__gt=2)))
{'boolor': False}
@@ -160,8 +161,9 @@ General-purpose aggregation functions
class Room(models.Model):
number = models.IntegerField(unique=True)
+
class HotelReservation(models.Model):
- room = models.ForeignKey('Room', on_delete=models.CASCADE)
+ room = models.ForeignKey("Room", on_delete=models.CASCADE)
start = models.DateTimeField()
end = models.DateTimeField()
requirements = models.JSONField(blank=True, null=True)
@@ -171,10 +173,10 @@ General-purpose aggregation functions
>>> from django.contrib.postgres.aggregates import JSONBAgg
>>> Room.objects.annotate(
... requirements=JSONBAgg(
- ... 'hotelreservation__requirements',
- ... ordering='-hotelreservation__start',
+ ... "hotelreservation__requirements",
+ ... ordering="-hotelreservation__start",
... )
- ... ).filter(requirements__0__sea_view=True).values('number', 'requirements')
+ ... ).filter(requirements__0__sea_view=True).values("number", "requirements")
<QuerySet [{'number': 102, 'requirements': [
{'parking': False, 'sea_view': True, 'double_bed': False},
{'parking': True, 'double_bed': True}
@@ -217,6 +219,7 @@ General-purpose aggregation functions
class Publication(models.Model):
title = models.CharField(max_length=30)
+
class Article(models.Model):
headline = models.CharField(max_length=100)
publications = models.ManyToManyField(Publication)
@@ -373,11 +376,11 @@ Here's some examples of some of the general-purpose aggregation functions:
.. code-block:: pycon
- >>> TestModel.objects.aggregate(result=StringAgg('field1', delimiter=';'))
+ >>> TestModel.objects.aggregate(result=StringAgg("field1", delimiter=";"))
{'result': 'foo;bar;test'}
- >>> TestModel.objects.aggregate(result=ArrayAgg('field2'))
+ >>> TestModel.objects.aggregate(result=ArrayAgg("field2"))
{'result': [1, 2, 3]}
- >>> TestModel.objects.aggregate(result=ArrayAgg('field1'))
+ >>> TestModel.objects.aggregate(result=ArrayAgg("field1"))
{'result': ['foo', 'bar', 'test']}
The next example shows the usage of statistical aggregate functions. The
@@ -386,8 +389,9 @@ underlying math will be not described (you can read about this, for example, at
.. code-block:: pycon
- >>> TestModel.objects.aggregate(count=RegrCount(y='field3', x='field2'))
+ >>> TestModel.objects.aggregate(count=RegrCount(y="field3", x="field2"))
{'count': 2}
- >>> TestModel.objects.aggregate(avgx=RegrAvgX(y='field3', x='field2'),
- ... avgy=RegrAvgY(y='field3', x='field2'))
+ >>> TestModel.objects.aggregate(
+ ... avgx=RegrAvgX(y="field3", x="field2"), avgy=RegrAvgY(y="field3", x="field2")
+ ... )
{'avgx': 2, 'avgy': 13}
diff --git a/docs/ref/contrib/postgres/constraints.txt b/docs/ref/contrib/postgres/constraints.txt
index abc5e4e4e4..ce9f0cf78f 100644
--- a/docs/ref/contrib/postgres/constraints.txt
+++ b/docs/ref/contrib/postgres/constraints.txt
@@ -47,9 +47,9 @@ second element is an SQL operator represented as a string. To avoid typos, you
may use :class:`~django.contrib.postgres.fields.RangeOperators` which maps the
operators with strings. For example::
- expressions=[
- ('timespan', RangeOperators.ADJACENT_TO),
- (F('room'), RangeOperators.EQUAL),
+ expressions = [
+ ("timespan", RangeOperators.ADJACENT_TO),
+ (F("room"), RangeOperators.EQUAL),
]
.. admonition:: Restrictions on operators.
@@ -60,8 +60,8 @@ The :class:`OpClass() <django.contrib.postgres.indexes.OpClass>` expression can
be used to specify a custom `operator class`_ for the constraint expressions.
For example::
- expressions=[
- (OpClass('circle', name='circle_ops'), RangeOperators.OVERLAPS),
+ expressions = [
+ (OpClass("circle", name="circle_ops"), RangeOperators.OVERLAPS),
]
creates an exclusion constraint on ``circle`` using ``circle_ops``.
@@ -103,9 +103,9 @@ are ``Deferrable.DEFERRED`` or ``Deferrable.IMMEDIATE``. For example::
ExclusionConstraint(
- name='exclude_overlapping_deferred',
+ name="exclude_overlapping_deferred",
expressions=[
- ('timespan', RangeOperators.OVERLAPS),
+ ("timespan", RangeOperators.OVERLAPS),
],
deferrable=Deferrable.DEFERRED,
)
@@ -161,22 +161,23 @@ taking canceled reservations into account::
from django.db import models
from django.db.models import Q
+
class Room(models.Model):
number = models.IntegerField()
class Reservation(models.Model):
- room = models.ForeignKey('Room', on_delete=models.CASCADE)
+ room = models.ForeignKey("Room", on_delete=models.CASCADE)
timespan = DateTimeRangeField()
cancelled = models.BooleanField(default=False)
class Meta:
constraints = [
ExclusionConstraint(
- name='exclude_overlapping_reservations',
+ name="exclude_overlapping_reservations",
expressions=[
- ('timespan', RangeOperators.OVERLAPS),
- ('room', RangeOperators.EQUAL),
+ ("timespan", RangeOperators.OVERLAPS),
+ ("room", RangeOperators.EQUAL),
],
condition=Q(cancelled=False),
),
@@ -202,12 +203,12 @@ current/rangetypes.html#RANGETYPES-INCLUSIVITY>`_. For example::
class TsTzRange(Func):
- function = 'TSTZRANGE'
+ function = "TSTZRANGE"
output_field = DateTimeRangeField()
class Reservation(models.Model):
- room = models.ForeignKey('Room', on_delete=models.CASCADE)
+ room = models.ForeignKey("Room", on_delete=models.CASCADE)
start = models.DateTimeField()
end = models.DateTimeField()
cancelled = models.BooleanField(default=False)
@@ -215,10 +216,13 @@ current/rangetypes.html#RANGETYPES-INCLUSIVITY>`_. For example::
class Meta:
constraints = [
ExclusionConstraint(
- name='exclude_overlapping_reservations',
+ name="exclude_overlapping_reservations",
expressions=[
- (TsTzRange('start', 'end', RangeBoundary()), RangeOperators.OVERLAPS),
- ('room', RangeOperators.EQUAL),
+ (
+ TsTzRange("start", "end", RangeBoundary()),
+ RangeOperators.OVERLAPS,
+ ),
+ ("room", RangeOperators.EQUAL),
],
condition=Q(cancelled=False),
),
diff --git a/docs/ref/contrib/postgres/expressions.txt b/docs/ref/contrib/postgres/expressions.txt
index 9ce2b9f7c6..c1252dbddb 100644
--- a/docs/ref/contrib/postgres/expressions.txt
+++ b/docs/ref/contrib/postgres/expressions.txt
@@ -29,8 +29,8 @@ objects:
>>> from django.db.models import OuterRef
>>> from django.db.models.functions import JSONObject
>>> from django.contrib.postgres.expressions import ArraySubquery
- >>> books = Book.objects.filter(author=OuterRef('pk')).values(
- ... json=JSONObject(title='title', pages='pages')
+ >>> books = Book.objects.filter(author=OuterRef("pk")).values(
+ ... json=JSONObject(title="title", pages="pages")
... )
>>> author = Author.objects.annotate(books=ArraySubquery(books)).first()
>>> author.books
diff --git a/docs/ref/contrib/postgres/fields.txt b/docs/ref/contrib/postgres/fields.txt
index 75f035d5b2..b53ce86696 100644
--- a/docs/ref/contrib/postgres/fields.txt
+++ b/docs/ref/contrib/postgres/fields.txt
@@ -57,6 +57,7 @@ may be a good choice for the :ref:`range fields <range-fields>` and
from django.contrib.postgres.fields import ArrayField
from django.db import models
+
class ChessBoard(models.Model):
board = ArrayField(
ArrayField(
@@ -86,20 +87,26 @@ may be a good choice for the :ref:`range fields <range-fields>` and
from django.contrib.postgres.fields import ArrayField
from django.db import models
+
class Board(models.Model):
pieces = ArrayField(ArrayField(models.IntegerField()))
+
# Valid
- Board(pieces=[
- [2, 3],
- [2, 1],
- ])
+ Board(
+ pieces=[
+ [2, 3],
+ [2, 1],
+ ]
+ )
# Not valid
- Board(pieces=[
- [2, 3],
- [2],
- ])
+ Board(
+ pieces=[
+ [2, 3],
+ [2],
+ ]
+ )
If irregular shapes are required, then the underlying field should be made
nullable and the values padded with ``None``.
@@ -113,6 +120,7 @@ We will use the following example model::
from django.contrib.postgres.fields import ArrayField
from django.db import models
+
class Post(models.Model):
name = models.CharField(max_length=200)
tags = ArrayField(models.CharField(max_length=200), blank=True)
@@ -131,17 +139,17 @@ data. It uses the SQL operator ``@>``. For example:
.. code-block:: pycon
- >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
- >>> Post.objects.create(name='Second post', tags=['thoughts'])
- >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
+ >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
+ >>> Post.objects.create(name="Second post", tags=["thoughts"])
+ >>> Post.objects.create(name="Third post", tags=["tutorial", "django"])
- >>> Post.objects.filter(tags__contains=['thoughts'])
+ >>> Post.objects.filter(tags__contains=["thoughts"])
<QuerySet [<Post: First post>, <Post: Second post>]>
- >>> Post.objects.filter(tags__contains=['django'])
+ >>> Post.objects.filter(tags__contains=["django"])
<QuerySet [<Post: First post>, <Post: Third post>]>
- >>> Post.objects.filter(tags__contains=['django', 'thoughts'])
+ >>> Post.objects.filter(tags__contains=["django", "thoughts"])
<QuerySet [<Post: First post>]>
.. fieldlookup:: arrayfield.contained_by
@@ -155,14 +163,14 @@ passed. It uses the SQL operator ``<@``. For example:
.. code-block:: pycon
- >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
- >>> Post.objects.create(name='Second post', tags=['thoughts'])
- >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
+ >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
+ >>> Post.objects.create(name="Second post", tags=["thoughts"])
+ >>> Post.objects.create(name="Third post", tags=["tutorial", "django"])
- >>> Post.objects.filter(tags__contained_by=['thoughts', 'django'])
+ >>> Post.objects.filter(tags__contained_by=["thoughts", "django"])
<QuerySet [<Post: First post>, <Post: Second post>]>
- >>> Post.objects.filter(tags__contained_by=['thoughts', 'django', 'tutorial'])
+ >>> Post.objects.filter(tags__contained_by=["thoughts", "django", "tutorial"])
<QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
.. fieldlookup:: arrayfield.overlap
@@ -175,17 +183,17 @@ the SQL operator ``&&``. For example:
.. code-block:: pycon
- >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
- >>> Post.objects.create(name='Second post', tags=['thoughts', 'tutorial'])
- >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
+ >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
+ >>> Post.objects.create(name="Second post", tags=["thoughts", "tutorial"])
+ >>> Post.objects.create(name="Third post", tags=["tutorial", "django"])
- >>> Post.objects.filter(tags__overlap=['thoughts'])
+ >>> Post.objects.filter(tags__overlap=["thoughts"])
<QuerySet [<Post: First post>, <Post: Second post>]>
- >>> Post.objects.filter(tags__overlap=['thoughts', 'tutorial'])
+ >>> Post.objects.filter(tags__overlap=["thoughts", "tutorial"])
<QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
- >>> Post.objects.filter(tags__overlap=Post.objects.values_list('tags'))
+ >>> Post.objects.filter(tags__overlap=Post.objects.values_list("tags"))
<QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
.. versionchanged:: 4.2
@@ -203,8 +211,8 @@ available for :class:`~django.db.models.IntegerField`. For example:
.. code-block:: pycon
- >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
- >>> Post.objects.create(name='Second post', tags=['thoughts'])
+ >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
+ >>> Post.objects.create(name="Second post", tags=["thoughts"])
>>> Post.objects.filter(tags__len=1)
<QuerySet [<Post: Second post>]>
@@ -221,16 +229,16 @@ array. The lookups available after the transform are those from the
.. code-block:: pycon
- >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
- >>> Post.objects.create(name='Second post', tags=['thoughts'])
+ >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
+ >>> Post.objects.create(name="Second post", tags=["thoughts"])
- >>> Post.objects.filter(tags__0='thoughts')
+ >>> Post.objects.filter(tags__0="thoughts")
<QuerySet [<Post: First post>, <Post: Second post>]>
- >>> Post.objects.filter(tags__1__iexact='Django')
+ >>> Post.objects.filter(tags__1__iexact="Django")
<QuerySet [<Post: First post>]>
- >>> Post.objects.filter(tags__276='javascript')
+ >>> Post.objects.filter(tags__276="javascript")
<QuerySet []>
.. note::
@@ -250,14 +258,14 @@ transform do not change. For example:
.. code-block:: pycon
- >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
- >>> Post.objects.create(name='Second post', tags=['thoughts'])
- >>> Post.objects.create(name='Third post', tags=['django', 'python', 'thoughts'])
+ >>> Post.objects.create(name="First post", tags=["thoughts", "django"])
+ >>> Post.objects.create(name="Second post", tags=["thoughts"])
+ >>> Post.objects.create(name="Third post", tags=["django", "python", "thoughts"])
- >>> Post.objects.filter(tags__0_1=['thoughts'])
+ >>> Post.objects.filter(tags__0_1=["thoughts"])
<QuerySet [<Post: First post>, <Post: Second post>]>
- >>> Post.objects.filter(tags__0_2__contains=['thoughts'])
+ >>> Post.objects.filter(tags__0_2__contains=["thoughts"])
<QuerySet [<Post: First post>, <Post: Second post>]>
.. note::
@@ -374,6 +382,7 @@ We will use the following example model::
from django.contrib.postgres.fields import HStoreField
from django.db import models
+
class Dog(models.Model):
name = models.CharField(max_length=200)
data = HStoreField()
@@ -390,17 +399,17 @@ To query based on a given key, you can use that key as the lookup name:
.. code-block:: pycon
- >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
- >>> Dog.objects.create(name='Meg', data={'breed': 'collie'})
+ >>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
+ >>> Dog.objects.create(name="Meg", data={"breed": "collie"})
- >>> Dog.objects.filter(data__breed='collie')
+ >>> Dog.objects.filter(data__breed="collie")
<QuerySet [<Dog: Meg>]>
You can chain other lookups after key lookups:
.. code-block:: pycon
- >>> Dog.objects.filter(data__breed__contains='l')
+ >>> Dog.objects.filter(data__breed__contains="l")
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
or use ``F()`` expressions to annotate a key value. For example:
@@ -441,14 +450,14 @@ field. It uses the SQL operator ``@>``. For example:
.. code-block:: pycon
- >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
- >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
- >>> Dog.objects.create(name='Fred', data={})
+ >>> Dog.objects.create(name="Rufus", data={"breed": "labrador", "owner": "Bob"})
+ >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
+ >>> Dog.objects.create(name="Fred", data={})
- >>> Dog.objects.filter(data__contains={'owner': 'Bob'})
+ >>> Dog.objects.filter(data__contains={"owner": "Bob"})
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
- >>> Dog.objects.filter(data__contains={'breed': 'collie'})
+ >>> Dog.objects.filter(data__contains={"breed": "collie"})
<QuerySet [<Dog: Meg>]>
.. fieldlookup:: hstorefield.contained_by
@@ -463,14 +472,14 @@ example:
.. code-block:: pycon
- >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
- >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
- >>> Dog.objects.create(name='Fred', data={})
+ >>> Dog.objects.create(name="Rufus", data={"breed": "labrador", "owner": "Bob"})
+ >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
+ >>> Dog.objects.create(name="Fred", data={})
- >>> Dog.objects.filter(data__contained_by={'breed': 'collie', 'owner': 'Bob'})
+ >>> Dog.objects.filter(data__contained_by={"breed": "collie", "owner": "Bob"})
<QuerySet [<Dog: Meg>, <Dog: Fred>]>
- >>> Dog.objects.filter(data__contained_by={'breed': 'collie'})
+ >>> Dog.objects.filter(data__contained_by={"breed": "collie"})
<QuerySet [<Dog: Fred>]>
.. fieldlookup:: hstorefield.has_key
@@ -483,10 +492,10 @@ Returns objects where the given key is in the data. Uses the SQL operator
.. code-block:: pycon
- >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
- >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
+ >>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
+ >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
- >>> Dog.objects.filter(data__has_key='owner')
+ >>> Dog.objects.filter(data__has_key="owner")
<QuerySet [<Dog: Meg>]>
.. fieldlookup:: hstorefield.has_any_keys
@@ -499,11 +508,11 @@ operator ``?|``. For example:
.. code-block:: pycon
- >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
- >>> Dog.objects.create(name='Meg', data={'owner': 'Bob'})
- >>> Dog.objects.create(name='Fred', data={})
+ >>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
+ >>> Dog.objects.create(name="Meg", data={"owner": "Bob"})
+ >>> Dog.objects.create(name="Fred", data={})
- >>> Dog.objects.filter(data__has_any_keys=['owner', 'breed'])
+ >>> Dog.objects.filter(data__has_any_keys=["owner", "breed"])
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
.. fieldlookup:: hstorefield.has_keys
@@ -516,10 +525,10 @@ Returns objects where all of the given keys are in the data. Uses the SQL operat
.. code-block:: pycon
- >>> Dog.objects.create(name='Rufus', data={})
- >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
+ >>> Dog.objects.create(name="Rufus", data={})
+ >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
- >>> Dog.objects.filter(data__has_keys=['breed', 'owner'])
+ >>> Dog.objects.filter(data__has_keys=["breed", "owner"])
<QuerySet [<Dog: Meg>]>
.. fieldlookup:: hstorefield.keys
@@ -535,10 +544,10 @@ in conjunction with lookups on
.. code-block:: pycon
- >>> Dog.objects.create(name='Rufus', data={'toy': 'bone'})
- >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
+ >>> Dog.objects.create(name="Rufus", data={"toy": "bone"})
+ >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
- >>> Dog.objects.filter(data__keys__overlap=['breed', 'toy'])
+ >>> Dog.objects.filter(data__keys__overlap=["breed", "toy"])
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
.. fieldlookup:: hstorefield.values
@@ -554,10 +563,10 @@ using in conjunction with lookups on
.. code-block:: pycon
- >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
- >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
+ >>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
+ >>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
- >>> Dog.objects.filter(data__values__contains=['collie'])
+ >>> Dog.objects.filter(data__values__contains=["collie"])
<QuerySet [<Dog: Meg>]>
.. _range-fields:
@@ -666,6 +675,7 @@ model::
from django.contrib.postgres.fields import IntegerRangeField
from django.db import models
+
class Event(models.Model):
name = models.CharField(max_length=200)
ages = IntegerRangeField()
@@ -681,8 +691,10 @@ We will also use the following example objects:
>>> import datetime
>>> from django.utils import timezone
>>> now = timezone.now()
- >>> Event.objects.create(name='Soft play', ages=(0, 10), start=now)
- >>> Event.objects.create(name='Pub trip', ages=(21, None), start=now - datetime.timedelta(days=1))
+ >>> Event.objects.create(name="Soft play", ages=(0, 10), start=now)
+ >>> Event.objects.create(
+ ... name="Pub trip", ages=(21, None), start=now - datetime.timedelta(days=1)
+ ... )
and ``NumericRange``:
@@ -945,16 +957,16 @@ corresponding lookups.
.. code-block:: python
class RangeOperators:
- EQUAL = '='
- NOT_EQUAL = '<>'
- CONTAINS = '@>'
- CONTAINED_BY = '<@'
- OVERLAPS = '&&'
- FULLY_LT = '<<'
- FULLY_GT = '>>'
- NOT_LT = '&>'
- NOT_GT = '&<'
- ADJACENT_TO = '-|-'
+ EQUAL = "="
+ NOT_EQUAL = "<>"
+ CONTAINS = "@>"
+ CONTAINED_BY = "<@"
+ OVERLAPS = "&&"
+ FULLY_LT = "<<"
+ FULLY_GT = ">>"
+ NOT_LT = "&>"
+ NOT_GT = "&<"
+ ADJACENT_TO = "-|-"
RangeBoundary() expressions
---------------------------
diff --git a/docs/ref/contrib/postgres/forms.txt b/docs/ref/contrib/postgres/forms.txt
index 95d705277b..3012b54a10 100644
--- a/docs/ref/contrib/postgres/forms.txt
+++ b/docs/ref/contrib/postgres/forms.txt
@@ -32,14 +32,15 @@ Fields
>>> class NumberListForm(forms.Form):
... numbers = SimpleArrayField(forms.IntegerField())
+ ...
- >>> form = NumberListForm({'numbers': '1,2,3'})
+ >>> form = NumberListForm({"numbers": "1,2,3"})
>>> form.is_valid()
True
>>> form.cleaned_data
{'numbers': [1, 2, 3]}
- >>> form = NumberListForm({'numbers': '1,2,a'})
+ >>> form = NumberListForm({"numbers": "1,2,a"})
>>> form.is_valid()
False
@@ -55,9 +56,10 @@ Fields
>>> from django.contrib.postgres.forms import SimpleArrayField
>>> class GridForm(forms.Form):
- ... places = SimpleArrayField(SimpleArrayField(IntegerField()), delimiter='|')
+ ... places = SimpleArrayField(SimpleArrayField(IntegerField()), delimiter="|")
+ ...
- >>> form = GridForm({'places': '1,2|2,1|4,3'})
+ >>> form = GridForm({"places": "1,2|2,1|4,3"})
>>> form.is_valid()
True
>>> form.cleaned_data
@@ -115,31 +117,31 @@ Fields
SplitArrayField(IntegerField(required=True), size=3, remove_trailing_nulls=False)
- ['1', '2', '3'] # -> [1, 2, 3]
- ['1', '2', ''] # -> ValidationError - third entry required.
- ['1', '', '3'] # -> ValidationError - second entry required.
- ['', '2', ''] # -> ValidationError - first and third entries required.
+ ["1", "2", "3"] # -> [1, 2, 3]
+ ["1", "2", ""] # -> ValidationError - third entry required.
+ ["1", "", "3"] # -> ValidationError - second entry required.
+ ["", "2", ""] # -> ValidationError - first and third entries required.
SplitArrayField(IntegerField(required=False), size=3, remove_trailing_nulls=False)
- ['1', '2', '3'] # -> [1, 2, 3]
- ['1', '2', ''] # -> [1, 2, None]
- ['1', '', '3'] # -> [1, None, 3]
- ['', '2', ''] # -> [None, 2, None]
+ ["1", "2", "3"] # -> [1, 2, 3]
+ ["1", "2", ""] # -> [1, 2, None]
+ ["1", "", "3"] # -> [1, None, 3]
+ ["", "2", ""] # -> [None, 2, None]
SplitArrayField(IntegerField(required=True), size=3, remove_trailing_nulls=True)
- ['1', '2', '3'] # -> [1, 2, 3]
- ['1', '2', ''] # -> [1, 2]
- ['1', '', '3'] # -> ValidationError - second entry required.
- ['', '2', ''] # -> ValidationError - first entry required.
+ ["1", "2", "3"] # -> [1, 2, 3]
+ ["1", "2", ""] # -> [1, 2]
+ ["1", "", "3"] # -> ValidationError - second entry required.
+ ["", "2", ""] # -> ValidationError - first entry required.
SplitArrayField(IntegerField(required=False), size=3, remove_trailing_nulls=True)
- ['1', '2', '3'] # -> [1, 2, 3]
- ['1', '2', ''] # -> [1, 2]
- ['1', '', '3'] # -> [1, None, 3]
- ['', '2', ''] # -> [None, 2]
+ ["1", "2", "3"] # -> [1, 2, 3]
+ ["1", "2", ""] # -> [1, 2]
+ ["1", "", "3"] # -> [1, None, 3]
+ ["", "2", ""] # -> [None, 2]
``HStoreField``
---------------
diff --git a/docs/ref/contrib/postgres/indexes.txt b/docs/ref/contrib/postgres/indexes.txt
index d428975c1a..5dfbef5c4c 100644
--- a/docs/ref/contrib/postgres/indexes.txt
+++ b/docs/ref/contrib/postgres/indexes.txt
@@ -149,16 +149,16 @@ available from the ``django.contrib.postgres.indexes`` module.
For example::
Index(
- OpClass(Lower('username'), name='varchar_pattern_ops'),
- name='lower_username_idx',
+ OpClass(Lower("username"), name="varchar_pattern_ops"),
+ name="lower_username_idx",
)
creates an index on ``Lower('username')`` using ``varchar_pattern_ops``.
::
UniqueConstraint(
- OpClass(Upper('description'), name='text_pattern_ops'),
- name='upper_description_unique',
+ OpClass(Upper("description"), name="text_pattern_ops"),
+ name="upper_description_unique",
)
creates a unique constraint on ``Upper('description')`` using
@@ -166,9 +166,9 @@ available from the ``django.contrib.postgres.indexes`` module.
::
ExclusionConstraint(
- name='exclude_overlapping_ops',
+ name="exclude_overlapping_ops",
expressions=[
- (OpClass('circle', name='circle_ops'), RangeOperators.OVERLAPS),
+ (OpClass("circle", name="circle_ops"), RangeOperators.OVERLAPS),
],
)
diff --git a/docs/ref/contrib/postgres/lookups.txt b/docs/ref/contrib/postgres/lookups.txt
index b4b072ffa8..b9b92fc7fa 100644
--- a/docs/ref/contrib/postgres/lookups.txt
+++ b/docs/ref/contrib/postgres/lookups.txt
@@ -53,7 +53,7 @@ The ``trigram_word_similar`` lookup can be used on
.. code-block:: pycon
- >>> Sentence.objects.filter(name__trigram_word_similar='Middlesborough')
+ >>> Sentence.objects.filter(name__trigram_word_similar="Middlesborough")
['<Sentence: Gumby rides on the path of Middlesbrough>']
.. fieldlookup:: trigram_strict_word_similar
diff --git a/docs/ref/contrib/postgres/operations.txt b/docs/ref/contrib/postgres/operations.txt
index d5b8a9e0d6..8928e4e0e2 100644
--- a/docs/ref/contrib/postgres/operations.txt
+++ b/docs/ref/contrib/postgres/operations.txt
@@ -22,13 +22,11 @@ For example::
from django.contrib.postgres.operations import HStoreExtension
+
class Migration(migrations.Migration):
...
- operations = [
- HStoreExtension(),
- ...
- ]
+ operations = [HStoreExtension(), ...]
The operation skips adding the extension if it already exists.
@@ -124,16 +122,17 @@ For example, to create a collation for German phone book ordering::
from django.contrib.postgres.operations import CreateCollation
+
class Migration(migrations.Migration):
...
operations = [
CreateCollation(
- 'german_phonebook',
- provider='icu',
- locale='und-u-ks-level2',
+ "german_phonebook",
+ provider="icu",
+ locale="und-u-ks-level2",
),
- ...
+ ...,
]
.. class:: CreateCollation(name, locale, *, provider='libc', deterministic=True)
diff --git a/docs/ref/contrib/postgres/search.txt b/docs/ref/contrib/postgres/search.txt
index cd737d3ed3..699f81bd11 100644
--- a/docs/ref/contrib/postgres/search.txt
+++ b/docs/ref/contrib/postgres/search.txt
@@ -26,7 +26,7 @@ single column in the database. For example:
.. code-block:: pycon
- >>> Entry.objects.filter(body_text__search='Cheese')
+ >>> Entry.objects.filter(body_text__search="Cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
This creates a ``to_tsvector`` in the database from the ``body_text`` field
@@ -50,8 +50,8 @@ To query against both fields, use a ``SearchVector``:
>>> from django.contrib.postgres.search import SearchVector
>>> Entry.objects.annotate(
- ... search=SearchVector('body_text', 'blog__tagline'),
- ... ).filter(search='Cheese')
+ ... search=SearchVector("body_text", "blog__tagline"),
+ ... ).filter(search="Cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
The arguments to ``SearchVector`` can be any
@@ -65,8 +65,8 @@ For example:
.. code-block:: pycon
>>> Entry.objects.annotate(
- ... search=SearchVector('body_text') + SearchVector('blog__tagline'),
- ... ).filter(search='Cheese')
+ ... search=SearchVector("body_text") + SearchVector("blog__tagline"),
+ ... ).filter(search="Cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
See :ref:`postgresql-fts-search-configuration` and
@@ -107,9 +107,9 @@ Examples:
.. code-block:: pycon
>>> from django.contrib.postgres.search import SearchQuery
- >>> SearchQuery('meat') & SearchQuery('cheese') # AND
- >>> SearchQuery('meat') | SearchQuery('cheese') # OR
- >>> ~SearchQuery('meat') # NOT
+ >>> SearchQuery("meat") & SearchQuery("cheese") # AND
+ >>> SearchQuery("meat") | SearchQuery("cheese") # OR
+ >>> ~SearchQuery("meat") # NOT
See :ref:`postgresql-fts-search-configuration` for an explanation of the
``config`` parameter.
@@ -130,9 +130,9 @@ order by relevancy:
.. code-block:: pycon
>>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
- >>> vector = SearchVector('body_text')
- >>> query = SearchQuery('cheese')
- >>> Entry.objects.annotate(rank=SearchRank(vector, query)).order_by('-rank')
+ >>> vector = SearchVector("body_text")
+ >>> query = SearchQuery("cheese")
+ >>> Entry.objects.annotate(rank=SearchRank(vector, query)).order_by("-rank")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
See :ref:`postgresql-fts-weighting-queries` for an explanation of the
@@ -199,13 +199,13 @@ Usage example:
.. code-block:: pycon
>>> from django.contrib.postgres.search import SearchHeadline, SearchQuery
- >>> query = SearchQuery('red tomato')
+ >>> query = SearchQuery("red tomato")
>>> entry = Entry.objects.annotate(
... headline=SearchHeadline(
- ... 'body_text',
+ ... "body_text",
... query,
- ... start_sel='<span>',
- ... stop_sel='</span>',
+ ... start_sel="<span>",
+ ... stop_sel="</span>",
... ),
... ).get()
>>> print(entry.headline)
@@ -229,8 +229,8 @@ different language parsers and dictionaries as defined by the database:
>>> from django.contrib.postgres.search import SearchQuery, SearchVector
>>> Entry.objects.annotate(
- ... search=SearchVector('body_text', config='french'),
- ... ).filter(search=SearchQuery('œuf', config='french'))
+ ... search=SearchVector("body_text", config="french"),
+ ... ).filter(search=SearchQuery("œuf", config="french"))
[<Entry: Pain perdu>]
The value of ``config`` could also be stored in another column:
@@ -239,8 +239,8 @@ The value of ``config`` could also be stored in another column:
>>> from django.db.models import F
>>> Entry.objects.annotate(
- ... search=SearchVector('body_text', config=F('blog__language')),
- ... ).filter(search=SearchQuery('œuf', config=F('blog__language')))
+ ... search=SearchVector("body_text", config=F("blog__language")),
+ ... ).filter(search=SearchQuery("œuf", config=F("blog__language")))
[<Entry: Pain perdu>]
.. _postgresql-fts-weighting-queries:
@@ -254,9 +254,13 @@ of various vectors before you combine them:
.. code-block:: pycon
>>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
- >>> vector = SearchVector('body_text', weight='A') + SearchVector('blog__tagline', weight='B')
- >>> query = SearchQuery('cheese')
- >>> Entry.objects.annotate(rank=SearchRank(vector, query)).filter(rank__gte=0.3).order_by('rank')
+ >>> vector = SearchVector("body_text", weight="A") + SearchVector(
+ ... "blog__tagline", weight="B"
+ ... )
+ >>> query = SearchQuery("cheese")
+ >>> Entry.objects.annotate(rank=SearchRank(vector, query)).filter(rank__gte=0.3).order_by(
+ ... "rank"
+ ... )
The weight should be one of the following letters: D, C, B, A. By default,
these weights refer to the numbers ``0.1``, ``0.2``, ``0.4``, and ``1.0``,
@@ -266,7 +270,7 @@ floats to :class:`SearchRank` as ``weights`` in the same order above:
.. code-block:: pycon
>>> rank = SearchRank(vector, query, weights=[0.2, 0.4, 0.6, 0.8])
- >>> Entry.objects.annotate(rank=rank).filter(rank__gte=0.3).order_by('-rank')
+ >>> Entry.objects.annotate(rank=rank).filter(rank__gte=0.3).order_by("-rank")
Performance
===========
@@ -283,8 +287,8 @@ particular model, you can create a functional
the search vector you wish to use. For example::
GinIndex(
- SearchVector('body_text', 'headline', config='english'),
- name='search_vector_idx',
+ SearchVector("body_text", "headline", config="english"),
+ name="search_vector_idx",
)
The PostgreSQL documentation has details on
@@ -303,8 +307,8 @@ if it were an annotated ``SearchVector``:
.. code-block:: pycon
- >>> Entry.objects.update(search_vector=SearchVector('body_text'))
- >>> Entry.objects.filter(search_vector='cheese')
+ >>> Entry.objects.update(search_vector=SearchVector("body_text"))
+ >>> Entry.objects.filter(search_vector="cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
.. _PostgreSQL documentation: https://www.postgresql.org/docs/current/textsearch-features.html#TEXTSEARCH-UPDATE-TRIGGERS
@@ -336,12 +340,14 @@ Usage example:
.. code-block:: pycon
>>> from django.contrib.postgres.search import TrigramSimilarity
- >>> Author.objects.create(name='Katy Stevens')
- >>> Author.objects.create(name='Stephen Keats')
- >>> test = 'Katie Stephens'
+ >>> Author.objects.create(name="Katy Stevens")
+ >>> Author.objects.create(name="Stephen Keats")
+ >>> test = "Katie Stephens"
>>> Author.objects.annotate(
- ... similarity=TrigramSimilarity('name', test),
- ... ).filter(similarity__gt=0.3).order_by('-similarity')
+ ... similarity=TrigramSimilarity("name", test),
+ ... ).filter(
+ ... similarity__gt=0.3
+ ... ).order_by("-similarity")
[<Author: Katy Stevens>, <Author: Stephen Keats>]
``TrigramWordSimilarity``
@@ -357,12 +363,14 @@ Usage example:
.. code-block:: pycon
>>> from django.contrib.postgres.search import TrigramWordSimilarity
- >>> Author.objects.create(name='Katy Stevens')
- >>> Author.objects.create(name='Stephen Keats')
- >>> test = 'Kat'
+ >>> Author.objects.create(name="Katy Stevens")
+ >>> Author.objects.create(name="Stephen Keats")
+ >>> test = "Kat"
>>> Author.objects.annotate(
- ... similarity=TrigramWordSimilarity(test, 'name'),
- ... ).filter(similarity__gt=0.3).order_by('-similarity')
+ ... similarity=TrigramWordSimilarity(test, "name"),
+ ... ).filter(
+ ... similarity__gt=0.3
+ ... ).order_by("-similarity")
[<Author: Katy Stevens>]
``TrigramStrictWordSimilarity``
@@ -390,12 +398,14 @@ Usage example:
.. code-block:: pycon
>>> from django.contrib.postgres.search import TrigramDistance
- >>> Author.objects.create(name='Katy Stevens')
- >>> Author.objects.create(name='Stephen Keats')
- >>> test = 'Katie Stephens'
+ >>> Author.objects.create(name="Katy Stevens")
+ >>> Author.objects.create(name="Stephen Keats")
+ >>> test = "Katie Stephens"
>>> Author.objects.annotate(
- ... distance=TrigramDistance('name', test),
- ... ).filter(distance__lte=0.7).order_by('distance')
+ ... distance=TrigramDistance("name", test),
+ ... ).filter(
+ ... distance__lte=0.7
+ ... ).order_by("distance")
[<Author: Katy Stevens>, <Author: Stephen Keats>]
``TrigramWordDistance``
@@ -411,12 +421,14 @@ Usage example:
.. code-block:: pycon
>>> from django.contrib.postgres.search import TrigramWordDistance
- >>> Author.objects.create(name='Katy Stevens')
- >>> Author.objects.create(name='Stephen Keats')
- >>> test = 'Kat'
+ >>> Author.objects.create(name="Katy Stevens")
+ >>> Author.objects.create(name="Stephen Keats")
+ >>> test = "Kat"
>>> Author.objects.annotate(
- ... distance=TrigramWordDistance(test, 'name'),
- ... ).filter(distance__lte=0.7).order_by('distance')
+ ... distance=TrigramWordDistance(test, "name"),
+ ... ).filter(
+ ... distance__lte=0.7
+ ... ).order_by("distance")
[<Author: Katy Stevens>]
``TrigramStrictWordDistance``
diff --git a/docs/ref/contrib/redirects.txt b/docs/ref/contrib/redirects.txt
index 02db2a2ec7..c3c082dec8 100644
--- a/docs/ref/contrib/redirects.txt
+++ b/docs/ref/contrib/redirects.txt
@@ -83,16 +83,16 @@ Via the Python API
>>> # Add a new redirect.
>>> redirect = Redirect.objects.create(
... site_id=1,
- ... old_path='/contact-us/',
- ... new_path='/contact/',
+ ... old_path="/contact-us/",
+ ... new_path="/contact/",
... )
>>> # Change a redirect.
- >>> redirect.new_path = '/contact-details/'
+ >>> redirect.new_path = "/contact-details/"
>>> redirect.save()
>>> redirect
<Redirect: /contact-us/ ---> /contact-details/>
>>> # Delete a redirect.
- >>> Redirect.objects.filter(site_id=1, old_path='/contact-us/').delete()
+ >>> Redirect.objects.filter(site_id=1, old_path="/contact-us/").delete()
(1, {'redirects.Redirect': 1})
Middleware
diff --git a/docs/ref/contrib/sitemaps.txt b/docs/ref/contrib/sitemaps.txt
index 79329d9c3a..af04611096 100644
--- a/docs/ref/contrib/sitemaps.txt
+++ b/docs/ref/contrib/sitemaps.txt
@@ -54,8 +54,12 @@ To activate sitemap generation on your Django site, add this line to your
from django.contrib.sitemaps.views import sitemap
- path('sitemap.xml', sitemap, {'sitemaps': sitemaps},
- name='django.contrib.sitemaps.views.sitemap')
+ path(
+ "sitemap.xml",
+ sitemap,
+ {"sitemaps": sitemaps},
+ name="django.contrib.sitemaps.views.sitemap",
+ )
This tells Django to build a sitemap when a client accesses :file:`/sitemap.xml`.
@@ -100,6 +104,7 @@ your sitemap class might look::
from django.contrib.sitemaps import Sitemap
from blog.models import Entry
+
class BlogSitemap(Sitemap):
changefreq = "never"
priority = 0.5
@@ -350,18 +355,20 @@ Here's an example of a :doc:`URLconf </topics/http/urls>` using
from blog.models import Entry
info_dict = {
- 'queryset': Entry.objects.all(),
- 'date_field': 'pub_date',
+ "queryset": Entry.objects.all(),
+ "date_field": "pub_date",
}
urlpatterns = [
# some generic view using info_dict
# ...
-
# the sitemap
- path('sitemap.xml', sitemap,
- {'sitemaps': {'blog': GenericSitemap(info_dict, priority=0.6)}},
- name='django.contrib.sitemaps.views.sitemap'),
+ path(
+ "sitemap.xml",
+ sitemap,
+ {"sitemaps": {"blog": GenericSitemap(info_dict, priority=0.6)}},
+ name="django.contrib.sitemaps.views.sitemap",
+ ),
]
.. _URLconf: ../url_dispatch/
@@ -378,16 +385,18 @@ the ``location`` method of the sitemap. For example::
from django.contrib import sitemaps
from django.urls import reverse
+
class StaticViewSitemap(sitemaps.Sitemap):
priority = 0.5
- changefreq = 'daily'
+ changefreq = "daily"
def items(self):
- return ['main', 'about', 'license']
+ return ["main", "about", "license"]
def location(self, item):
return reverse(item)
+
# urls.py
from django.contrib.sitemaps.views import sitemap
from django.urls import path
@@ -396,16 +405,20 @@ the ``location`` method of the sitemap. For example::
from . import views
sitemaps = {
- 'static': StaticViewSitemap,
+ "static": StaticViewSitemap,
}
urlpatterns = [
- path('', views.main, name='main'),
- path('about/', views.about, name='about'),
- path('license/', views.license, name='license'),
+ path("", views.main, name="main"),
+ path("about/", views.about, name="about"),
+ path("license/", views.license, name="license"),
# ...
- path('sitemap.xml', sitemap, {'sitemaps': sitemaps},
- name='django.contrib.sitemaps.views.sitemap')
+ path(
+ "sitemap.xml",
+ sitemap,
+ {"sitemaps": sitemaps},
+ name="django.contrib.sitemaps.views.sitemap",
+ ),
]
@@ -428,10 +441,18 @@ Here's what the relevant URLconf lines would look like for the example above::
from django.contrib.sitemaps import views
urlpatterns = [
- path('sitemap.xml', views.index, {'sitemaps': sitemaps},
- name='django.contrib.sitemaps.views.index'),
- path('sitemap-<section>.xml', views.sitemap, {'sitemaps': sitemaps},
- name='django.contrib.sitemaps.views.sitemap'),
+ path(
+ "sitemap.xml",
+ views.index,
+ {"sitemaps": sitemaps},
+ name="django.contrib.sitemaps.views.index",
+ ),
+ path(
+ "sitemap-<section>.xml",
+ views.sitemap,
+ {"sitemaps": sitemaps},
+ name="django.contrib.sitemaps.views.sitemap",
+ ),
]
This will automatically generate a :file:`sitemap.xml` file that references
@@ -455,12 +476,17 @@ with a caching decorator -- you must name your sitemap view and pass
from django.views.decorators.cache import cache_page
urlpatterns = [
- path('sitemap.xml',
- cache_page(86400)(sitemaps_views.index),
- {'sitemaps': sitemaps, 'sitemap_url_name': 'sitemaps'}),
- path('sitemap-<section>.xml',
- cache_page(86400)(sitemaps_views.sitemap),
- {'sitemaps': sitemaps}, name='sitemaps'),
+ path(
+ "sitemap.xml",
+ cache_page(86400)(sitemaps_views.index),
+ {"sitemaps": sitemaps, "sitemap_url_name": "sitemaps"},
+ ),
+ path(
+ "sitemap-<section>.xml",
+ cache_page(86400)(sitemaps_views.sitemap),
+ {"sitemaps": sitemaps},
+ name="sitemaps",
+ ),
]
Template customization
@@ -473,14 +499,18 @@ parameter to the ``sitemap`` and ``index`` views via the URLconf::
from django.contrib.sitemaps import views
urlpatterns = [
- path('custom-sitemap.xml', views.index, {
- 'sitemaps': sitemaps,
- 'template_name': 'custom_sitemap.html'
- }, name='django.contrib.sitemaps.views.index'),
- path('custom-sitemap-<section>.xml', views.sitemap, {
- 'sitemaps': sitemaps,
- 'template_name': 'custom_sitemap.html'
- }, name='django.contrib.sitemaps.views.sitemap'),
+ path(
+ "custom-sitemap.xml",
+ views.index,
+ {"sitemaps": sitemaps, "template_name": "custom_sitemap.html"},
+ name="django.contrib.sitemaps.views.index",
+ ),
+ path(
+ "custom-sitemap-<section>.xml",
+ views.sitemap,
+ {"sitemaps": sitemaps, "template_name": "custom_sitemap.html"},
+ name="django.contrib.sitemaps.views.sitemap",
+ ),
]
@@ -601,6 +631,7 @@ method::
from django.contrib.sitemaps import ping_google
+
class Entry(models.Model):
# ...
def save(self, force_insert=False, force_update=False):
diff --git a/docs/ref/contrib/sites.txt b/docs/ref/contrib/sites.txt
index e74ce97a97..b8b6a296e2 100644
--- a/docs/ref/contrib/sites.txt
+++ b/docs/ref/contrib/sites.txt
@@ -65,6 +65,7 @@ Django model terminology, that's represented by a
from django.contrib.sites.models import Site
from django.db import models
+
class Article(models.Model):
headline = models.CharField(max_length=200)
# ...
@@ -84,6 +85,7 @@ This accomplishes several things quite nicely:
from django.contrib.sites.shortcuts import get_current_site
+
def article_detail(request, article_id):
try:
a = Article.objects.get(id=article_id, sites__id=get_current_site(request).id)
@@ -108,6 +110,7 @@ like this::
from django.contrib.sites.models import Site
from django.db import models
+
class Article(models.Model):
headline = models.CharField(max_length=200)
# ...
@@ -126,6 +129,7 @@ For example::
from django.conf import settings
+
def my_view(request):
if settings.SITE_ID == 3:
# Do something.
@@ -140,9 +144,10 @@ domain::
from django.contrib.sites.shortcuts import get_current_site
+
def my_view(request):
current_site = get_current_site(request)
- if current_site.domain == 'foo.com':
+ if current_site.domain == "foo.com":
# Do something
pass
else:
@@ -160,9 +165,10 @@ the :setting:`SITE_ID` setting. This example is equivalent to the previous one::
from django.contrib.sites.models import Site
+
def my_function_without_request():
current_site = Site.objects.get_current()
- if current_site.domain == 'foo.com':
+ if current_site.domain == "foo.com":
# Do something
pass
else:
@@ -190,17 +196,17 @@ Here's an example of what the form-handling view looks like::
from django.contrib.sites.shortcuts import get_current_site
from django.core.mail import send_mail
+
def register_for_newsletter(request):
# Check form values, etc., and subscribe the user.
# ...
current_site = get_current_site(request)
send_mail(
- 'Thanks for subscribing to %s alerts' % current_site.name,
- 'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % (
- current_site.name,
- ),
- 'editor@%s' % current_site.domain,
+ "Thanks for subscribing to %s alerts" % current_site.name,
+ "Thanks for your subscription. We appreciate it.\n\n-The %s team."
+ % (current_site.name,),
+ "editor@%s" % current_site.domain,
[user.email],
)
@@ -218,13 +224,14 @@ farm out to the template system like so::
from django.core.mail import send_mail
from django.template import loader
+
def register_for_newsletter(request):
# Check form values, etc., and subscribe the user.
# ...
- subject = loader.get_template('alerts/subject.txt').render({})
- message = loader.get_template('alerts/message.txt').render({})
- send_mail(subject, message, 'editor@ljworld.com', [user.email])
+ subject = loader.get_template("alerts/subject.txt").render({})
+ message = loader.get_template("alerts/message.txt").render({})
+ send_mail(subject, message, "editor@ljworld.com", [user.email])
# ...
@@ -251,7 +258,7 @@ To do this, you can use the sites framework. An example:
'/mymodel/objects/3/'
>>> Site.objects.get_current().domain
'example.com'
- >>> 'https://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
+ >>> "https://%s%s" % (Site.objects.get_current().domain, obj.get_absolute_url())
'https://example.com/mymodel/objects/3/'
.. _enabling-the-sites-framework:
@@ -328,8 +335,9 @@ your model explicitly. For example::
from django.contrib.sites.managers import CurrentSiteManager
from django.db import models
+
class Photo(models.Model):
- photo = models.FileField(upload_to='photos')
+ photo = models.FileField(upload_to="photos")
photographer_name = models.CharField(max_length=100)
pub_date = models.DateField()
site = models.ForeignKey(Site, on_delete=models.CASCADE)
@@ -365,13 +373,14 @@ demonstrates this::
from django.contrib.sites.managers import CurrentSiteManager
from django.db import models
+
class Photo(models.Model):
- photo = models.FileField(upload_to='photos')
+ photo = models.FileField(upload_to="photos")
photographer_name = models.CharField(max_length=100)
pub_date = models.DateField()
publish_on = models.ForeignKey(Site, on_delete=models.CASCADE)
objects = models.Manager()
- on_site = CurrentSiteManager('publish_on')
+ on_site = CurrentSiteManager("publish_on")
If you attempt to use :class:`~django.contrib.sites.managers.CurrentSiteManager`
and pass a field name that doesn't exist, Django will raise a ``ValueError``.
@@ -397,6 +406,7 @@ If you often use this pattern::
from django.contrib.sites.models import Site
+
def my_view(request):
site = Site.objects.get_current()
...
diff --git a/docs/ref/contrib/staticfiles.txt b/docs/ref/contrib/staticfiles.txt
index 374e21cb0f..1b5c4b6abc 100644
--- a/docs/ref/contrib/staticfiles.txt
+++ b/docs/ref/contrib/staticfiles.txt
@@ -77,10 +77,11 @@ respectively. For example::
from django.contrib.staticfiles import storage
+
class MyStaticFilesStorage(storage.StaticFilesStorage):
def __init__(self, *args, **kwargs):
- kwargs['file_permissions_mode'] = 0o640
- kwargs['directory_permissions_mode'] = 0o760
+ kwargs["file_permissions_mode"] = 0o640
+ kwargs["directory_permissions_mode"] = 0o760
super().__init__(*args, **kwargs)
Then set the ``staticfiles`` storage backend in :setting:`STORAGES` setting to
@@ -142,6 +143,7 @@ class, override the ``ignore_patterns`` attribute of this class and replace
from django.contrib.staticfiles.apps import StaticFilesConfig
+
class MyStaticFilesConfig(StaticFilesConfig):
ignore_patterns = [...] # your custom ignore list
@@ -322,9 +324,11 @@ argument. For example::
from django.conf import settings
from django.contrib.staticfiles.storage import (
- ManifestStaticFilesStorage, StaticFilesStorage,
+ ManifestStaticFilesStorage,
+ StaticFilesStorage,
)
+
class MyManifestStaticFilesStorage(ManifestStaticFilesStorage):
def __init__(self, *args, **kwargs):
manifest_storage = StaticFilesStorage(location=settings.BASE_DIR)
@@ -421,7 +425,7 @@ of directory paths in which the finders searched. Example usage::
from django.contrib.staticfiles import finders
- result = finders.find('css/base.css')
+ result = finders.find("css/base.css")
searched_locations = finders.searched_locations
Other Helpers
@@ -499,7 +503,7 @@ primary URL configuration::
if settings.DEBUG:
urlpatterns += [
- re_path(r'^static/(?P<path>.*)$', views.serve),
+ re_path(r"^static/(?P<path>.*)$", views.serve),
]
Note, the beginning of the pattern (``r'^static/'``) should be your
diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt
index 7eab5dfd05..a3f678b1f0 100644
--- a/docs/ref/contrib/syndication.txt
+++ b/docs/ref/contrib/syndication.txt
@@ -55,13 +55,14 @@ a feed of the latest five news items::
from django.urls import reverse
from policebeat.models import NewsItem
+
class LatestEntriesFeed(Feed):
title = "Police beat site news"
link = "/sitenews/"
description = "Updates on changes and additions to police beat central."
def items(self):
- return NewsItem.objects.order_by('-pub_date')[:5]
+ return NewsItem.objects.order_by("-pub_date")[:5]
def item_title(self, item):
return item.title
@@ -71,7 +72,7 @@ a feed of the latest five news items::
# item_link is only needed if NewsItem has no get_absolute_url method.
def item_link(self, item):
- return reverse('news-item', args=[item.pk])
+ return reverse("news-item", args=[item.pk])
To connect a URL to this feed, put an instance of the Feed object in
your :doc:`URLconf </topics/http/urls>`. For example::
@@ -81,7 +82,7 @@ your :doc:`URLconf </topics/http/urls>`. For example::
urlpatterns = [
# ...
- path('latest/feed/', LatestEntriesFeed()),
+ path("latest/feed/", LatestEntriesFeed()),
# ...
]
@@ -145,16 +146,17 @@ into those elements.
from mysite.models import Article
from django.contrib.syndication.views import Feed
+
class ArticlesFeed(Feed):
title = "My articles"
description_template = "feeds/articles.html"
def items(self):
- return Article.objects.order_by('-pub_date')[:5]
+ return Article.objects.order_by("-pub_date")[:5]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- context['foo'] = 'bar'
+ context["foo"] = "bar"
return context
And the template:
@@ -215,7 +217,7 @@ The police beat feeds could be accessible via URLs like this:
These can be matched with a :doc:`URLconf </topics/http/urls>` line such as::
- path('beats/<int:beat_id>/rss/', BeatFeed()),
+ path("beats/<int:beat_id>/rss/", BeatFeed()),
Like a view, the arguments in the URL are passed to the ``get_object()``
method along with the request object.
@@ -224,8 +226,9 @@ Here's the code for these beat-specific feeds::
from django.contrib.syndication.views import Feed
+
class BeatFeed(Feed):
- description_template = 'feeds/beat_description.html'
+ description_template = "feeds/beat_description.html"
def get_object(self, request, beat_id):
return Beat.objects.get(pk=beat_id)
@@ -240,7 +243,7 @@ Here's the code for these beat-specific feeds::
return "Crimes recently reported in police beat %s" % obj.beat
def items(self, obj):
- return Crime.objects.filter(beat=obj).order_by('-crime_date')[:30]
+ return Crime.objects.filter(beat=obj).order_by("-crime_date")[:30]
To generate the feed's ``<title>``, ``<link>`` and ``<description>``, Django
uses the ``title()``, ``link()`` and ``description()`` methods. In
@@ -282,6 +285,7 @@ To change that, add a ``feed_type`` attribute to your
from django.utils.feedgenerator import Atom1Feed
+
class MyFeed(Feed):
feed_type = Atom1Feed
@@ -337,13 +341,15 @@ Here's a full example::
from policebeat.models import NewsItem
from django.utils.feedgenerator import Atom1Feed
+
class RssSiteNewsFeed(Feed):
title = "Police beat site news"
link = "/sitenews/"
description = "Updates on changes and additions to police beat central."
def items(self):
- return NewsItem.objects.order_by('-pub_date')[:5]
+ return NewsItem.objects.order_by("-pub_date")[:5]
+
class AtomSiteNewsFeed(RssSiteNewsFeed):
feed_type = Atom1Feed
@@ -370,8 +376,8 @@ And the accompanying URLconf::
urlpatterns = [
# ...
- path('sitenews/rss/', RssSiteNewsFeed()),
- path('sitenews/atom/', AtomSiteNewsFeed()),
+ path("sitenews/rss/", RssSiteNewsFeed()),
+ path("sitenews/atom/", AtomSiteNewsFeed()),
# ...
]
@@ -386,8 +392,8 @@ This example illustrates all possible attributes and methods for a
from django.contrib.syndication.views import Feed
from django.utils import feedgenerator
- class ExampleFeed(Feed):
+ class ExampleFeed(Feed):
# FEED TYPE -- Optional. This should be a class that subclasses
# django.utils.feedgenerator.SyndicationFeed. This designates
# which type of feed this should be: RSS 2.0, Atom 1.0, etc. If
@@ -407,7 +413,7 @@ This example illustrates all possible attributes and methods for a
# LANGUAGE -- Optional. This should be a string specifying a language
# code. Defaults to django.utils.translation.get_language().
- language = 'de'
+ language = "de"
# TITLE -- One of the following three is required. The framework
# looks for them in this order.
@@ -423,7 +429,7 @@ This example illustrates all possible attributes and methods for a
Returns the feed's title as a normal Python string.
"""
- title = 'foo' # Hard-coded title.
+ title = "foo" # Hard-coded title.
# LINK -- One of the following three is required. The framework
# looks for them in this order.
@@ -440,7 +446,7 @@ This example illustrates all possible attributes and methods for a
string.
"""
- link = '/blog/' # Hard-coded URL.
+ link = "/blog/" # Hard-coded URL.
# FEED_URL -- One of the following three is optional. The framework
# looks for them in this order.
@@ -456,7 +462,7 @@ This example illustrates all possible attributes and methods for a
Returns the feed's own URL as a normal Python string.
"""
- feed_url = '/blog/rss/' # Hard-coded URL.
+ feed_url = "/blog/rss/" # Hard-coded URL.
# GUID -- One of the following three is optional. The framework looks
# for them in this order. This property is only used for Atom feeds
@@ -474,7 +480,7 @@ This example illustrates all possible attributes and methods for a
Returns the feed's globally unique ID as a normal Python string.
"""
- feed_guid = '/foo/bar/1234' # Hard-coded guid.
+ feed_guid = "/foo/bar/1234" # Hard-coded guid.
# DESCRIPTION -- One of the following three is required. The framework
# looks for them in this order.
@@ -490,7 +496,7 @@ This example illustrates all possible attributes and methods for a
Returns the feed's description as a normal Python string.
"""
- description = 'Foo bar baz.' # Hard-coded description.
+ description = "Foo bar baz." # Hard-coded description.
# AUTHOR NAME --One of the following three is optional. The framework
# looks for them in this order.
@@ -506,7 +512,7 @@ This example illustrates all possible attributes and methods for a
Returns the feed's author's name as a normal Python string.
"""
- author_name = 'Sally Smith' # Hard-coded author name.
+ author_name = "Sally Smith" # Hard-coded author name.
# AUTHOR EMAIL --One of the following three is optional. The framework
# looks for them in this order.
@@ -522,7 +528,7 @@ This example illustrates all possible attributes and methods for a
Returns the feed's author's email as a normal Python string.
"""
- author_email = 'test@example.com' # Hard-coded author email.
+ author_email = "test@example.com" # Hard-coded author email.
# AUTHOR LINK --One of the following three is optional. The framework
# looks for them in this order. In each case, the URL should include
@@ -539,7 +545,7 @@ This example illustrates all possible attributes and methods for a
Returns the feed's author's URL as a normal Python string.
"""
- author_link = 'https://www.example.com/' # Hard-coded author URL.
+ author_link = "https://www.example.com/" # Hard-coded author URL.
# CATEGORIES -- One of the following three is optional. The framework
# looks for them in this order. In each case, the method/attribute
@@ -556,7 +562,7 @@ This example illustrates all possible attributes and methods for a
Returns the feed's categories as iterable over strings.
"""
- categories = ["python", "django"] # Hard-coded list of categories.
+ categories = ["python", "django"] # Hard-coded list of categories.
# COPYRIGHT NOTICE -- One of the following three is optional. The
# framework looks for them in this order.
@@ -572,7 +578,7 @@ This example illustrates all possible attributes and methods for a
Returns the feed's copyright notice as a normal Python string.
"""
- feed_copyright = 'Copyright (c) 2007, Sally Smith' # Hard-coded copyright notice.
+ feed_copyright = "Copyright (c) 2007, Sally Smith" # Hard-coded copyright notice.
# TTL -- One of the following three is optional. The framework looks
# for them in this order. Ignored for Atom feeds.
@@ -588,7 +594,7 @@ This example illustrates all possible attributes and methods for a
Returns the feed's TTL as a normal Python string.
"""
- ttl = 600 # Hard-coded Time To Live.
+ ttl = 600 # Hard-coded Time To Live.
# ITEMS -- One of the following three is required. The framework looks
# for them in this order.
@@ -604,7 +610,7 @@ This example illustrates all possible attributes and methods for a
Returns a list of items to publish in this feed.
"""
- items = ['Item 1', 'Item 2'] # Hard-coded items.
+ items = ["Item 1", "Item 2"] # Hard-coded items.
# GET_OBJECT -- This is required for feeds that publish different data
# for different URL parameters. (See "A complex example" above.)
@@ -632,7 +638,7 @@ This example illustrates all possible attributes and methods for a
Returns the title for every item in the feed.
"""
- item_title = 'Breaking News: Nothing Happening' # Hard-coded title.
+ item_title = "Breaking News: Nothing Happening" # Hard-coded title.
def item_description(self, item):
"""
@@ -645,7 +651,7 @@ This example illustrates all possible attributes and methods for a
Returns the description for every item in the feed.
"""
- item_description = 'A description of the item.' # Hard-coded description.
+ item_description = "A description of the item." # Hard-coded description.
def get_context_data(self, **kwargs):
"""
@@ -707,7 +713,7 @@ This example illustrates all possible attributes and methods for a
Returns the author name for every item in the feed.
"""
- item_author_name = 'Sally Smith' # Hard-coded author name.
+ item_author_name = "Sally Smith" # Hard-coded author name.
# ITEM AUTHOR EMAIL --One of the following three is optional. The
# framework looks for them in this order.
@@ -725,7 +731,7 @@ This example illustrates all possible attributes and methods for a
Returns the author email for every item in the feed.
"""
- item_author_email = 'test@example.com' # Hard-coded author email.
+ item_author_email = "test@example.com" # Hard-coded author email.
# ITEM AUTHOR LINK -- One of the following three is optional. The
# framework looks for them in this order. In each case, the URL should
@@ -744,7 +750,7 @@ This example illustrates all possible attributes and methods for a
Returns the author URL for every item in the feed.
"""
- item_author_link = 'https://www.example.com/' # Hard-coded author URL.
+ item_author_link = "https://www.example.com/" # Hard-coded author URL.
# ITEM ENCLOSURES -- One of the following three is optional. The
# framework looks for them in this order. If one of them is defined,
@@ -780,7 +786,7 @@ This example illustrates all possible attributes and methods for a
Returns the enclosure URL for every item in the feed.
"""
- item_enclosure_url = "/foo/bar.mp3" # Hard-coded enclosure link.
+ item_enclosure_url = "/foo/bar.mp3" # Hard-coded enclosure link.
# ITEM ENCLOSURE LENGTH -- One of these three is required if you're
# publishing enclosures and you're not using ``item_enclosures``. The
@@ -799,7 +805,7 @@ This example illustrates all possible attributes and methods for a
Returns the enclosure length for every item in the feed.
"""
- item_enclosure_length = 32000 # Hard-coded enclosure length.
+ item_enclosure_length = 32000 # Hard-coded enclosure length.
# ITEM ENCLOSURE MIME TYPE -- One of these three is required if you're
# publishing enclosures and you're not using ``item_enclosures``. The
@@ -816,7 +822,7 @@ This example illustrates all possible attributes and methods for a
Returns the enclosure MIME type for every item in the feed.
"""
- item_enclosure_mime_type = "audio/mpeg" # Hard-coded enclosure MIME type.
+ item_enclosure_mime_type = "audio/mpeg" # Hard-coded enclosure MIME type.
# ITEM PUBDATE -- It's optional to use one of these three. This is a
# hook that specifies how to get the pubdate for a given item.
@@ -834,7 +840,7 @@ This example illustrates all possible attributes and methods for a
Returns the pubdate for every item in the feed.
"""
- item_pubdate = datetime.datetime(2005, 5, 3) # Hard-coded pubdate.
+ item_pubdate = datetime.datetime(2005, 5, 3) # Hard-coded pubdate.
# ITEM UPDATED -- It's optional to use one of these three. This is a
# hook that specifies how to get the updateddate for a given item.
@@ -852,7 +858,7 @@ This example illustrates all possible attributes and methods for a
Returns the updateddate for every item in the feed.
"""
- item_updateddate = datetime.datetime(2005, 5, 3) # Hard-coded updateddate.
+ item_updateddate = datetime.datetime(2005, 5, 3) # Hard-coded updateddate.
# ITEM CATEGORIES -- It's optional to use one of these three. This is
# a hook that specifies how to get the list of categories for a given
@@ -870,7 +876,7 @@ This example illustrates all possible attributes and methods for a
Returns the categories for every item in the feed.
"""
- item_categories = ["python", "django"] # Hard-coded categories.
+ item_categories = ["python", "django"] # Hard-coded categories.
# ITEM COPYRIGHT NOTICE (only applicable to Atom feeds) -- One of the
# following three is optional. The framework looks for them in this
@@ -887,7 +893,7 @@ This example illustrates all possible attributes and methods for a
Returns the copyright notice for every item in the feed.
"""
- item_copyright = 'Copyright (c) 2007, Sally Smith' # Hard-coded copyright notice.
+ item_copyright = "Copyright (c) 2007, Sally Smith" # Hard-coded copyright notice.
# ITEM COMMENTS URL -- It's optional to use one of these three. This is
# a hook that specifies how to get the URL of a page for comments for a
@@ -904,7 +910,7 @@ This example illustrates all possible attributes and methods for a
Returns the comments URL for every item in the feed.
"""
- item_comments = 'https://www.example.com/comments' # Hard-coded comments URL
+ item_comments = "https://www.example.com/comments" # Hard-coded comments URL
The low-level framework
=======================
@@ -1016,12 +1022,15 @@ For example, to create an Atom 1.0 feed and print it to standard output:
... description="In which I write about what I ate today.",
... language="en",
... author_name="Myself",
- ... feed_url="https://example.com/atom.xml")
- >>> f.add_item(title="Hot dog today",
+ ... feed_url="https://example.com/atom.xml",
+ ... )
+ >>> f.add_item(
+ ... title="Hot dog today",
... link="https://www.example.com/entries/1/",
... pubdate=datetime.now(),
- ... description="<p>Today I had a Vienna Beef hot dog. It was pink, plump and perfect.</p>")
- >>> print(f.writeString('UTF-8'))
+ ... description="<p>Today I had a Vienna Beef hot dog. It was pink, plump and perfect.</p>",
+ ... )
+ >>> print(f.writeString("UTF-8"))
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
...
@@ -1077,12 +1086,12 @@ For example, you might start implementing an iTunes RSS feed generator like so::
class iTunesFeed(Rss201rev2Feed):
def root_attributes(self):
attrs = super().root_attributes()
- attrs['xmlns:itunes'] = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
+ attrs["xmlns:itunes"] = "http://www.itunes.com/dtds/podcast-1.0.dtd"
return attrs
def add_root_elements(self, handler):
super().add_root_elements(handler)
- handler.addQuickElement('itunes:explicit', 'clean')
+ handler.addQuickElement("itunes:explicit", "clean")
There's a lot more work to be done for a complete custom feed class, but the
above example should demonstrate the basic idea.
diff --git a/docs/ref/csrf.txt b/docs/ref/csrf.txt
index 008e81f403..583f78472c 100644
--- a/docs/ref/csrf.txt
+++ b/docs/ref/csrf.txt
@@ -145,9 +145,10 @@ class-based views<decorating-class-based-views>`.
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
+
@csrf_exempt
def my_view(request):
- return HttpResponse('Hello world')
+ return HttpResponse("Hello world")
.. function:: csrf_protect(view)
@@ -158,6 +159,7 @@ class-based views<decorating-class-based-views>`.
from django.shortcuts import render
from django.views.decorators.csrf import csrf_protect
+
@csrf_protect
def my_view(request):
c = {}
@@ -177,6 +179,7 @@ class-based views<decorating-class-based-views>`.
from django.shortcuts import render
from django.views.decorators.csrf import requires_csrf_token
+
@requires_csrf_token
def my_view(request):
c = {}
diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt
index 2fc5edb9f8..928511d979 100644
--- a/docs/ref/databases.txt
+++ b/docs/ref/databases.txt
@@ -137,11 +137,11 @@ password from the `password file`_, you must specify them in the
:caption: ``settings.py``
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql',
- 'OPTIONS': {
- 'service': 'my_service',
- 'passfile': '.my_pgpass',
+ "default": {
+ "ENGINE": "django.db.backends.postgresql",
+ "OPTIONS": {
+ "service": "my_service",
+ "passfile": ".my_pgpass",
},
}
}
@@ -206,8 +206,8 @@ configuration in :setting:`DATABASES`::
DATABASES = {
# ...
- 'OPTIONS': {
- 'isolation_level': IsolationLevel.SERIALIZABLE,
+ "OPTIONS": {
+ "isolation_level": IsolationLevel.SERIALIZABLE,
},
}
@@ -353,11 +353,10 @@ cause a conflict. For example:
.. code-block:: pycon
>>> from django.contrib.auth.models import User
- >>> User.objects.create(username='alice', pk=1)
+ >>> User.objects.create(username="alice", pk=1)
<User: alice>
>>> # The sequence hasn't been updated; its next value is 1.
- >>> User.objects.create(username='bob')
- ...
+ >>> User.objects.create(username="bob")
IntegrityError: duplicate key value violates unique constraint
"auth_user_pkey" DETAIL: Key (id)=(1) already exists.
@@ -567,10 +566,10 @@ Here's a sample configuration which uses a MySQL option file::
# settings.py
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.mysql',
- 'OPTIONS': {
- 'read_default_file': '/path/to/my.cnf',
+ "default": {
+ "ENGINE": "django.db.backends.mysql",
+ "OPTIONS": {
+ "read_default_file": "/path/to/my.cnf",
},
}
}
@@ -657,8 +656,8 @@ storage engine, you have a couple of options.
* Another option is to use the ``init_command`` option for MySQLdb prior to
creating your tables::
- 'OPTIONS': {
- 'init_command': 'SET default_storage_engine=INNODB',
+ "OPTIONS": {
+ "init_command": "SET default_storage_engine=INNODB",
}
This sets the default storage engine upon connecting to the database.
@@ -864,9 +863,9 @@ If you're getting this error, you can solve it by:
* Increase the default timeout value by setting the ``timeout`` database
option::
- 'OPTIONS': {
+ "OPTIONS": {
# ...
- 'timeout': 20,
+ "timeout": 20,
# ...
}
@@ -976,13 +975,13 @@ To connect using the service name of your Oracle database, your ``settings.py``
file should look something like this::
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.oracle',
- 'NAME': 'xe',
- 'USER': 'a_user',
- 'PASSWORD': 'a_password',
- 'HOST': '',
- 'PORT': '',
+ "default": {
+ "ENGINE": "django.db.backends.oracle",
+ "NAME": "xe",
+ "USER": "a_user",
+ "PASSWORD": "a_password",
+ "HOST": "",
+ "PORT": "",
}
}
@@ -993,13 +992,13 @@ and want to connect using the SID ("xe" in this example), then fill in both
:setting:`HOST` and :setting:`PORT` like so::
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.oracle',
- 'NAME': 'xe',
- 'USER': 'a_user',
- 'PASSWORD': 'a_password',
- 'HOST': 'dbprod01ned.mycompany.com',
- 'PORT': '1540',
+ "default": {
+ "ENGINE": "django.db.backends.oracle",
+ "NAME": "xe",
+ "USER": "a_user",
+ "PASSWORD": "a_password",
+ "HOST": "dbprod01ned.mycompany.com",
+ "PORT": "1540",
}
}
@@ -1016,13 +1015,13 @@ using RAC or pluggable databases without ``tnsnames.ora``, for example.
Example of an Easy Connect string::
- 'NAME': 'localhost:1521/orclpdb1'
+ "NAME": "localhost:1521/orclpdb1"
Example of a full DSN string::
- 'NAME': (
- '(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))'
- '(CONNECT_DATA=(SERVICE_NAME=orclpdb1)))'
+ "NAME": (
+ "(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))"
+ "(CONNECT_DATA=(SERVICE_NAME=orclpdb1)))"
)
Threaded option
@@ -1032,8 +1031,8 @@ If you plan to run Django in a multithreaded environment (e.g. Apache using the
default MPM module on any modern operating system), then you **must** set
the ``threaded`` option of your Oracle database configuration to ``True``::
- 'OPTIONS': {
- 'threaded': True,
+ "OPTIONS": {
+ "threaded": True,
}
Failure to do this may result in crashes and other odd behavior.
@@ -1048,8 +1047,8 @@ inserting into a remote table, or into a view with an ``INSTEAD OF`` trigger.
The ``RETURNING INTO`` clause can be disabled by setting the
``use_returning_into`` option of the database configuration to ``False``::
- 'OPTIONS': {
- 'use_returning_into': False,
+ "OPTIONS": {
+ "use_returning_into": False,
}
In this case, the Oracle backend will use a separate ``SELECT`` query to
@@ -1071,6 +1070,7 @@ a quoted name as the value for ``db_table``::
class Meta:
db_table = '"name_left_in_lowercase"'
+
class ForeignModel(models.Model):
class Meta:
db_table = '"OTHER_USER"."NAME_ONLY_SEEMS_OVER_30"'
@@ -1146,10 +1146,12 @@ example of subclassing the PostgreSQL engine to change a feature class
from django.db.backends.postgresql import base, features
+
class DatabaseFeatures(features.DatabaseFeatures):
def allows_group_by_selected_pks_on_model(self, model):
return True
+
class DatabaseWrapper(base.DatabaseWrapper):
features_class = DatabaseFeatures
@@ -1157,8 +1159,8 @@ Finally, you must specify a :setting:`DATABASE-ENGINE` in your ``settings.py``
file::
DATABASES = {
- 'default': {
- 'ENGINE': 'mydbengine',
+ "default": {
+ "ENGINE": "mydbengine",
# ...
},
}
diff --git a/docs/ref/django-admin.txt b/docs/ref/django-admin.txt
index 3a766d748a..56e29861ee 100644
--- a/docs/ref/django-admin.txt
+++ b/docs/ref/django-admin.txt
@@ -2097,9 +2097,9 @@ Examples::
from django.core import management
from django.core.management.commands import loaddata
- management.call_command('flush', verbosity=0, interactive=False)
- management.call_command('loaddata', 'test_data', verbosity=0)
- management.call_command(loaddata.Command(), 'test_data', verbosity=0)
+ management.call_command("flush", verbosity=0, interactive=False)
+ management.call_command("loaddata", "test_data", verbosity=0)
+ management.call_command(loaddata.Command(), "test_data", verbosity=0)
Note that command options that take no arguments are passed as keywords
with ``True`` or ``False``, as you can see with the ``interactive`` option above.
@@ -2107,14 +2107,14 @@ with ``True`` or ``False``, as you can see with the ``interactive`` option above
Named arguments can be passed by using either one of the following syntaxes::
# Similar to the command line
- management.call_command('dumpdata', '--natural-foreign')
+ management.call_command("dumpdata", "--natural-foreign")
# Named argument similar to the command line minus the initial dashes and
# with internal dashes replaced by underscores
- management.call_command('dumpdata', natural_foreign=True)
+ management.call_command("dumpdata", natural_foreign=True)
# `use_natural_foreign_keys` is the option destination variable
- management.call_command('dumpdata', use_natural_foreign_keys=True)
+ management.call_command("dumpdata", use_natural_foreign_keys=True)
Some command options have different names when using ``call_command()`` instead
of ``django-admin`` or ``manage.py``. For example, ``django-admin
@@ -2125,7 +2125,7 @@ passed to ``parser.add_argument()``.
Command options which take multiple options are passed a list::
- management.call_command('dumpdata', exclude=['contenttypes', 'auth'])
+ management.call_command("dumpdata", exclude=["contenttypes", "auth"])
The return value of the ``call_command()`` function is the same as the return
value of the ``handle()`` method of the command.
@@ -2136,5 +2136,5 @@ Output redirection
Note that you can redirect standard output and error streams as all commands
support the ``stdout`` and ``stderr`` options. For example, you could write::
- with open('/path/to/command_output', 'w') as f:
- management.call_command('dumpdata', stdout=f)
+ with open("/path/to/command_output", "w") as f:
+ management.call_command("dumpdata", stdout=f)
diff --git a/docs/ref/files/file.txt b/docs/ref/files/file.txt
index 253e3d2903..f5c1b10917 100644
--- a/docs/ref/files/file.txt
+++ b/docs/ref/files/file.txt
@@ -139,14 +139,14 @@ below) will also have a couple of extra methods:
.. code-block:: pycon
- >>> car.photo.save('myphoto.jpg', content, save=False)
+ >>> car.photo.save("myphoto.jpg", content, save=False)
>>> car.save()
are equivalent to:
.. code-block:: pycon
- >>> car.photo.save('myphoto.jpg', content, save=True)
+ >>> car.photo.save("myphoto.jpg", content, save=True)
Note that the ``content`` argument must be an instance of either
:class:`File` or of a subclass of :class:`File`, such as
diff --git a/docs/ref/forms/api.txt b/docs/ref/forms/api.txt
index f648ee7ec4..12754dbae5 100644
--- a/docs/ref/forms/api.txt
+++ b/docs/ref/forms/api.txt
@@ -36,10 +36,12 @@ your :class:`Form` class constructor:
.. code-block:: pycon
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True}
+ >>> data = {
+ ... "subject": "hello",
+ ... "message": "Hi there",
+ ... "sender": "foo@example.com",
+ ... "cc_myself": True,
+ ... }
>>> f = ContactForm(data)
In this dictionary, the keys are the field names, which correspond to the
@@ -58,7 +60,7 @@ check the value of the form's :attr:`~Form.is_bound` attribute:
>>> f = ContactForm()
>>> f.is_bound
False
- >>> f = ContactForm({'subject': 'hello'})
+ >>> f = ContactForm({"subject": "hello"})
>>> f.is_bound
True
@@ -93,10 +95,12 @@ and return a boolean designating whether the data was valid:
.. code-block:: pycon
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True}
+ >>> data = {
+ ... "subject": "hello",
+ ... "message": "Hi there",
+ ... "sender": "foo@example.com",
+ ... "cc_myself": True,
+ ... }
>>> f = ContactForm(data)
>>> f.is_valid()
True
@@ -107,10 +111,12 @@ email address:
.. code-block:: pycon
- >>> data = {'subject': '',
- ... 'message': 'Hi there',
- ... 'sender': 'invalid email address',
- ... 'cc_myself': True}
+ >>> data = {
+ ... "subject": "",
+ ... "message": "Hi there",
+ ... "sender": "invalid email address",
+ ... "cc_myself": True,
+ ... }
>>> f = ContactForm(data)
>>> f.is_valid()
False
@@ -256,7 +262,7 @@ it's not necessary to include every field in your form. For example:
.. code-block:: pycon
- >>> f = ContactForm(initial={'subject': 'Hi there!'})
+ >>> f = ContactForm(initial={"subject": "Hi there!"})
These values are only displayed for unbound forms, and they're not used as
fallback values if a particular value isn't provided.
@@ -271,10 +277,11 @@ precedence:
>>> from django import forms
>>> class CommentForm(forms.Form):
- ... name = forms.CharField(initial='class')
+ ... name = forms.CharField(initial="class")
... url = forms.URLField()
... comment = forms.CharField()
- >>> f = CommentForm(initial={'name': 'instance'}, auto_id=False)
+ ...
+ >>> f = CommentForm(initial={"name": "instance"}, auto_id=False)
>>> print(f)
<div>Name:<input type="text" name="name" value="instance" required></div>
<div>Url:<input type="url" name="url" required></div>
@@ -298,15 +305,16 @@ dealing with callables whose return values can change (e.g. ``datetime.now`` or
>>> import uuid
>>> class UUIDCommentForm(CommentForm):
... identifier = forms.UUIDField(initial=uuid.uuid4)
+ ...
>>> f = UUIDCommentForm()
- >>> f.get_initial_for_field(f.fields['identifier'], 'identifier')
+ >>> f.get_initial_for_field(f.fields["identifier"], "identifier")
UUID('972ca9e4-7bfe-4f5b-af7d-07b3aa306334')
- >>> f.get_initial_for_field(f.fields['identifier'], 'identifier')
+ >>> f.get_initial_for_field(f.fields["identifier"], "identifier")
UUID('1b411fab-844e-4dec-bd4f-e9b0495f04d0')
>>> # Using BoundField.initial, for comparison
- >>> f['identifier'].initial
+ >>> f["identifier"].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
- >>> f['identifier'].initial
+ >>> f["identifier"].initial
UUID('28a09c59-5f00-4ed9-9179-a3b074fa9c30')
Checking which form data has changed
@@ -358,12 +366,13 @@ attribute:
.. code-block:: pycon
- >>> for row in f.fields.values(): print(row)
+ >>> for row in f.fields.values():
+ ... print(row)
...
<django.forms.fields.CharField object at 0x7ffaac632510>
<django.forms.fields.URLField object at 0x7ffaac632f90>
<django.forms.fields.CharField object at 0x7ffaac3aa050>
- >>> f.fields['name']
+ >>> f.fields["name"]
<django.forms.fields.CharField object at 0x7ffaac6324d0>
You can alter the field and :class:`.BoundField` of :class:`Form` instance to
@@ -409,10 +418,12 @@ it, you can access the clean data via its ``cleaned_data`` attribute:
.. code-block:: pycon
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True}
+ >>> data = {
+ ... "subject": "hello",
+ ... "message": "Hi there",
+ ... "sender": "foo@example.com",
+ ... "cc_myself": True,
+ ... }
>>> f = ContactForm(data)
>>> f.is_valid()
True
@@ -428,10 +439,12 @@ only the valid fields:
.. code-block:: pycon
- >>> data = {'subject': '',
- ... 'message': 'Hi there',
- ... 'sender': 'invalid email address',
- ... 'cc_myself': True}
+ >>> data = {
+ ... "subject": "",
+ ... "message": "Hi there",
+ ... "sender": "invalid email address",
+ ... "cc_myself": True,
+ ... }
>>> f = ContactForm(data)
>>> f.is_valid()
False
@@ -445,17 +458,19 @@ but ``cleaned_data`` contains only the form's fields:
.. code-block:: pycon
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True,
- ... 'extra_field_1': 'foo',
- ... 'extra_field_2': 'bar',
- ... 'extra_field_3': 'baz'}
+ >>> data = {
+ ... "subject": "hello",
+ ... "message": "Hi there",
+ ... "sender": "foo@example.com",
+ ... "cc_myself": True,
+ ... "extra_field_1": "foo",
+ ... "extra_field_2": "bar",
+ ... "extra_field_3": "baz",
+ ... }
>>> f = ContactForm(data)
>>> f.is_valid()
True
- >>> f.cleaned_data # Doesn't contain extra_field_1, etc.
+ >>> f.cleaned_data # Doesn't contain extra_field_1, etc.
{'cc_myself': True, 'message': 'Hi there', 'sender': 'foo@example.com', 'subject': 'hello'}
When the ``Form`` is valid, ``cleaned_data`` will include a key and value for
@@ -470,7 +485,8 @@ fields. In this example, the data dictionary doesn't include a value for the
... first_name = forms.CharField()
... last_name = forms.CharField()
... nick_name = forms.CharField(required=False)
- >>> data = {'first_name': 'John', 'last_name': 'Lennon'}
+ ...
+ >>> data = {"first_name": "John", "last_name": "Lennon"}
>>> f = OptionalPersonForm(data)
>>> f.is_valid()
True
@@ -513,10 +529,12 @@ include ``checked`` if appropriate:
.. code-block:: pycon
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True}
+ >>> data = {
+ ... "subject": "hello",
+ ... "message": "Hi there",
+ ... "sender": "foo@example.com",
+ ... "cc_myself": True,
+ ... }
>>> f = ContactForm(data)
>>> print(f)
<div><label for="id_subject">Subject:</label><input type="text" name="subject" value="hello" maxlength="100" required id="id_subject"></div>
@@ -764,9 +782,10 @@ attributes::
from django import forms
+
class ContactForm(forms.Form):
- error_css_class = 'error'
- required_css_class = 'required'
+ error_css_class = "error"
+ required_css_class = "required"
# ... and the rest of your fields here
@@ -781,13 +800,13 @@ classes, as needed. The HTML will look something like:
<div class="required"><label for="id_message" class="required">Message:</label> ...
<div class="required"><label for="id_sender" class="required">Sender:</label> ...
<div><label for="id_cc_myself">Cc myself:</label> ...
- >>> f['subject'].label_tag()
+ >>> f["subject"].label_tag()
<label class="required" for="id_subject">Subject:</label>
- >>> f['subject'].legend_tag()
+ >>> f["subject"].legend_tag()
<legend class="required" for="id_subject">Subject:</legend>
- >>> f['subject'].label_tag(attrs={'class': 'foo'})
+ >>> f["subject"].label_tag(attrs={"class": "foo"})
<label for="id_subject" class="foo required">Subject:</label>
- >>> f['subject'].legend_tag(attrs={'class': 'foo'})
+ >>> f["subject"].legend_tag(attrs={"class": "foo"})
<legend for="id_subject" class="foo required">Subject:</legend>
.. _ref-forms-api-configuring-label:
@@ -847,7 +866,7 @@ attributes based on the format string. For example, for a format string
.. code-block:: pycon
- >>> f = ContactForm(auto_id='id_for_%s')
+ >>> f = ContactForm(auto_id="id_for_%s")
>>> print(f)
<div><label for="id_for_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message:</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
@@ -869,13 +888,13 @@ It's possible to customize that character, or omit it entirely, using the
.. code-block:: pycon
- >>> f = ContactForm(auto_id='id_for_%s', label_suffix='')
+ >>> f = ContactForm(auto_id="id_for_%s", label_suffix="")
>>> print(f)
<div><label for="id_for_subject">Subject</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
<div><label for="id_for_sender">Sender</label><input type="email" name="sender" required id="id_for_sender"></div>
<div><label for="id_for_cc_myself">Cc myself</label><input type="checkbox" name="cc_myself" id="id_for_cc_myself"></div>
- >>> f = ContactForm(auto_id='id_for_%s', label_suffix=' ->')
+ >>> f = ContactForm(auto_id="id_for_%s", label_suffix=" ->")
>>> print(f)
<div><label for="id_for_subject">Subject:</label><input type="text" name="subject" maxlength="100" required id="id_for_subject"></div>
<div><label for="id_for_message">Message -&gt;</label><textarea name="message" cols="40" rows="10" required id="id_for_message"></textarea></div>
@@ -916,6 +935,7 @@ You can set this as a class attribute when declaring your form or use the
from django import forms
+
class MyForm(forms.Form):
default_renderer = MyRenderer()
@@ -964,10 +984,12 @@ method you're using:
.. code-block:: pycon
- >>> data = {'subject': '',
- ... 'message': 'Hi there',
- ... 'sender': 'invalid email address',
- ... 'cc_myself': True}
+ >>> data = {
+ ... "subject": "",
+ ... "message": "Hi there",
+ ... "sender": "invalid email address",
+ ... "cc_myself": True,
+ ... }
>>> f = ContactForm(data, auto_id=False)
>>> print(f)
<div>Subject:<ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="subject" maxlength="100" required></div>
@@ -1072,7 +1094,7 @@ using the field's name as the key:
.. code-block:: pycon
>>> form = ContactForm()
- >>> print(form['subject'])
+ >>> print(form["subject"])
<input id="id_subject" type="text" name="subject" maxlength="100" required>
To retrieve all ``BoundField`` objects, iterate the form:
@@ -1080,7 +1102,9 @@ To retrieve all ``BoundField`` objects, iterate the form:
.. code-block:: pycon
>>> form = ContactForm()
- >>> for boundfield in form: print(boundfield)
+ >>> for boundfield in form:
+ ... print(boundfield)
+ ...
<input id="id_subject" type="text" name="subject" maxlength="100" required>
<input type="text" name="message" id="id_message" required>
<input type="email" name="sender" id="id_sender" required>
@@ -1091,10 +1115,10 @@ The field-specific output honors the form object's ``auto_id`` setting:
.. code-block:: pycon
>>> f = ContactForm(auto_id=False)
- >>> print(f['message'])
+ >>> print(f["message"])
<input type="text" name="message" required>
- >>> f = ContactForm(auto_id='id_%s')
- >>> print(f['message'])
+ >>> f = ContactForm(auto_id="id_%s")
+ >>> print(f["message"])
<input type="text" name="message" id="id_message" required>
Attributes of ``BoundField``
@@ -1114,10 +1138,10 @@ Attributes of ``BoundField``
.. code-block:: pycon
>>> unbound_form = ContactForm()
- >>> print(unbound_form['subject'].data)
+ >>> print(unbound_form["subject"].data)
None
- >>> bound_form = ContactForm(data={'subject': 'My Subject'})
- >>> print(bound_form['subject'].data)
+ >>> bound_form = ContactForm(data={"subject": "My Subject"})
+ >>> print(bound_form["subject"].data)
My Subject
.. attribute:: BoundField.errors
@@ -1127,19 +1151,19 @@ Attributes of ``BoundField``
.. code-block:: pycon
- >>> data = {'subject': 'hi', 'message': '', 'sender': '', 'cc_myself': ''}
+ >>> data = {"subject": "hi", "message": "", "sender": "", "cc_myself": ""}
>>> f = ContactForm(data, auto_id=False)
- >>> print(f['message'])
+ >>> print(f["message"])
<input type="text" name="message" required>
- >>> f['message'].errors
+ >>> f["message"].errors
['This field is required.']
- >>> print(f['message'].errors)
+ >>> print(f["message"].errors)
<ul class="errorlist"><li>This field is required.</li></ul>
- >>> f['subject'].errors
+ >>> f["subject"].errors
[]
- >>> print(f['subject'].errors)
+ >>> print(f["subject"].errors)
- >>> str(f['subject'].errors)
+ >>> str(f["subject"].errors)
''
.. attribute:: BoundField.field
@@ -1177,7 +1201,7 @@ Attributes of ``BoundField``
:attr:`~django.forms.Widget.attrs` on the field's widget. For example,
declaring a field like this::
- my_field = forms.CharField(widget=forms.TextInput(attrs={'id': 'myFIELD'}))
+ my_field = forms.CharField(widget=forms.TextInput(attrs={"id": "myFIELD"}))
and using the template above, would render something like:
@@ -1201,10 +1225,11 @@ Attributes of ``BoundField``
>>> from datetime import datetime
>>> class DatedCommentForm(CommentForm):
... created = forms.DateTimeField(initial=datetime.now)
+ ...
>>> f = DatedCommentForm()
- >>> f['created'].initial
+ >>> f["created"].initial
datetime.datetime(2021, 7, 27, 9, 5, 54)
- >>> f['created'].initial
+ >>> f["created"].initial
datetime.datetime(2021, 7, 27, 9, 5, 54)
Using :attr:`BoundField.initial` is recommended over
@@ -1227,9 +1252,9 @@ Attributes of ``BoundField``
.. code-block:: pycon
>>> f = ContactForm()
- >>> print(f['subject'].name)
+ >>> print(f["subject"].name)
subject
- >>> print(f['message'].name)
+ >>> print(f["message"].name)
message
.. attribute:: BoundField.use_fieldset
@@ -1282,8 +1307,8 @@ Methods of ``BoundField``
.. code-block:: pycon
- >>> f = ContactForm(data={'message': ''})
- >>> f['message'].css_classes()
+ >>> f = ContactForm(data={"message": ""})
+ >>> f["message"].css_classes()
'required'
If you want to provide some additional classes in addition to the
@@ -1292,8 +1317,8 @@ Methods of ``BoundField``
.. code-block:: pycon
- >>> f = ContactForm(data={'message': ''})
- >>> f['message'].css_classes('foo bar')
+ >>> f = ContactForm(data={"message": ""})
+ >>> f["message"].css_classes("foo bar")
'foo bar required'
.. method:: BoundField.label_tag(contents=None, attrs=None, label_suffix=None, tag=None)
@@ -1327,8 +1352,8 @@ Methods of ``BoundField``
.. code-block:: pycon
- >>> f = ContactForm(data={'message': ''})
- >>> print(f['message'].label_tag())
+ >>> f = ContactForm(data={"message": ""})
+ >>> print(f["message"].label_tag())
<label for="id_message">Message:</label>
If you'd like to customize the rendering this can be achieved by overriding
@@ -1350,12 +1375,12 @@ Methods of ``BoundField``
.. code-block:: pycon
- >>> initial = {'subject': 'welcome'}
+ >>> initial = {"subject": "welcome"}
>>> unbound_form = ContactForm(initial=initial)
- >>> bound_form = ContactForm(data={'subject': 'hi'}, initial=initial)
- >>> print(unbound_form['subject'].value())
+ >>> bound_form = ContactForm(data={"subject": "hi"}, initial=initial)
+ >>> print(unbound_form["subject"].value())
welcome
- >>> print(bound_form['subject'].value())
+ >>> print(bound_form["subject"].value())
hi
Customizing ``BoundField``
@@ -1391,6 +1416,7 @@ be implemented as follows::
else:
return None
+
class GPSCoordinatesField(Field):
def get_bound_field(self, form, field_name):
return GPSCoordinatesBoundField(form, self, field_name)
@@ -1425,11 +1451,13 @@ need to bind the file data containing the mugshot image:
# Bound form with an image field
>>> from django.core.files.uploadedfile import SimpleUploadedFile
- >>> data = {'subject': 'hello',
- ... 'message': 'Hi there',
- ... 'sender': 'foo@example.com',
- ... 'cc_myself': True}
- >>> file_data = {'mugshot': SimpleUploadedFile('face.jpg', b"file data")}
+ >>> data = {
+ ... "subject": "hello",
+ ... "message": "Hi there",
+ ... "sender": "foo@example.com",
+ ... "cc_myself": True,
+ ... }
+ >>> file_data = {"mugshot": SimpleUploadedFile("face.jpg", b"file data")}
>>> f = ContactFormWithMugshot(data, file_data)
In practice, you will usually specify ``request.FILES`` as the source
@@ -1494,6 +1522,7 @@ fields are ordered first:
>>> class ContactFormWithPriority(ContactForm):
... priority = forms.CharField()
+ ...
>>> f = ContactFormWithPriority(auto_id=False)
>>> print(f)
<div>Subject:<input type="text" name="subject" maxlength="100" required></div>
@@ -1513,10 +1542,13 @@ classes:
>>> class PersonForm(forms.Form):
... first_name = forms.CharField()
... last_name = forms.CharField()
+ ...
>>> class InstrumentForm(forms.Form):
... instrument = forms.CharField()
+ ...
>>> class BeatleForm(InstrumentForm, PersonForm):
... haircut_type = forms.CharField()
+ ...
>>> b = BeatleForm(auto_id=False)
>>> print(b)
<div>First name:<input type="text" name="first_name" required></div>
@@ -1534,9 +1566,11 @@ by setting the name of the field to ``None`` on the subclass. For example:
>>> class ParentForm(forms.Form):
... name = forms.CharField()
... age = forms.IntegerField()
+ ...
>>> class ChildForm(ParentForm):
... name = None
+ ...
>>> list(ChildForm().fields)
['age']
@@ -1568,4 +1602,5 @@ The prefix can also be specified on the form class:
>>> class PersonForm(forms.Form):
... ...
- ... prefix = 'person'
+ ... prefix = "person"
+ ...
diff --git a/docs/ref/forms/fields.txt b/docs/ref/forms/fields.txt
index 727f494da2..317a955a15 100644
--- a/docs/ref/forms/fields.txt
+++ b/docs/ref/forms/fields.txt
@@ -26,9 +26,9 @@ value:
>>> from django import forms
>>> f = forms.EmailField()
- >>> f.clean('foo@example.com')
+ >>> f.clean("foo@example.com")
'foo@example.com'
- >>> f.clean('invalid email address')
+ >>> f.clean("invalid email address")
Traceback (most recent call last):
...
ValidationError: ['Enter a valid email address.']
@@ -55,9 +55,9 @@ an empty value -- either ``None`` or the empty string (``""``) -- then
>>> from django import forms
>>> f = forms.CharField()
- >>> f.clean('foo')
+ >>> f.clean("foo")
'foo'
- >>> f.clean('')
+ >>> f.clean("")
Traceback (most recent call last):
...
ValidationError: ['This field is required.']
@@ -65,7 +65,7 @@ an empty value -- either ``None`` or the empty string (``""``) -- then
Traceback (most recent call last):
...
ValidationError: ['This field is required.']
- >>> f.clean(' ')
+ >>> f.clean(" ")
' '
>>> f.clean(0)
'0'
@@ -80,9 +80,9 @@ To specify that a field is *not* required, pass ``required=False`` to the
.. code-block:: pycon
>>> f = forms.CharField(required=False)
- >>> f.clean('foo')
+ >>> f.clean("foo")
'foo'
- >>> f.clean('')
+ >>> f.clean("")
''
>>> f.clean(None)
''
@@ -124,9 +124,10 @@ We've specified ``auto_id=False`` to simplify the output:
>>> from django import forms
>>> class CommentForm(forms.Form):
- ... name = forms.CharField(label='Your name')
- ... url = forms.URLField(label='Your website', required=False)
+ ... name = forms.CharField(label="Your name")
+ ... url = forms.URLField(label="Your website", required=False)
... comment = forms.CharField()
+ ...
>>> f = CommentForm(auto_id=False)
>>> print(f)
<div>Your name:<input type="text" name="name" required></div>
@@ -146,8 +147,9 @@ The ``label_suffix`` argument lets you override the form's
>>> class ContactForm(forms.Form):
... age = forms.IntegerField()
... nationality = forms.CharField()
- ... captcha_answer = forms.IntegerField(label='2 + 2', label_suffix=' =')
- >>> f = ContactForm(label_suffix='?')
+ ... captcha_answer = forms.IntegerField(label="2 + 2", label_suffix=" =")
+ ...
+ >>> f = ContactForm(label_suffix="?")
>>> print(f)
<div><label for="id_age">Age?</label><input type="number" name="age" required id="id_age"></div>
<div><label for="id_nationality">Nationality?</label><input type="text" name="nationality" required id="id_nationality"></div>
@@ -170,9 +172,10 @@ field is initialized to a particular value. For example:
>>> from django import forms
>>> class CommentForm(forms.Form):
- ... name = forms.CharField(initial='Your name')
- ... url = forms.URLField(initial='http://')
+ ... name = forms.CharField(initial="Your name")
+ ... url = forms.URLField(initial="http://")
... comment = forms.CharField()
+ ...
>>> f = CommentForm(auto_id=False)
>>> print(f)
<div>Name:<input type="text" name="name" value="Your name" required></div>
@@ -189,7 +192,8 @@ and the HTML output will include any validation errors:
... name = forms.CharField()
... url = forms.URLField()
... comment = forms.CharField()
- >>> default_data = {'name': 'Your name', 'url': 'http://'}
+ ...
+ >>> default_data = {"name": "Your name", "url": "http://"}
>>> f = CommentForm(default_data, auto_id=False)
>>> print(f)
<div>Name:<input type="text" name="name" value="Your name" required></div>
@@ -206,10 +210,11 @@ validation if a particular field's value is not given. ``initial`` values are
.. code-block:: pycon
>>> class CommentForm(forms.Form):
- ... name = forms.CharField(initial='Your name')
- ... url = forms.URLField(initial='http://')
+ ... name = forms.CharField(initial="Your name")
+ ... url = forms.URLField(initial="http://")
... comment = forms.CharField()
- >>> data = {'name': '', 'url': '', 'comment': 'Foo'}
+ ...
+ >>> data = {"name": "", "url": "", "comment": "Foo"}
>>> f = CommentForm(data)
>>> f.is_valid()
False
@@ -224,6 +229,7 @@ Instead of a constant, you can also pass any callable:
>>> import datetime
>>> class DateForm(forms.Form):
... day = forms.DateField(initial=datetime.date.today)
+ ...
>>> print(DateForm())
<div><label for="id_day">Day:</label><input type="text" name="day" value="2023-02-11" required id="id_day"></div>
@@ -257,10 +263,11 @@ fields. We've specified ``auto_id=False`` to simplify the output:
>>> from django import forms
>>> class HelpTextContactForm(forms.Form):
- ... subject = forms.CharField(max_length=100, help_text='100 characters max.')
+ ... subject = forms.CharField(max_length=100, help_text="100 characters max.")
... message = forms.CharField()
- ... sender = forms.EmailField(help_text='A valid email address, please.')
+ ... sender = forms.EmailField(help_text="A valid email address, please.")
... cc_myself = forms.BooleanField(required=False)
+ ...
>>> f = HelpTextContactForm(auto_id=False)
>>> print(f)
<div>Subject:<div class="helptext">100 characters max.</div><input type="text" name="subject" maxlength="100" required></div>
@@ -281,7 +288,7 @@ want to override. For example, here is the default error message:
>>> from django import forms
>>> generic = forms.CharField()
- >>> generic.clean('')
+ >>> generic.clean("")
Traceback (most recent call last):
...
ValidationError: ['This field is required.']
@@ -290,8 +297,8 @@ And here is a custom error message:
.. code-block:: pycon
- >>> name = forms.CharField(error_messages={'required': 'Please enter your name'})
- >>> name.clean('')
+ >>> name = forms.CharField(error_messages={"required": "Please enter your name"})
+ >>> name.clean("")
Traceback (most recent call last):
...
ValidationError: ['Please enter your name']
@@ -746,12 +753,13 @@ For each field, we describe the default widget used if you don't specify
>>> from django.core.files.uploadedfile import SimpleUploadedFile
>>> class ImageForm(forms.Form):
... img = forms.ImageField()
- >>> file_data = {'img': SimpleUploadedFile('test.png', b"file data")}
+ ...
+ >>> file_data = {"img": SimpleUploadedFile("test.png", b"file data")}
>>> form = ImageForm({}, file_data)
# Pillow closes the underlying file descriptor.
>>> form.is_valid()
True
- >>> image_field = form.cleaned_data['img']
+ >>> image_field = form.cleaned_data["img"]
>>> image_field.image
<PIL.PngImagePlugin.PngImageFile image mode=RGBA size=191x287 at 0x7F5985045C18>
>>> image_field.image.width
@@ -893,9 +901,9 @@ For each field, we describe the default widget used if you don't specify
NullBooleanField(
widget=Select(
choices=[
- ('', 'Unknown'),
- (True, 'Yes'),
- (False, 'No'),
+ ("", "Unknown"),
+ (True, "Yes"),
+ (False, "No"),
]
)
)
@@ -1141,32 +1149,35 @@ Slightly complex built-in ``Field`` classes
from django.core.validators import RegexValidator
+
class PhoneField(MultiValueField):
def __init__(self, **kwargs):
# Define one message for all fields.
error_messages = {
- 'incomplete': 'Enter a country calling code and a phone number.',
+ "incomplete": "Enter a country calling code and a phone number.",
}
# Or define a different message for each field.
fields = (
CharField(
- error_messages={'incomplete': 'Enter a country calling code.'},
+ error_messages={"incomplete": "Enter a country calling code."},
validators=[
- RegexValidator(r'^[0-9]+$', 'Enter a valid country calling code.'),
+ RegexValidator(r"^[0-9]+$", "Enter a valid country calling code."),
],
),
CharField(
- error_messages={'incomplete': 'Enter a phone number.'},
- validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid phone number.')],
+ error_messages={"incomplete": "Enter a phone number."},
+ validators=[RegexValidator(r"^[0-9]+$", "Enter a valid phone number.")],
),
CharField(
- validators=[RegexValidator(r'^[0-9]+$', 'Enter a valid extension.')],
+ validators=[RegexValidator(r"^[0-9]+$", "Enter a valid extension.")],
required=False,
),
)
super().__init__(
- error_messages=error_messages, fields=fields,
- require_all_fields=False, **kwargs
+ error_messages=error_messages,
+ fields=fields,
+ require_all_fields=False,
+ **kwargs
)
.. attribute:: MultiValueField.widget
@@ -1238,7 +1249,7 @@ method::
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['foo_select'].queryset = ...
+ self.fields["foo_select"].queryset = ...
Both ``ModelChoiceField`` and ``ModelMultipleChoiceField`` have an ``iterator``
attribute which specifies the class used to iterate over the queryset when
@@ -1351,6 +1362,7 @@ generating choices. See :ref:`iterating-relationship-choices` for details.
from django.forms import ModelChoiceField
+
class MyModelChoiceField(ModelChoiceField):
def label_from_instance(self, obj):
return "My Object #%i" % obj.id
@@ -1416,6 +1428,7 @@ For example, consider the following models::
from django.db import models
+
class Topping(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(decimal_places=2, max_digits=6)
@@ -1423,6 +1436,7 @@ For example, consider the following models::
def __str__(self):
return self.name
+
class Pizza(models.Model):
topping = models.ForeignKey(Topping, on_delete=models.CASCADE)
@@ -1432,18 +1446,24 @@ the value of ``Topping.price`` as the HTML attribute ``data-price`` for each
from django import forms
+
class ToppingSelect(forms.Select):
- def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
- option = super().create_option(name, value, label, selected, index, subindex, attrs)
+ def create_option(
+ self, name, value, label, selected, index, subindex=None, attrs=None
+ ):
+ option = super().create_option(
+ name, value, label, selected, index, subindex, attrs
+ )
if value:
- option['attrs']['data-price'] = value.instance.price
+ option["attrs"]["data-price"] = value.instance.price
return option
+
class PizzaForm(forms.ModelForm):
class Meta:
model = Pizza
- fields = ['topping']
- widgets = {'topping': ToppingSelect}
+ fields = ["topping"]
+ widgets = {"topping": ToppingSelect}
This will render the ``Pizza.topping`` select as:
diff --git a/docs/ref/forms/renderers.txt b/docs/ref/forms/renderers.txt
index 425594b470..6b4eb95cd7 100644
--- a/docs/ref/forms/renderers.txt
+++ b/docs/ref/forms/renderers.txt
@@ -137,7 +137,8 @@ Using this renderer along with the built-in templates requires either:
of one of your template engines. To generate that path::
import django
- django.__path__[0] + '/forms/templates' # or '/forms/jinja2'
+
+ django.__path__[0] + "/forms/templates" # or '/forms/jinja2'
Using this renderer requires you to make sure the form templates your project
needs can be located.
diff --git a/docs/ref/forms/validation.txt b/docs/ref/forms/validation.txt
index c3fa968bdb..a2b3fb4885 100644
--- a/docs/ref/forms/validation.txt
+++ b/docs/ref/forms/validation.txt
@@ -120,22 +120,22 @@ following guidelines:
* Provide a descriptive error ``code`` to the constructor::
# Good
- ValidationError(_('Invalid value'), code='invalid')
+ ValidationError(_("Invalid value"), code="invalid")
# Bad
- ValidationError(_('Invalid value'))
+ ValidationError(_("Invalid value"))
* Don't coerce variables into the message; use placeholders and the ``params``
argument of the constructor::
# Good
ValidationError(
- _('Invalid value: %(value)s'),
- params={'value': '42'},
+ _("Invalid value: %(value)s"),
+ params={"value": "42"},
)
# Bad
- ValidationError(_('Invalid value: %s') % value)
+ ValidationError(_("Invalid value: %s") % value)
* Use mapping keys instead of positional formatting. This enables putting
the variables in any order or omitting them altogether when rewriting the
@@ -143,30 +143,30 @@ following guidelines:
# Good
ValidationError(
- _('Invalid value: %(value)s'),
- params={'value': '42'},
+ _("Invalid value: %(value)s"),
+ params={"value": "42"},
)
# Bad
ValidationError(
- _('Invalid value: %s'),
- params=('42',),
+ _("Invalid value: %s"),
+ params=("42",),
)
* Wrap the message with ``gettext`` to enable translation::
# Good
- ValidationError(_('Invalid value'))
+ ValidationError(_("Invalid value"))
# Bad
- ValidationError('Invalid value')
+ ValidationError("Invalid value")
Putting it all together::
raise ValidationError(
- _('Invalid value: %(value)s'),
- code='invalid',
- params={'value': '42'},
+ _("Invalid value: %(value)s"),
+ code="invalid",
+ params={"value": "42"},
)
Following these guidelines is particularly necessary if you write reusable
@@ -176,7 +176,7 @@ While not recommended, if you are at the end of the validation chain
(i.e. your form ``clean()`` method) and you know you will *never* need
to override your error message you can still opt for the less verbose::
- ValidationError(_('Invalid value: %s') % value)
+ ValidationError(_("Invalid value: %s") % value)
The :meth:`Form.errors.as_data() <django.forms.Form.errors.as_data()>` and
:meth:`Form.errors.as_json() <django.forms.Form.errors.as_json()>` methods
@@ -194,16 +194,20 @@ As above, it is recommended to pass a list of ``ValidationError`` instances
with ``code``\s and ``params`` but a list of strings will also work::
# Good
- raise ValidationError([
- ValidationError(_('Error 1'), code='error1'),
- ValidationError(_('Error 2'), code='error2'),
- ])
+ raise ValidationError(
+ [
+ ValidationError(_("Error 1"), code="error1"),
+ ValidationError(_("Error 2"), code="error2"),
+ ]
+ )
# Bad
- raise ValidationError([
- _('Error 1'),
- _('Error 2'),
- ])
+ raise ValidationError(
+ [
+ _("Error 1"),
+ _("Error 2"),
+ ]
+ )
Using validation in practice
============================
@@ -232,6 +236,7 @@ at Django's ``SlugField``::
from django.core import validators
from django.forms import CharField
+
class SlugField(CharField):
default_validators = [validators.validate_slug]
@@ -262,13 +267,14 @@ containing comma-separated email addresses. The full class looks like this::
from django import forms
from django.core.validators import validate_email
+
class MultiEmailField(forms.Field):
def to_python(self, value):
"""Normalize data to a list of strings."""
# Return an empty list if no input was given.
if not value:
return []
- return value.split(',')
+ return value.split(",")
def validate(self, value):
"""Check if value consists only of valid emails."""
@@ -307,12 +313,13 @@ write a cleaning method that operates on the ``recipients`` field, like so::
from django import forms
from django.core.exceptions import ValidationError
+
class ContactForm(forms.Form):
# Everything as before.
...
def clean_recipients(self):
- data = self.cleaned_data['recipients']
+ data = self.cleaned_data["recipients"]
if "fred@example.com" not in data:
raise ValidationError("You have forgotten about Fred!")
@@ -349,6 +356,7 @@ example::
from django import forms
from django.core.exceptions import ValidationError
+
class ContactForm(forms.Form):
# Everything as before.
...
@@ -362,8 +370,7 @@ example::
# Only do something if both fields are valid so far.
if "help" not in subject:
raise ValidationError(
- "Did not send for 'help' in the subject despite "
- "CC'ing yourself."
+ "Did not send for 'help' in the subject despite " "CC'ing yourself."
)
In this code, if the validation error is raised, the form will display an
@@ -392,6 +399,7 @@ work out what works effectively in your particular situation. Our new code
from django import forms
+
class ContactForm(forms.Form):
# Everything as before.
...
@@ -403,8 +411,8 @@ work out what works effectively in your particular situation. Our new code
if cc_myself and subject and "help" not in subject:
msg = "Must put 'help' in subject when cc'ing yourself."
- self.add_error('cc_myself', msg)
- self.add_error('subject', msg)
+ self.add_error("cc_myself", msg)
+ self.add_error("subject", msg)
The second argument of ``add_error()`` can be a string, or preferably an
instance of ``ValidationError``. See :ref:`raising-validation-error` for more
diff --git a/docs/ref/forms/widgets.txt b/docs/ref/forms/widgets.txt
index 43a579b4a5..1fbd5ad4a0 100644
--- a/docs/ref/forms/widgets.txt
+++ b/docs/ref/forms/widgets.txt
@@ -38,6 +38,7 @@ use the :attr:`~Field.widget` argument on the field definition. For example::
from django import forms
+
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
@@ -56,15 +57,18 @@ widget on the field. In the following example, the
from django import forms
- BIRTH_YEAR_CHOICES = ['1980', '1981', '1982']
+ BIRTH_YEAR_CHOICES = ["1980", "1981", "1982"]
FAVORITE_COLORS_CHOICES = [
- ('blue', 'Blue'),
- ('green', 'Green'),
- ('black', 'Black'),
+ ("blue", "Blue"),
+ ("green", "Green"),
+ ("black", "Black"),
]
+
class SimpleForm(forms.Form):
- birth_year = forms.DateField(widget=forms.SelectDateWidget(years=BIRTH_YEAR_CHOICES))
+ birth_year = forms.DateField(
+ widget=forms.SelectDateWidget(years=BIRTH_YEAR_CHOICES)
+ )
favorite_colors = forms.MultipleChoiceField(
required=False,
widget=forms.CheckboxSelectMultiple,
@@ -91,14 +95,14 @@ example:
.. code-block:: pycon
>>> from django import forms
- >>> CHOICES = [('1', 'First'), ('2', 'Second')]
+ >>> CHOICES = [("1", "First"), ("2", "Second")]
>>> choice_field = forms.ChoiceField(widget=forms.RadioSelect, choices=CHOICES)
>>> choice_field.choices
[('1', 'First'), ('2', 'Second')]
>>> choice_field.widget.choices
[('1', 'First'), ('2', 'Second')]
>>> choice_field.widget.choices = []
- >>> choice_field.choices = [('1', 'First and only')]
+ >>> choice_field.choices = [("1", "First and only")]
>>> choice_field.widget.choices
[('1', 'First and only')]
@@ -132,6 +136,7 @@ For example, take the following form::
from django import forms
+
class CommentForm(forms.Form):
name = forms.CharField()
url = forms.URLField()
@@ -156,9 +161,9 @@ the 'type' attribute to take advantage of the new HTML5 input types. To do
this, you use the :attr:`Widget.attrs` argument when creating the widget::
class CommentForm(forms.Form):
- name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
+ name = forms.CharField(widget=forms.TextInput(attrs={"class": "special"}))
url = forms.URLField()
- comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))
+ comment = forms.CharField(widget=forms.TextInput(attrs={"size": "40"}))
You can also modify a widget in the form definition::
@@ -167,8 +172,8 @@ You can also modify a widget in the form definition::
url = forms.URLField()
comment = forms.CharField()
- name.widget.attrs.update({'class': 'special'})
- comment.widget.attrs.update(size='40')
+ name.widget.attrs.update({"class": "special"})
+ comment.widget.attrs.update(size="40")
Or if the field isn't declared directly on the form (such as model form fields),
you can use the :attr:`Form.fields` attribute::
@@ -176,8 +181,8 @@ you can use the :attr:`Form.fields` attribute::
class CommentForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.fields['name'].widget.attrs.update({'class': 'special'})
- self.fields['comment'].widget.attrs.update(size='40')
+ self.fields["name"].widget.attrs.update({"class": "special"})
+ self.fields["comment"].widget.attrs.update(size="40")
Django will then include the extra attributes in the rendered output:
@@ -231,8 +236,8 @@ foundation for custom widgets.
.. code-block:: pycon
>>> from django import forms
- >>> name = forms.TextInput(attrs={'size': 10, 'title': 'Your name'})
- >>> name.render('name', 'A name')
+ >>> name = forms.TextInput(attrs={"size": 10, "title": "Your name"})
+ >>> name.render("name", "A name")
'<input title="Your name" type="text" name="name" value="A name" size="10">'
If you assign a value of ``True`` or ``False`` to an attribute,
@@ -240,12 +245,12 @@ foundation for custom widgets.
.. code-block:: pycon
- >>> name = forms.TextInput(attrs={'required': True})
- >>> name.render('name', 'A name')
+ >>> name = forms.TextInput(attrs={"required": True})
+ >>> name.render("name", "A name")
'<input name="name" type="text" value="A name" required>'
>>>
- >>> name = forms.TextInput(attrs={'required': False})
- >>> name.render('name', 'A name')
+ >>> name = forms.TextInput(attrs={"required": False})
+ >>> name.render("name", "A name")
'<input name="name" type="text" value="A name">'
.. attribute:: Widget.supports_microseconds
@@ -373,7 +378,7 @@ foundation for custom widgets.
>>> from django.forms import MultiWidget, TextInput
>>> widget = MultiWidget(widgets=[TextInput, TextInput])
- >>> widget.render('name', ['john', 'paul'])
+ >>> widget.render("name", ["john", "paul"])
'<input type="text" name="name_0" value="john"><input type="text" name="name_1" value="paul">'
You may provide a dictionary in order to specify custom suffixes for
@@ -385,8 +390,8 @@ foundation for custom widgets.
.. code-block:: pycon
- >>> widget = MultiWidget(widgets={'': TextInput, 'last': TextInput})
- >>> widget.render('name', ['john', 'paul'])
+ >>> widget = MultiWidget(widgets={"": TextInput, "last": TextInput})
+ >>> widget.render("name", ["john", "paul"])
'<input type="text" name="name" value="john"><input type="text" name="name_last" value="paul">'
And one required method:
@@ -409,8 +414,8 @@ foundation for custom widgets.
from django.forms import MultiWidget
- class SplitDateTimeWidget(MultiWidget):
+ class SplitDateTimeWidget(MultiWidget):
# ...
def decompress(self, value):
@@ -450,6 +455,7 @@ foundation for custom widgets.
from datetime import date
from django import forms
+
class DateSelectorWidget(forms.MultiWidget):
def __init__(self, attrs=None):
days = [(day, day) for day in range(1, 32)]
@@ -466,14 +472,14 @@ foundation for custom widgets.
if isinstance(value, date):
return [value.day, value.month, value.year]
elif isinstance(value, str):
- year, month, day = value.split('-')
+ year, month, day = value.split("-")
return [day, month, year]
return [None, None, None]
def value_from_datadict(self, data, files, name):
day, month, year = super().value_from_datadict(data, files, name)
# DateField expects a single string that it can parse into a date.
- return '{}-{}-{}'.format(year, month, day)
+ return "{}-{}-{}".format(year, month, day)
The constructor creates several :class:`Select` widgets in a list. The
``super()`` method uses this list to set up the widget.
@@ -952,9 +958,18 @@ Composite widgets
the values are the displayed months::
MONTHS = {
- 1:_('jan'), 2:_('feb'), 3:_('mar'), 4:_('apr'),
- 5:_('may'), 6:_('jun'), 7:_('jul'), 8:_('aug'),
- 9:_('sep'), 10:_('oct'), 11:_('nov'), 12:_('dec')
+ 1: _("jan"),
+ 2: _("feb"),
+ 3: _("mar"),
+ 4: _("apr"),
+ 5: _("may"),
+ 6: _("jun"),
+ 7: _("jul"),
+ 8: _("aug"),
+ 9: _("sep"),
+ 10: _("oct"),
+ 11: _("nov"),
+ 12: _("dec"),
}
.. attribute:: SelectDateWidget.empty_label
diff --git a/docs/ref/logging.txt b/docs/ref/logging.txt
index c21bd67a70..a117f0863c 100644
--- a/docs/ref/logging.txt
+++ b/docs/ref/logging.txt
@@ -64,51 +64,51 @@ available as ``django.utils.log.DEFAULT_LOGGING`` and defined in
:source:`django/utils/log.py`::
{
- 'version': 1,
- 'disable_existing_loggers': False,
- 'filters': {
- 'require_debug_false': {
- '()': 'django.utils.log.RequireDebugFalse',
+ "version": 1,
+ "disable_existing_loggers": False,
+ "filters": {
+ "require_debug_false": {
+ "()": "django.utils.log.RequireDebugFalse",
},
- 'require_debug_true': {
- '()': 'django.utils.log.RequireDebugTrue',
+ "require_debug_true": {
+ "()": "django.utils.log.RequireDebugTrue",
},
},
- 'formatters': {
- 'django.server': {
- '()': 'django.utils.log.ServerFormatter',
- 'format': '[{server_time}] {message}',
- 'style': '{',
+ "formatters": {
+ "django.server": {
+ "()": "django.utils.log.ServerFormatter",
+ "format": "[{server_time}] {message}",
+ "style": "{",
}
},
- 'handlers': {
- 'console': {
- 'level': 'INFO',
- 'filters': ['require_debug_true'],
- 'class': 'logging.StreamHandler',
+ "handlers": {
+ "console": {
+ "level": "INFO",
+ "filters": ["require_debug_true"],
+ "class": "logging.StreamHandler",
},
- 'django.server': {
- 'level': 'INFO',
- 'class': 'logging.StreamHandler',
- 'formatter': 'django.server',
+ "django.server": {
+ "level": "INFO",
+ "class": "logging.StreamHandler",
+ "formatter": "django.server",
+ },
+ "mail_admins": {
+ "level": "ERROR",
+ "filters": ["require_debug_false"],
+ "class": "django.utils.log.AdminEmailHandler",
},
- 'mail_admins': {
- 'level': 'ERROR',
- 'filters': ['require_debug_false'],
- 'class': 'django.utils.log.AdminEmailHandler'
- }
},
- 'loggers': {
- 'django': {
- 'handlers': ['console', 'mail_admins'],
- 'level': 'INFO',
+ "loggers": {
+ "django": {
+ "handlers": ["console", "mail_admins"],
+ "level": "INFO",
},
- 'django.server': {
- 'handlers': ['django.server'],
- 'level': 'INFO',
- 'propagate': False,
+ "django.server": {
+ "handlers": ["django.server"],
+ "level": "INFO",
+ "propagate": False,
},
- }
+ },
}
See :ref:`configuring-logging` on how to complement or replace this default
@@ -230,15 +230,15 @@ specific logger following this example::
LOGGING = {
# ...
- 'handlers': {
- 'null': {
- 'class': 'logging.NullHandler',
+ "handlers": {
+ "null": {
+ "class": "logging.NullHandler",
},
},
- 'loggers': {
- 'django.security.DisallowedHost': {
- 'handlers': ['null'],
- 'propagate': False,
+ "loggers": {
+ "django.security.DisallowedHost": {
+ "handlers": ["null"],
+ "propagate": False,
},
},
# ...
@@ -284,11 +284,11 @@ Python logging module <python:logging.handlers>`.
configuration, include it in the handler definition for
``django.utils.log.AdminEmailHandler``, like this::
- 'handlers': {
- 'mail_admins': {
- 'level': 'ERROR',
- 'class': 'django.utils.log.AdminEmailHandler',
- 'include_html': True,
+ "handlers": {
+ "mail_admins": {
+ "level": "ERROR",
+ "class": "django.utils.log.AdminEmailHandler",
+ "include_html": True,
},
}
@@ -299,11 +299,11 @@ Python logging module <python:logging.handlers>`.
:ref:`email backend <topic-email-backends>` that is being used by the
handler can be overridden, like this::
- 'handlers': {
- 'mail_admins': {
- 'level': 'ERROR',
- 'class': 'django.utils.log.AdminEmailHandler',
- 'email_backend': 'django.core.mail.backends.filebased.EmailBackend',
+ "handlers": {
+ "mail_admins": {
+ "level": "ERROR",
+ "class": "django.utils.log.AdminEmailHandler",
+ "email_backend": "django.core.mail.backends.filebased.EmailBackend",
},
}
@@ -315,12 +315,12 @@ Python logging module <python:logging.handlers>`.
traceback text sent in the email body. You provide a string import path to
the class you wish to use, like this::
- 'handlers': {
- 'mail_admins': {
- 'level': 'ERROR',
- 'class': 'django.utils.log.AdminEmailHandler',
- 'include_html': True,
- 'reporter_class': 'somepackage.error_reporter.CustomErrorReporter',
+ "handlers": {
+ "mail_admins": {
+ "level": "ERROR",
+ "class": "django.utils.log.AdminEmailHandler",
+ "include_html": True,
+ "reporter_class": "somepackage.error_reporter.CustomErrorReporter",
},
}
@@ -349,6 +349,7 @@ logging module.
from django.http import UnreadablePostError
+
def skip_unreadable_post(record):
if record.exc_info:
exc_type, exc_value = record.exc_info[:2]
@@ -360,17 +361,17 @@ logging module.
LOGGING = {
# ...
- 'filters': {
- 'skip_unreadable_posts': {
- '()': 'django.utils.log.CallbackFilter',
- 'callback': skip_unreadable_post,
+ "filters": {
+ "skip_unreadable_posts": {
+ "()": "django.utils.log.CallbackFilter",
+ "callback": skip_unreadable_post,
},
},
- 'handlers': {
- 'mail_admins': {
- 'level': 'ERROR',
- 'filters': ['skip_unreadable_posts'],
- 'class': 'django.utils.log.AdminEmailHandler',
+ "handlers": {
+ "mail_admins": {
+ "level": "ERROR",
+ "filters": ["skip_unreadable_posts"],
+ "class": "django.utils.log.AdminEmailHandler",
},
},
# ...
@@ -386,16 +387,16 @@ logging module.
LOGGING = {
# ...
- 'filters': {
- 'require_debug_false': {
- '()': 'django.utils.log.RequireDebugFalse',
+ "filters": {
+ "require_debug_false": {
+ "()": "django.utils.log.RequireDebugFalse",
},
},
- 'handlers': {
- 'mail_admins': {
- 'level': 'ERROR',
- 'filters': ['require_debug_false'],
- 'class': 'django.utils.log.AdminEmailHandler',
+ "handlers": {
+ "mail_admins": {
+ "level": "ERROR",
+ "filters": ["require_debug_false"],
+ "class": "django.utils.log.AdminEmailHandler",
},
},
# ...
diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt
index a270b8b774..73f315e7fc 100644
--- a/docs/ref/middleware.txt
+++ b/docs/ref/middleware.txt
@@ -67,6 +67,7 @@ Adds a few conveniences for perfectionists:
from django.views.decorators.common import no_append_slash
+
@no_append_slash
def sensitive_fbv(request, *args, **kwargs):
"""View to be excluded from APPEND_SLASH."""
diff --git a/docs/ref/migration-operations.txt b/docs/ref/migration-operations.txt
index 2481dd4f27..96a8e4bc8c 100644
--- a/docs/ref/migration-operations.txt
+++ b/docs/ref/migration-operations.txt
@@ -297,7 +297,7 @@ queries and parameters in the same way as :ref:`cursor.execute()
migrations.RunSQL("INSERT INTO musician (name) VALUES ('Reinhardt');")
migrations.RunSQL([("INSERT INTO musician (name) VALUES ('Reinhardt');", None)])
- migrations.RunSQL([("INSERT INTO musician (name) VALUES (%s);", ['Reinhardt'])])
+ migrations.RunSQL([("INSERT INTO musician (name) VALUES (%s);", ["Reinhardt"])])
If you want to include literal percent signs in the query, you have to double
them if you are passing parameters.
@@ -307,8 +307,8 @@ should undo what is done by the ``sql`` queries. For example, to undo the above
insertion with a deletion::
migrations.RunSQL(
- sql=[("INSERT INTO musician (name) VALUES (%s);", ['Reinhardt'])],
- reverse_sql=[("DELETE FROM musician where name=%s;", ['Reinhardt'])],
+ sql=[("INSERT INTO musician (name) VALUES (%s);", ["Reinhardt"])],
+ reverse_sql=[("DELETE FROM musician where name=%s;", ["Reinhardt"])],
)
If ``reverse_sql`` is ``None`` (the default), the ``RunSQL`` operation is
@@ -325,8 +325,8 @@ operation that adds that field and so will try to run it again. For example::
"ALTER TABLE musician ADD COLUMN name varchar(255) NOT NULL;",
state_operations=[
migrations.AddField(
- 'musician',
- 'name',
+ "musician",
+ "name",
models.CharField(max_length=255),
),
],
@@ -377,15 +377,19 @@ using ``RunPython`` to create some initial objects on a ``Country`` model::
from django.db import migrations
+
def forwards_func(apps, schema_editor):
# We get the model from the versioned app registry;
# if we directly import it, it'll be the wrong version
Country = apps.get_model("myapp", "Country")
db_alias = schema_editor.connection.alias
- Country.objects.using(db_alias).bulk_create([
- Country(name="USA", code="us"),
- Country(name="France", code="fr"),
- ])
+ Country.objects.using(db_alias).bulk_create(
+ [
+ Country(name="USA", code="us"),
+ Country(name="France", code="fr"),
+ ]
+ )
+
def reverse_func(apps, schema_editor):
# forwards_func() creates two Country instances,
@@ -395,8 +399,8 @@ using ``RunPython`` to create some initial objects on a ``Country`` model::
Country.objects.using(db_alias).filter(name="USA", code="us").delete()
Country.objects.using(db_alias).filter(name="France", code="fr").delete()
- class Migration(migrations.Migration):
+ class Migration(migrations.Migration):
dependencies = []
operations = [
@@ -484,8 +488,8 @@ structure of an ``Operation`` looks like this::
from django.db.migrations.operations.base import Operation
- class MyCustomOperation(Operation):
+ class MyCustomOperation(Operation):
# If this is False, it means that this operation will be ignored by
# sqlmigrate; if true, it will be run and the SQL collected for its output.
reduces_to_sql = False
@@ -574,8 +578,8 @@ state changes, all it does is run one command::
from django.db.migrations.operations.base import Operation
- class LoadExtension(Operation):
+ class LoadExtension(Operation):
reversible = True
def __init__(self, name):
diff --git a/docs/ref/models/class.txt b/docs/ref/models/class.txt
index 81414973a9..c0ccb6caff 100644
--- a/docs/ref/models/class.txt
+++ b/docs/ref/models/class.txt
@@ -55,6 +55,7 @@ Attributes
from django.db import models
+
class Person(models.Model):
# Add manager with another name
people = models.Manager()
diff --git a/docs/ref/models/conditional-expressions.txt b/docs/ref/models/conditional-expressions.txt
index 8dd477a187..d14312870f 100644
--- a/docs/ref/models/conditional-expressions.txt
+++ b/docs/ref/models/conditional-expressions.txt
@@ -17,14 +17,15 @@ We'll be using the following model in the subsequent examples::
from django.db import models
+
class Client(models.Model):
- REGULAR = 'R'
- GOLD = 'G'
- PLATINUM = 'P'
+ REGULAR = "R"
+ GOLD = "G"
+ PLATINUM = "P"
ACCOUNT_TYPE_CHOICES = [
- (REGULAR, 'Regular'),
- (GOLD, 'Gold'),
- (PLATINUM, 'Platinum'),
+ (REGULAR, "Regular"),
+ (GOLD, "Gold"),
+ (PLATINUM, "Platinum"),
]
name = models.CharField(max_length=50)
registered_on = models.DateField()
@@ -54,28 +55,33 @@ Some examples:
>>> from django.db.models import F, Q, When
>>> # String arguments refer to fields; the following two examples are equivalent:
- >>> When(account_type=Client.GOLD, then='name')
- >>> When(account_type=Client.GOLD, then=F('name'))
+ >>> When(account_type=Client.GOLD, then="name")
+ >>> When(account_type=Client.GOLD, then=F("name"))
>>> # You can use field lookups in the condition
>>> from datetime import date
- >>> When(registered_on__gt=date(2014, 1, 1),
- ... registered_on__lt=date(2015, 1, 1),
- ... then='account_type')
+ >>> When(
+ ... registered_on__gt=date(2014, 1, 1),
+ ... registered_on__lt=date(2015, 1, 1),
+ ... then="account_type",
+ ... )
>>> # Complex conditions can be created using Q objects
- >>> When(Q(name__startswith="John") | Q(name__startswith="Paul"),
- ... then='name')
+ >>> When(Q(name__startswith="John") | Q(name__startswith="Paul"), then="name")
>>> # Condition can be created using boolean expressions.
>>> from django.db.models import Exists, OuterRef
- >>> non_unique_account_type = Client.objects.filter(
- ... account_type=OuterRef('account_type'),
- ... ).exclude(pk=OuterRef('pk')).values('pk')
- >>> When(Exists(non_unique_account_type), then=Value('non unique'))
+ >>> non_unique_account_type = (
+ ... Client.objects.filter(
+ ... account_type=OuterRef("account_type"),
+ ... )
+ ... .exclude(pk=OuterRef("pk"))
+ ... .values("pk")
+ ... )
+ >>> When(Exists(non_unique_account_type), then=Value("non unique"))
>>> # Condition can be created using lookup expressions.
>>> from django.db.models.lookups import GreaterThan, LessThan
>>> When(
- ... GreaterThan(F('registered_on'), date(2014, 1, 1)) &
- ... LessThan(F('registered_on'), date(2015, 1, 1)),
- ... then='account_type',
+ ... GreaterThan(F("registered_on"), date(2014, 1, 1))
+ ... & LessThan(F("registered_on"), date(2015, 1, 1)),
+ ... then="account_type",
... )
Keep in mind that each of these values can be an expression.
@@ -111,25 +117,28 @@ An example:
>>> from datetime import date, timedelta
>>> from django.db.models import Case, Value, When
>>> Client.objects.create(
- ... name='Jane Doe',
+ ... name="Jane Doe",
... account_type=Client.REGULAR,
- ... registered_on=date.today() - timedelta(days=36))
+ ... registered_on=date.today() - timedelta(days=36),
+ ... )
>>> Client.objects.create(
- ... name='James Smith',
+ ... name="James Smith",
... account_type=Client.GOLD,
- ... registered_on=date.today() - timedelta(days=5))
+ ... registered_on=date.today() - timedelta(days=5),
+ ... )
>>> Client.objects.create(
- ... name='Jack Black',
+ ... name="Jack Black",
... account_type=Client.PLATINUM,
- ... registered_on=date.today() - timedelta(days=10 * 365))
+ ... registered_on=date.today() - timedelta(days=10 * 365),
+ ... )
>>> # Get the discount for each Client based on the account type
>>> Client.objects.annotate(
... discount=Case(
- ... When(account_type=Client.GOLD, then=Value('5%')),
- ... When(account_type=Client.PLATINUM, then=Value('10%')),
- ... default=Value('0%'),
+ ... When(account_type=Client.GOLD, then=Value("5%")),
+ ... When(account_type=Client.PLATINUM, then=Value("10%")),
+ ... default=Value("0%"),
... ),
- ... ).values_list('name', 'discount')
+ ... ).values_list("name", "discount")
<QuerySet [('Jane Doe', '0%'), ('James Smith', '5%'), ('Jack Black', '10%')]>
``Case()`` accepts any number of ``When()`` objects as individual arguments.
@@ -148,11 +157,11 @@ the ``Client`` has been with us, we could do so using lookups:
>>> # Get the discount for each Client based on the registration date
>>> Client.objects.annotate(
... discount=Case(
- ... When(registered_on__lte=a_year_ago, then=Value('10%')),
- ... When(registered_on__lte=a_month_ago, then=Value('5%')),
- ... default=Value('0%'),
+ ... When(registered_on__lte=a_year_ago, then=Value("10%")),
+ ... When(registered_on__lte=a_month_ago, then=Value("5%")),
+ ... default=Value("0%"),
... )
- ... ).values_list('name', 'discount')
+ ... ).values_list("name", "discount")
<QuerySet [('Jane Doe', '5%'), ('James Smith', '0%'), ('Jack Black', '10%')]>
.. note::
@@ -175,7 +184,7 @@ registered more than a year ago:
... When(account_type=Client.GOLD, then=a_month_ago),
... When(account_type=Client.PLATINUM, then=a_year_ago),
... ),
- ... ).values_list('name', 'account_type')
+ ... ).values_list("name", "account_type")
<QuerySet [('Jack Black', 'P')]>
Advanced queries
@@ -199,14 +208,12 @@ their registration dates. We can do this using a conditional expression and the
>>> # Update the account_type for each Client from the registration date
>>> Client.objects.update(
... account_type=Case(
- ... When(registered_on__lte=a_year_ago,
- ... then=Value(Client.PLATINUM)),
- ... When(registered_on__lte=a_month_ago,
- ... then=Value(Client.GOLD)),
- ... default=Value(Client.REGULAR)
+ ... When(registered_on__lte=a_year_ago, then=Value(Client.PLATINUM)),
+ ... When(registered_on__lte=a_month_ago, then=Value(Client.GOLD)),
+ ... default=Value(Client.REGULAR),
... ),
... )
- >>> Client.objects.values_list('name', 'account_type')
+ >>> Client.objects.values_list("name", "account_type")
<QuerySet [('Jane Doe', 'G'), ('James Smith', 'R'), ('Jack Black', 'P')]>
.. _conditional-aggregation:
@@ -222,23 +229,20 @@ functions <aggregation-functions>` to achieve this:
>>> # Create some more Clients first so we can have something to count
>>> Client.objects.create(
- ... name='Jean Grey',
- ... account_type=Client.REGULAR,
- ... registered_on=date.today())
+ ... name="Jean Grey", account_type=Client.REGULAR, registered_on=date.today()
+ ... )
>>> Client.objects.create(
- ... name='James Bond',
- ... account_type=Client.PLATINUM,
- ... registered_on=date.today())
+ ... name="James Bond", account_type=Client.PLATINUM, registered_on=date.today()
+ ... )
>>> Client.objects.create(
- ... name='Jane Porter',
- ... account_type=Client.PLATINUM,
- ... registered_on=date.today())
+ ... name="Jane Porter", account_type=Client.PLATINUM, registered_on=date.today()
+ ... )
>>> # Get counts for each value of account_type
>>> from django.db.models import Count
>>> Client.objects.aggregate(
- ... regular=Count('pk', filter=Q(account_type=Client.REGULAR)),
- ... gold=Count('pk', filter=Q(account_type=Client.GOLD)),
- ... platinum=Count('pk', filter=Q(account_type=Client.PLATINUM)),
+ ... regular=Count("pk", filter=Q(account_type=Client.REGULAR)),
+ ... gold=Count("pk", filter=Q(account_type=Client.GOLD)),
+ ... platinum=Count("pk", filter=Q(account_type=Client.PLATINUM)),
... )
{'regular': 2, 'gold': 1, 'platinum': 3}
@@ -273,9 +277,13 @@ columns, but you can still use it to filter results:
.. code-block:: pycon
- >>> non_unique_account_type = Client.objects.filter(
- ... account_type=OuterRef('account_type'),
- ... ).exclude(pk=OuterRef('pk')).values('pk')
+ >>> non_unique_account_type = (
+ ... Client.objects.filter(
+ ... account_type=OuterRef("account_type"),
+ ... )
+ ... .exclude(pk=OuterRef("pk"))
+ ... .values("pk")
+ ... )
>>> Client.objects.filter(~Exists(non_unique_account_type))
In SQL terms, that evaluates to:
diff --git a/docs/ref/models/constraints.txt b/docs/ref/models/constraints.txt
index f248de0315..4ed5b65d46 100644
--- a/docs/ref/models/constraints.txt
+++ b/docs/ref/models/constraints.txt
@@ -126,7 +126,7 @@ ensures the age field is never less than 18.
to behave the same as check constraints validation. For example, if ``age``
is a nullable field::
- CheckConstraint(check=Q(age__gte=18) | Q(age__isnull=True), name='age_gte_18')
+ CheckConstraint(check=Q(age__gte=18) | Q(age__isnull=True), name="age_gte_18")
``UniqueConstraint``
====================
@@ -145,7 +145,7 @@ constraints on expressions and database functions.
For example::
- UniqueConstraint(Lower('name').desc(), 'category', name='unique_lower_name_category')
+ UniqueConstraint(Lower("name").desc(), "category", name="unique_lower_name_category")
creates a unique constraint on the lowercased value of the ``name`` field in
descending order and the ``category`` field in the default ascending order.
@@ -175,7 +175,7 @@ enforce.
For example::
- UniqueConstraint(fields=['user'], condition=Q(status='DRAFT'), name='unique_draft_user')
+ UniqueConstraint(fields=["user"], condition=Q(status="DRAFT"), name="unique_draft_user")
ensures that each user only has one draft.
@@ -193,8 +193,8 @@ are ``Deferrable.DEFERRED`` or ``Deferrable.IMMEDIATE``. For example::
from django.db.models import Deferrable, UniqueConstraint
UniqueConstraint(
- name='unique_order',
- fields=['order'],
+ name="unique_order",
+ fields=["order"],
deferrable=Deferrable.DEFERRED,
)
@@ -224,7 +224,7 @@ and filter only by unique fields (:attr:`~UniqueConstraint.fields`).
For example::
- UniqueConstraint(name='unique_booking', fields=['room', 'date'], include=['full_name'])
+ UniqueConstraint(name="unique_booking", fields=["room", "date"], include=["full_name"])
will allow filtering on ``room`` and ``date``, also selecting ``full_name``,
while fetching data only from the index.
@@ -246,7 +246,9 @@ for each field in the index.
For example::
- UniqueConstraint(name='unique_username', fields=['username'], opclasses=['varchar_pattern_ops'])
+ UniqueConstraint(
+ name="unique_username", fields=["username"], opclasses=["varchar_pattern_ops"]
+ )
creates a unique index on ``username`` using ``varchar_pattern_ops``.
diff --git a/docs/ref/models/database-functions.txt b/docs/ref/models/database-functions.txt
index a9c404b60a..13b70d76cd 100644
--- a/docs/ref/models/database-functions.txt
+++ b/docs/ref/models/database-functions.txt
@@ -41,9 +41,9 @@ Usage example:
>>> from django.db.models import FloatField
>>> from django.db.models.functions import Cast
- >>> Author.objects.create(age=25, name='Margaret Smith')
+ >>> Author.objects.create(age=25, name="Margaret Smith")
>>> author = Author.objects.annotate(
- ... age_as_float=Cast('age', output_field=FloatField()),
+ ... age_as_float=Cast("age", output_field=FloatField()),
... ).get()
>>> print(author.age_as_float)
25.0
@@ -65,24 +65,23 @@ Usage examples:
>>> # Get a screen name from least to most public
>>> from django.db.models import Sum
>>> from django.db.models.functions import Coalesce
- >>> Author.objects.create(name='Margaret Smith', goes_by='Maggie')
- >>> author = Author.objects.annotate(
- ... screen_name=Coalesce('alias', 'goes_by', 'name')).get()
+ >>> Author.objects.create(name="Margaret Smith", goes_by="Maggie")
+ >>> author = Author.objects.annotate(screen_name=Coalesce("alias", "goes_by", "name")).get()
>>> print(author.screen_name)
Maggie
>>> # Prevent an aggregate Sum() from returning None
>>> # The aggregate default argument uses Coalesce() under the hood.
>>> aggregated = Author.objects.aggregate(
- ... combined_age=Sum('age'),
- ... combined_age_default=Sum('age', default=0),
- ... combined_age_coalesce=Coalesce(Sum('age'), 0),
+ ... combined_age=Sum("age"),
+ ... combined_age_default=Sum("age", default=0),
+ ... combined_age_coalesce=Coalesce(Sum("age"), 0),
... )
- >>> print(aggregated['combined_age'])
+ >>> print(aggregated["combined_age"])
None
- >>> print(aggregated['combined_age_default'])
+ >>> print(aggregated["combined_age_default"])
0
- >>> print(aggregated['combined_age_coalesce'])
+ >>> print(aggregated["combined_age_coalesce"])
0
.. warning::
@@ -107,14 +106,14 @@ For example, to filter case-insensitively in SQLite:
.. code-block:: pycon
- >>> Author.objects.filter(name=Collate(Value('john'), 'nocase'))
+ >>> Author.objects.filter(name=Collate(Value("john"), "nocase"))
<QuerySet [<Author: John>, <Author: john>]>
It can also be used when ordering, for example with PostgreSQL:
.. code-block:: pycon
- >>> Author.objects.order_by(Collate('name', 'et-x-icu'))
+ >>> Author.objects.order_by(Collate("name", "et-x-icu"))
<QuerySet [<Author: Ursula>, <Author: Veronika>, <Author: Ülle>]>
``Greatest``
@@ -132,6 +131,7 @@ Usage example::
body = models.TextField()
modified = models.DateTimeField(auto_now=True)
+
class Comment(models.Model):
body = models.TextField()
modified = models.DateTimeField(auto_now=True)
@@ -140,9 +140,9 @@ Usage example::
.. code-block:: pycon
>>> from django.db.models.functions import Greatest
- >>> blog = Blog.objects.create(body='Greatest is the best.')
- >>> comment = Comment.objects.create(body='No, Least is better.', blog=blog)
- >>> comments = Comment.objects.annotate(last_updated=Greatest('modified', 'blog__modified'))
+ >>> blog = Blog.objects.create(body="Greatest is the best.")
+ >>> comment = Comment.objects.create(body="No, Least is better.", blog=blog)
+ >>> comments = Comment.objects.annotate(last_updated=Greatest("modified", "blog__modified"))
>>> annotated_comment = comments.get()
``annotated_comment.last_updated`` will be the most recent of ``blog.modified``
@@ -175,12 +175,14 @@ Usage example:
>>> from django.db.models import F
>>> from django.db.models.functions import JSONObject, Lower
- >>> Author.objects.create(name='Margaret Smith', alias='msmith', age=25)
- >>> author = Author.objects.annotate(json_object=JSONObject(
- ... name=Lower('name'),
- ... alias='alias',
- ... age=F('age') * 2,
- ... )).get()
+ >>> Author.objects.create(name="Margaret Smith", alias="msmith", age=25)
+ >>> author = Author.objects.annotate(
+ ... json_object=JSONObject(
+ ... name=Lower("name"),
+ ... alias="alias",
+ ... age=F("age") * 2,
+ ... )
+ ... ).get()
>>> author.json_object
{'name': 'margaret smith', 'alias': 'msmith', 'age': 50}
@@ -315,16 +317,16 @@ Usage example:
>>> start = datetime(2015, 6, 15)
>>> end = datetime(2015, 7, 2)
>>> Experiment.objects.create(
- ... start_datetime=start, start_date=start.date(),
- ... end_datetime=end, end_date=end.date())
+ ... start_datetime=start, start_date=start.date(), end_datetime=end, end_date=end.date()
+ ... )
>>> # Add the experiment start year as a field in the QuerySet.
>>> experiment = Experiment.objects.annotate(
- ... start_year=Extract('start_datetime', 'year')).get()
+ ... start_year=Extract("start_datetime", "year")
+ ... ).get()
>>> experiment.start_year
2015
>>> # How many experiments completed in the same year in which they started?
- >>> Experiment.objects.filter(
- ... start_datetime__year=Extract('end_datetime', 'year')).count()
+ >>> Experiment.objects.filter(start_datetime__year=Extract("end_datetime", "year")).count()
1
``DateField`` extracts
@@ -378,27 +380,44 @@ that deal with date-parts can be used with ``DateField``:
>>> from datetime import datetime, timezone
>>> from django.db.models.functions import (
- ... ExtractDay, ExtractMonth, ExtractQuarter, ExtractWeek,
- ... ExtractIsoWeekDay, ExtractWeekDay, ExtractIsoYear, ExtractYear,
+ ... ExtractDay,
+ ... ExtractMonth,
+ ... ExtractQuarter,
+ ... ExtractWeek,
+ ... ExtractIsoWeekDay,
+ ... ExtractWeekDay,
+ ... ExtractIsoYear,
+ ... ExtractYear,
... )
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
>>> Experiment.objects.create(
- ... start_datetime=start_2015, start_date=start_2015.date(),
- ... end_datetime=end_2015, end_date=end_2015.date())
+ ... start_datetime=start_2015,
+ ... start_date=start_2015.date(),
+ ... end_datetime=end_2015,
+ ... end_date=end_2015.date(),
+ ... )
>>> Experiment.objects.annotate(
- ... year=ExtractYear('start_date'),
- ... isoyear=ExtractIsoYear('start_date'),
- ... quarter=ExtractQuarter('start_date'),
- ... month=ExtractMonth('start_date'),
- ... week=ExtractWeek('start_date'),
- ... day=ExtractDay('start_date'),
- ... weekday=ExtractWeekDay('start_date'),
- ... isoweekday=ExtractIsoWeekDay('start_date'),
+ ... year=ExtractYear("start_date"),
+ ... isoyear=ExtractIsoYear("start_date"),
+ ... quarter=ExtractQuarter("start_date"),
+ ... month=ExtractMonth("start_date"),
+ ... week=ExtractWeek("start_date"),
+ ... day=ExtractDay("start_date"),
+ ... weekday=ExtractWeekDay("start_date"),
+ ... isoweekday=ExtractIsoWeekDay("start_date"),
... ).values(
- ... 'year', 'isoyear', 'quarter', 'month', 'week', 'day', 'weekday',
- ... 'isoweekday',
- ... ).get(end_date__year=ExtractYear('start_date'))
+ ... "year",
+ ... "isoyear",
+ ... "quarter",
+ ... "month",
+ ... "week",
+ ... "day",
+ ... "weekday",
+ ... "isoweekday",
+ ... ).get(
+ ... end_date__year=ExtractYear("start_date")
+ ... )
{'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
'day': 15, 'weekday': 2, 'isoweekday': 1}
@@ -430,31 +449,52 @@ Each class is also a ``Transform`` registered on ``DateTimeField`` as
>>> from datetime import datetime, timezone
>>> from django.db.models.functions import (
- ... ExtractDay, ExtractHour, ExtractMinute, ExtractMonth,
- ... ExtractQuarter, ExtractSecond, ExtractWeek, ExtractIsoWeekDay,
- ... ExtractWeekDay, ExtractIsoYear, ExtractYear,
+ ... ExtractDay,
+ ... ExtractHour,
+ ... ExtractMinute,
+ ... ExtractMonth,
+ ... ExtractQuarter,
+ ... ExtractSecond,
+ ... ExtractWeek,
+ ... ExtractIsoWeekDay,
+ ... ExtractWeekDay,
+ ... ExtractIsoYear,
+ ... ExtractYear,
... )
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
>>> Experiment.objects.create(
- ... start_datetime=start_2015, start_date=start_2015.date(),
- ... end_datetime=end_2015, end_date=end_2015.date())
+ ... start_datetime=start_2015,
+ ... start_date=start_2015.date(),
+ ... end_datetime=end_2015,
+ ... end_date=end_2015.date(),
+ ... )
>>> Experiment.objects.annotate(
- ... year=ExtractYear('start_datetime'),
- ... isoyear=ExtractIsoYear('start_datetime'),
- ... quarter=ExtractQuarter('start_datetime'),
- ... month=ExtractMonth('start_datetime'),
- ... week=ExtractWeek('start_datetime'),
- ... day=ExtractDay('start_datetime'),
- ... weekday=ExtractWeekDay('start_datetime'),
- ... isoweekday=ExtractIsoWeekDay('start_datetime'),
- ... hour=ExtractHour('start_datetime'),
- ... minute=ExtractMinute('start_datetime'),
- ... second=ExtractSecond('start_datetime'),
+ ... year=ExtractYear("start_datetime"),
+ ... isoyear=ExtractIsoYear("start_datetime"),
+ ... quarter=ExtractQuarter("start_datetime"),
+ ... month=ExtractMonth("start_datetime"),
+ ... week=ExtractWeek("start_datetime"),
+ ... day=ExtractDay("start_datetime"),
+ ... weekday=ExtractWeekDay("start_datetime"),
+ ... isoweekday=ExtractIsoWeekDay("start_datetime"),
+ ... hour=ExtractHour("start_datetime"),
+ ... minute=ExtractMinute("start_datetime"),
+ ... second=ExtractSecond("start_datetime"),
... ).values(
- ... 'year', 'isoyear', 'month', 'week', 'day',
- ... 'weekday', 'isoweekday', 'hour', 'minute', 'second',
- ... ).get(end_datetime__year=ExtractYear('start_datetime'))
+ ... "year",
+ ... "isoyear",
+ ... "month",
+ ... "week",
+ ... "day",
+ ... "weekday",
+ ... "isoweekday",
+ ... "hour",
+ ... "minute",
+ ... "second",
+ ... ).get(
+ ... end_datetime__year=ExtractYear("start_datetime")
+ ... )
{'year': 2015, 'isoyear': 2015, 'quarter': 2, 'month': 6, 'week': 25,
'day': 15, 'weekday': 2, 'isoweekday': 1, 'hour': 23, 'minute': 30,
'second': 1}
@@ -469,16 +509,17 @@ values that are returned:
>>> from django.utils import timezone
>>> import zoneinfo
- >>> melb = zoneinfo.ZoneInfo('Australia/Melbourne') # UTC+10:00
+ >>> melb = zoneinfo.ZoneInfo("Australia/Melbourne") # UTC+10:00
>>> with timezone.override(melb):
- ... Experiment.objects.annotate(
- ... day=ExtractDay('start_datetime'),
- ... weekday=ExtractWeekDay('start_datetime'),
- ... isoweekday=ExtractIsoWeekDay('start_datetime'),
- ... hour=ExtractHour('start_datetime'),
- ... ).values('day', 'weekday', 'isoweekday', 'hour').get(
- ... end_datetime__year=ExtractYear('start_datetime'),
- ... )
+ ... Experiment.objects.annotate(
+ ... day=ExtractDay("start_datetime"),
+ ... weekday=ExtractWeekDay("start_datetime"),
+ ... isoweekday=ExtractIsoWeekDay("start_datetime"),
+ ... hour=ExtractHour("start_datetime"),
+ ... ).values("day", "weekday", "isoweekday", "hour").get(
+ ... end_datetime__year=ExtractYear("start_datetime"),
+ ... )
+ ...
{'day': 16, 'weekday': 3, 'isoweekday': 2, 'hour': 9}
Explicitly passing the timezone to the ``Extract`` function behaves in the same
@@ -487,14 +528,14 @@ way, and takes priority over an active timezone:
.. code-block:: pycon
>>> import zoneinfo
- >>> melb = zoneinfo.ZoneInfo('Australia/Melbourne')
+ >>> melb = zoneinfo.ZoneInfo("Australia/Melbourne")
>>> Experiment.objects.annotate(
- ... day=ExtractDay('start_datetime', tzinfo=melb),
- ... weekday=ExtractWeekDay('start_datetime', tzinfo=melb),
- ... isoweekday=ExtractIsoWeekDay('start_datetime', tzinfo=melb),
- ... hour=ExtractHour('start_datetime', tzinfo=melb),
- ... ).values('day', 'weekday', 'isoweekday', 'hour').get(
- ... end_datetime__year=ExtractYear('start_datetime'),
+ ... day=ExtractDay("start_datetime", tzinfo=melb),
+ ... weekday=ExtractWeekDay("start_datetime", tzinfo=melb),
+ ... isoweekday=ExtractIsoWeekDay("start_datetime", tzinfo=melb),
+ ... hour=ExtractHour("start_datetime", tzinfo=melb),
+ ... ).values("day", "weekday", "isoweekday", "hour").get(
+ ... end_datetime__year=ExtractYear("start_datetime"),
... )
{'day': 16, 'weekday': 3, 'isoweekday': 2, 'hour': 9}
@@ -594,16 +635,20 @@ Usage example:
>>> Experiment.objects.create(start_datetime=datetime(2015, 6, 15, 14, 30, 50, 321))
>>> Experiment.objects.create(start_datetime=datetime(2015, 6, 15, 14, 40, 2, 123))
>>> Experiment.objects.create(start_datetime=datetime(2015, 12, 25, 10, 5, 27, 999))
- >>> experiments_per_day = Experiment.objects.annotate(
- ... start_day=Trunc('start_datetime', 'day', output_field=DateTimeField())
- ... ).values('start_day').annotate(experiments=Count('id'))
+ >>> experiments_per_day = (
+ ... Experiment.objects.annotate(
+ ... start_day=Trunc("start_datetime", "day", output_field=DateTimeField())
+ ... )
+ ... .values("start_day")
+ ... .annotate(experiments=Count("id"))
+ ... )
>>> for exp in experiments_per_day:
- ... print(exp['start_day'], exp['experiments'])
+ ... print(exp["start_day"], exp["experiments"])
...
2015-06-15 00:00:00 2
2015-12-25 00:00:00 1
>>> experiments = Experiment.objects.annotate(
- ... start_day=Trunc('start_datetime', 'day', output_field=DateTimeField())
+ ... start_day=Trunc("start_datetime", "day", output_field=DateTimeField())
... ).filter(start_day=datetime(2015, 6, 15))
>>> for exp in experiments:
... print(exp.start_datetime)
@@ -651,22 +696,26 @@ that deal with date-parts can be used with ``DateField``:
>>> Experiment.objects.create(start_datetime=start1, start_date=start1.date())
>>> Experiment.objects.create(start_datetime=start2, start_date=start2.date())
>>> Experiment.objects.create(start_datetime=start3, start_date=start3.date())
- >>> experiments_per_year = Experiment.objects.annotate(
- ... year=TruncYear('start_date')).values('year').annotate(
- ... experiments=Count('id'))
+ >>> experiments_per_year = (
+ ... Experiment.objects.annotate(year=TruncYear("start_date"))
+ ... .values("year")
+ ... .annotate(experiments=Count("id"))
+ ... )
>>> for exp in experiments_per_year:
- ... print(exp['year'], exp['experiments'])
+ ... print(exp["year"], exp["experiments"])
...
2014-01-01 1
2015-01-01 2
>>> import zoneinfo
- >>> melb = zoneinfo.ZoneInfo('Australia/Melbourne')
- >>> experiments_per_month = Experiment.objects.annotate(
- ... month=TruncMonth('start_datetime', tzinfo=melb)).values('month').annotate(
- ... experiments=Count('id'))
+ >>> melb = zoneinfo.ZoneInfo("Australia/Melbourne")
+ >>> experiments_per_month = (
+ ... Experiment.objects.annotate(month=TruncMonth("start_datetime", tzinfo=melb))
+ ... .values("month")
+ ... .annotate(experiments=Count("id"))
+ ... )
>>> for exp in experiments_per_month:
- ... print(exp['month'], exp['experiments'])
+ ... print(exp["month"], exp["experiments"])
...
2015-06-01 00:00:00+10:00 1
2016-01-01 00:00:00+11:00 1
@@ -721,19 +770,23 @@ Usage example:
>>> from datetime import date, datetime, timezone
>>> from django.db.models import Count
>>> from django.db.models.functions import (
- ... TruncDate, TruncDay, TruncHour, TruncMinute, TruncSecond,
+ ... TruncDate,
+ ... TruncDay,
+ ... TruncHour,
+ ... TruncMinute,
+ ... TruncSecond,
... )
>>> import zoneinfo
>>> start1 = datetime(2014, 6, 15, 14, 30, 50, 321, tzinfo=timezone.utc)
>>> Experiment.objects.create(start_datetime=start1, start_date=start1.date())
- >>> melb = zoneinfo.ZoneInfo('Australia/Melbourne')
+ >>> melb = zoneinfo.ZoneInfo("Australia/Melbourne")
>>> Experiment.objects.annotate(
- ... date=TruncDate('start_datetime'),
- ... day=TruncDay('start_datetime', tzinfo=melb),
- ... hour=TruncHour('start_datetime', tzinfo=melb),
- ... minute=TruncMinute('start_datetime'),
- ... second=TruncSecond('start_datetime'),
- ... ).values('date', 'day', 'hour', 'minute', 'second').get()
+ ... date=TruncDate("start_datetime"),
+ ... day=TruncDay("start_datetime", tzinfo=melb),
+ ... hour=TruncHour("start_datetime", tzinfo=melb),
+ ... minute=TruncMinute("start_datetime"),
+ ... second=TruncSecond("start_datetime"),
+ ... ).values("date", "day", "hour", "minute", "second").get()
{'date': datetime.date(2014, 6, 15),
'day': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=zoneinfo.ZoneInfo('Australia/Melbourne')),
'hour': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=zoneinfo.ZoneInfo('Australia/Melbourne')),
@@ -778,22 +831,30 @@ that deal with time-parts can be used with ``TimeField``:
>>> Experiment.objects.create(start_datetime=start1, start_time=start1.time())
>>> Experiment.objects.create(start_datetime=start2, start_time=start2.time())
>>> Experiment.objects.create(start_datetime=start3, start_time=start3.time())
- >>> experiments_per_hour = Experiment.objects.annotate(
- ... hour=TruncHour('start_datetime', output_field=TimeField()),
- ... ).values('hour').annotate(experiments=Count('id'))
+ >>> experiments_per_hour = (
+ ... Experiment.objects.annotate(
+ ... hour=TruncHour("start_datetime", output_field=TimeField()),
+ ... )
+ ... .values("hour")
+ ... .annotate(experiments=Count("id"))
+ ... )
>>> for exp in experiments_per_hour:
- ... print(exp['hour'], exp['experiments'])
+ ... print(exp["hour"], exp["experiments"])
...
14:00:00 2
17:00:00 1
>>> import zoneinfo
- >>> melb = zoneinfo.ZoneInfo('Australia/Melbourne')
- >>> experiments_per_hour = Experiment.objects.annotate(
- ... hour=TruncHour('start_datetime', tzinfo=melb),
- ... ).values('hour').annotate(experiments=Count('id'))
+ >>> melb = zoneinfo.ZoneInfo("Australia/Melbourne")
+ >>> experiments_per_hour = (
+ ... Experiment.objects.annotate(
+ ... hour=TruncHour("start_datetime", tzinfo=melb),
+ ... )
+ ... .values("hour")
+ ... .annotate(experiments=Count("id"))
+ ... )
>>> for exp in experiments_per_hour:
- ... print(exp['hour'], exp['experiments'])
+ ... print(exp["hour"], exp["experiments"])
...
2014-06-16 00:00:00+10:00 2
2016-01-01 04:00:00+11:00 1
@@ -822,7 +883,7 @@ Usage example:
>>> from django.db.models.functions import Abs
>>> Vector.objects.create(x=-0.5, y=1.1)
- >>> vector = Vector.objects.annotate(x_abs=Abs('x'), y_abs=Abs('y')).get()
+ >>> vector = Vector.objects.annotate(x_abs=Abs("x"), y_abs=Abs("y")).get()
>>> vector.x_abs, vector.y_abs
(0.5, 1.1)
@@ -850,7 +911,7 @@ Usage example:
>>> from django.db.models.functions import ACos
>>> Vector.objects.create(x=0.5, y=-0.9)
- >>> vector = Vector.objects.annotate(x_acos=ACos('x'), y_acos=ACos('y')).get()
+ >>> vector = Vector.objects.annotate(x_acos=ACos("x"), y_acos=ACos("y")).get()
>>> vector.x_acos, vector.y_acos
(1.0471975511965979, 2.6905658417935308)
@@ -878,7 +939,7 @@ Usage example:
>>> from django.db.models.functions import ASin
>>> Vector.objects.create(x=0, y=1)
- >>> vector = Vector.objects.annotate(x_asin=ASin('x'), y_asin=ASin('y')).get()
+ >>> vector = Vector.objects.annotate(x_asin=ASin("x"), y_asin=ASin("y")).get()
>>> vector.x_asin, vector.y_asin
(0.0, 1.5707963267948966)
@@ -905,7 +966,7 @@ Usage example:
>>> from django.db.models.functions import ATan
>>> Vector.objects.create(x=3.12, y=6.987)
- >>> vector = Vector.objects.annotate(x_atan=ATan('x'), y_atan=ATan('y')).get()
+ >>> vector = Vector.objects.annotate(x_atan=ATan("x"), y_atan=ATan("y")).get()
>>> vector.x_atan, vector.y_atan
(1.2606282660069106, 1.428638798133829)
@@ -932,7 +993,7 @@ Usage example:
>>> from django.db.models.functions import ATan2
>>> Vector.objects.create(x=2.5, y=1.9)
- >>> vector = Vector.objects.annotate(atan2=ATan2('x', 'y')).get()
+ >>> vector = Vector.objects.annotate(atan2=ATan2("x", "y")).get()
>>> vector.atan2
0.9209258773829491
@@ -950,7 +1011,7 @@ Usage example:
>>> from django.db.models.functions import Ceil
>>> Vector.objects.create(x=3.12, y=7.0)
- >>> vector = Vector.objects.annotate(x_ceil=Ceil('x'), y_ceil=Ceil('y')).get()
+ >>> vector = Vector.objects.annotate(x_ceil=Ceil("x"), y_ceil=Ceil("y")).get()
>>> vector.x_ceil, vector.y_ceil
(4.0, 7.0)
@@ -977,7 +1038,7 @@ Usage example:
>>> from django.db.models.functions import Cos
>>> Vector.objects.create(x=-8.0, y=3.1415926)
- >>> vector = Vector.objects.annotate(x_cos=Cos('x'), y_cos=Cos('y')).get()
+ >>> vector = Vector.objects.annotate(x_cos=Cos("x"), y_cos=Cos("y")).get()
>>> vector.x_cos, vector.y_cos
(-0.14550003380861354, -0.9999999999999986)
@@ -1004,7 +1065,7 @@ Usage example:
>>> from django.db.models.functions import Cot
>>> Vector.objects.create(x=12.0, y=1.0)
- >>> vector = Vector.objects.annotate(x_cot=Cot('x'), y_cot=Cot('y')).get()
+ >>> vector = Vector.objects.annotate(x_cot=Cot("x"), y_cot=Cot("y")).get()
>>> vector.x_cot, vector.y_cot
(-1.5726734063976826, 0.642092615934331)
@@ -1031,7 +1092,7 @@ Usage example:
>>> from django.db.models.functions import Degrees
>>> Vector.objects.create(x=-1.57, y=3.14)
- >>> vector = Vector.objects.annotate(x_d=Degrees('x'), y_d=Degrees('y')).get()
+ >>> vector = Vector.objects.annotate(x_d=Degrees("x"), y_d=Degrees("y")).get()
>>> vector.x_d, vector.y_d
(-89.95437383553924, 179.9087476710785)
@@ -1059,7 +1120,7 @@ Usage example:
>>> from django.db.models.functions import Exp
>>> Vector.objects.create(x=5.4, y=-2.0)
- >>> vector = Vector.objects.annotate(x_exp=Exp('x'), y_exp=Exp('y')).get()
+ >>> vector = Vector.objects.annotate(x_exp=Exp("x"), y_exp=Exp("y")).get()
>>> vector.x_exp, vector.y_exp
(221.40641620418717, 0.1353352832366127)
@@ -1087,7 +1148,7 @@ Usage example:
>>> from django.db.models.functions import Floor
>>> Vector.objects.create(x=5.4, y=-2.3)
- >>> vector = Vector.objects.annotate(x_floor=Floor('x'), y_floor=Floor('y')).get()
+ >>> vector = Vector.objects.annotate(x_floor=Floor("x"), y_floor=Floor("y")).get()
>>> vector.x_floor, vector.y_floor
(5.0, -3.0)
@@ -1114,7 +1175,7 @@ Usage example:
>>> from django.db.models.functions import Ln
>>> Vector.objects.create(x=5.4, y=233.0)
- >>> vector = Vector.objects.annotate(x_ln=Ln('x'), y_ln=Ln('y')).get()
+ >>> vector = Vector.objects.annotate(x_ln=Ln("x"), y_ln=Ln("y")).get()
>>> vector.x_ln, vector.y_ln
(1.6863989535702288, 5.4510384535657)
@@ -1142,7 +1203,7 @@ Usage example:
>>> from django.db.models.functions import Log
>>> Vector.objects.create(x=2.0, y=4.0)
- >>> vector = Vector.objects.annotate(log=Log('x', 'y')).get()
+ >>> vector = Vector.objects.annotate(log=Log("x", "y")).get()
>>> vector.log
2.0
@@ -1160,7 +1221,7 @@ Usage example:
>>> from django.db.models.functions import Mod
>>> Vector.objects.create(x=5.4, y=2.3)
- >>> vector = Vector.objects.annotate(mod=Mod('x', 'y')).get()
+ >>> vector = Vector.objects.annotate(mod=Mod("x", "y")).get()
>>> vector.mod
0.8
@@ -1185,7 +1246,7 @@ Usage example:
>>> from django.db.models.functions import Power
>>> Vector.objects.create(x=2, y=-2)
- >>> vector = Vector.objects.annotate(power=Power('x', 'y')).get()
+ >>> vector = Vector.objects.annotate(power=Power("x", "y")).get()
>>> vector.power
0.25
@@ -1202,7 +1263,7 @@ Usage example:
>>> from django.db.models.functions import Radians
>>> Vector.objects.create(x=-90, y=180)
- >>> vector = Vector.objects.annotate(x_r=Radians('x'), y_r=Radians('y')).get()
+ >>> vector = Vector.objects.annotate(x_r=Radians("x"), y_r=Radians("y")).get()
>>> vector.x_r, vector.y_r
(-1.5707963267948966, 3.141592653589793)
@@ -1238,7 +1299,7 @@ Usage example:
>>> from django.db.models.functions import Round
>>> Vector.objects.create(x=5.4, y=-2.37)
- >>> vector = Vector.objects.annotate(x_r=Round('x'), y_r=Round('y', precision=1)).get()
+ >>> vector = Vector.objects.annotate(x_r=Round("x"), y_r=Round("y", precision=1)).get()
>>> vector.x_r, vector.y_r
(5.0, -2.4)
@@ -1265,7 +1326,7 @@ Usage example:
>>> from django.db.models.functions import Sign
>>> Vector.objects.create(x=5.4, y=-2.3)
- >>> vector = Vector.objects.annotate(x_sign=Sign('x'), y_sign=Sign('y')).get()
+ >>> vector = Vector.objects.annotate(x_sign=Sign("x"), y_sign=Sign("y")).get()
>>> vector.x_sign, vector.y_sign
(1, -1)
@@ -1292,7 +1353,7 @@ Usage example:
>>> from django.db.models.functions import Sin
>>> Vector.objects.create(x=5.4, y=-2.3)
- >>> vector = Vector.objects.annotate(x_sin=Sin('x'), y_sin=Sin('y')).get()
+ >>> vector = Vector.objects.annotate(x_sin=Sin("x"), y_sin=Sin("y")).get()
>>> vector.x_sin, vector.y_sin
(-0.7727644875559871, -0.7457052121767203)
@@ -1319,7 +1380,7 @@ Usage example:
>>> from django.db.models.functions import Sqrt
>>> Vector.objects.create(x=4.0, y=12.0)
- >>> vector = Vector.objects.annotate(x_sqrt=Sqrt('x'), y_sqrt=Sqrt('y')).get()
+ >>> vector = Vector.objects.annotate(x_sqrt=Sqrt("x"), y_sqrt=Sqrt("y")).get()
>>> vector.x_sqrt, vector.y_sqrt
(2.0, 3.46410)
@@ -1346,7 +1407,7 @@ Usage example:
>>> from django.db.models.functions import Tan
>>> Vector.objects.create(x=0, y=12)
- >>> vector = Vector.objects.annotate(x_tan=Tan('x'), y_tan=Tan('y')).get()
+ >>> vector = Vector.objects.annotate(x_tan=Tan("x"), y_tan=Tan("y")).get()
>>> vector.x_tan, vector.y_tan
(0.0, -0.6358599286615808)
@@ -1382,8 +1443,8 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import Chr
- >>> Author.objects.create(name='Margaret Smith')
- >>> author = Author.objects.filter(name__startswith=Chr(ord('M'))).get()
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> author = Author.objects.filter(name__startswith=Chr(ord("M"))).get()
>>> print(author.name)
Margaret Smith
@@ -1410,12 +1471,9 @@ Usage example:
>>> # Get the display name as "name (goes_by)"
>>> from django.db.models import CharField, Value as V
>>> from django.db.models.functions import Concat
- >>> Author.objects.create(name='Margaret Smith', goes_by='Maggie')
+ >>> Author.objects.create(name="Margaret Smith", goes_by="Maggie")
>>> author = Author.objects.annotate(
- ... screen_name=Concat(
- ... 'name', V(' ('), 'goes_by', V(')'),
- ... output_field=CharField()
- ... )
+ ... screen_name=Concat("name", V(" ("), "goes_by", V(")"), output_field=CharField())
... ).get()
>>> print(author.screen_name)
Margaret Smith (Maggie)
@@ -1432,8 +1490,8 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import Left
- >>> Author.objects.create(name='Margaret Smith')
- >>> author = Author.objects.annotate(first_initial=Left('name', 1)).get()
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> author = Author.objects.annotate(first_initial=Left("name", 1)).get()
>>> print(author.first_initial)
M
@@ -1451,10 +1509,10 @@ Usage example:
>>> # Get the length of the name and goes_by fields
>>> from django.db.models.functions import Length
- >>> Author.objects.create(name='Margaret Smith')
+ >>> Author.objects.create(name="Margaret Smith")
>>> author = Author.objects.annotate(
- ... name_length=Length('name'),
- ... goes_by_length=Length('goes_by')).get()
+ ... name_length=Length("name"), goes_by_length=Length("goes_by")
+ ... ).get()
>>> print(author.name_length, author.goes_by_length)
(14, None)
@@ -1483,8 +1541,8 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import Lower
- >>> Author.objects.create(name='Margaret Smith')
- >>> author = Author.objects.annotate(name_lower=Lower('name')).get()
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> author = Author.objects.annotate(name_lower=Lower("name")).get()
>>> print(author.name_lower)
margaret smith
@@ -1503,10 +1561,10 @@ Usage example:
>>> from django.db.models import Value
>>> from django.db.models.functions import LPad
- >>> Author.objects.create(name='John', alias='j')
- >>> Author.objects.update(name=LPad('name', 8, Value('abc')))
+ >>> Author.objects.create(name="John", alias="j")
+ >>> Author.objects.update(name=LPad("name", 8, Value("abc")))
1
- >>> print(Author.objects.get(alias='j').name)
+ >>> print(Author.objects.get(alias="j").name)
abcaJohn
``LTrim``
@@ -1532,8 +1590,8 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import MD5
- >>> Author.objects.create(name='Margaret Smith')
- >>> author = Author.objects.annotate(name_md5=MD5('name')).get()
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> author = Author.objects.annotate(name_md5=MD5("name")).get()
>>> print(author.name_md5)
749fb689816b2db85f5b169c2055b247
@@ -1555,8 +1613,8 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import Ord
- >>> Author.objects.create(name='Margaret Smith')
- >>> author = Author.objects.annotate(name_code_point=Ord('name')).get()
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> author = Author.objects.annotate(name_code_point=Ord("name")).get()
>>> print(author.name_code_point)
77
@@ -1573,10 +1631,10 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import Repeat
- >>> Author.objects.create(name='John', alias='j')
- >>> Author.objects.update(name=Repeat('name', 3))
+ >>> Author.objects.create(name="John", alias="j")
+ >>> Author.objects.update(name=Repeat("name", 3))
1
- >>> print(Author.objects.get(alias='j').name)
+ >>> print(Author.objects.get(alias="j").name)
JohnJohnJohn
``Replace``
@@ -1594,11 +1652,11 @@ Usage example:
>>> from django.db.models import Value
>>> from django.db.models.functions import Replace
- >>> Author.objects.create(name='Margaret Johnson')
- >>> Author.objects.create(name='Margaret Smith')
- >>> Author.objects.update(name=Replace('name', Value('Margaret'), Value('Margareth')))
+ >>> Author.objects.create(name="Margaret Johnson")
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> Author.objects.update(name=Replace("name", Value("Margaret"), Value("Margareth")))
2
- >>> Author.objects.values('name')
+ >>> Author.objects.values("name")
<QuerySet [{'name': 'Margareth Johnson'}, {'name': 'Margareth Smith'}]>
``Reverse``
@@ -1617,8 +1675,8 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import Reverse
- >>> Author.objects.create(name='Margaret Smith')
- >>> author = Author.objects.annotate(backward=Reverse('name')).get()
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> author = Author.objects.annotate(backward=Reverse("name")).get()
>>> print(author.backward)
htimS teragraM
@@ -1634,8 +1692,8 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import Right
- >>> Author.objects.create(name='Margaret Smith')
- >>> author = Author.objects.annotate(last_letter=Right('name', 1)).get()
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> author = Author.objects.annotate(last_letter=Right("name", 1)).get()
>>> print(author.last_letter)
h
@@ -1674,8 +1732,8 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import SHA1
- >>> Author.objects.create(name='Margaret Smith')
- >>> author = Author.objects.annotate(name_sha1=SHA1('name')).get()
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> author = Author.objects.annotate(name_sha1=SHA1("name")).get()
>>> print(author.name_sha1)
b87efd8a6c991c390be5a68e8a7945a7851c7e5c
@@ -1705,16 +1763,16 @@ Usage example:
>>> from django.db.models import Value as V
>>> from django.db.models.functions import StrIndex
- >>> Author.objects.create(name='Margaret Smith')
- >>> Author.objects.create(name='Smith, Margaret')
- >>> Author.objects.create(name='Margaret Jackson')
- >>> Author.objects.filter(name='Margaret Jackson').annotate(
- ... smith_index=StrIndex('name', V('Smith'))
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> Author.objects.create(name="Smith, Margaret")
+ >>> Author.objects.create(name="Margaret Jackson")
+ >>> Author.objects.filter(name="Margaret Jackson").annotate(
+ ... smith_index=StrIndex("name", V("Smith"))
... ).get().smith_index
0
- >>> authors = Author.objects.annotate(
- ... smith_index=StrIndex('name', V('Smith'))
- ... ).filter(smith_index__gt=0)
+ >>> authors = Author.objects.annotate(smith_index=StrIndex("name", V("Smith"))).filter(
+ ... smith_index__gt=0
+ ... )
<QuerySet [<Author: Margaret Smith>, <Author: Smith, Margaret>]>
.. warning::
@@ -1739,10 +1797,10 @@ Usage example:
>>> # Set the alias to the first 5 characters of the name as lowercase
>>> from django.db.models.functions import Lower, Substr
- >>> Author.objects.create(name='Margaret Smith')
- >>> Author.objects.update(alias=Lower(Substr('name', 1, 5)))
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> Author.objects.update(alias=Lower(Substr("name", 1, 5)))
1
- >>> print(Author.objects.get(name='Margaret Smith').alias)
+ >>> print(Author.objects.get(name="Margaret Smith").alias)
marga
``Trim``
@@ -1758,10 +1816,10 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import Trim
- >>> Author.objects.create(name=' John ', alias='j')
- >>> Author.objects.update(name=Trim('name'))
+ >>> Author.objects.create(name=" John ", alias="j")
+ >>> Author.objects.update(name=Trim("name"))
1
- >>> print(Author.objects.get(alias='j').name)
+ >>> print(Author.objects.get(alias="j").name)
John
``Upper``
@@ -1779,8 +1837,8 @@ Usage example:
.. code-block:: pycon
>>> from django.db.models.functions import Upper
- >>> Author.objects.create(name='Margaret Smith')
- >>> author = Author.objects.annotate(name_upper=Upper('name')).get()
+ >>> Author.objects.create(name="Margaret Smith")
+ >>> author = Author.objects.annotate(name_upper=Upper("name")).get()
>>> print(author.name_upper)
MARGARET SMITH
diff --git a/docs/ref/models/expressions.txt b/docs/ref/models/expressions.txt
index b109efcff3..52a1022771 100644
--- a/docs/ref/models/expressions.txt
+++ b/docs/ref/models/expressions.txt
@@ -28,18 +28,19 @@ Some examples
>>> from django.db.models.lookups import GreaterThan
# Find companies that have more employees than chairs.
- >>> Company.objects.filter(num_employees__gt=F('num_chairs'))
+ >>> Company.objects.filter(num_employees__gt=F("num_chairs"))
# Find companies that have at least twice as many employees
# as chairs. Both the querysets below are equivalent.
- >>> Company.objects.filter(num_employees__gt=F('num_chairs') * 2)
- >>> Company.objects.filter(
- ... num_employees__gt=F('num_chairs') + F('num_chairs'))
+ >>> Company.objects.filter(num_employees__gt=F("num_chairs") * 2)
+ >>> Company.objects.filter(num_employees__gt=F("num_chairs") + F("num_chairs"))
# How many chairs are needed for each company to seat all employees?
- >>> company = Company.objects.filter(
- ... num_employees__gt=F('num_chairs')).annotate(
- ... chairs_needed=F('num_employees') - F('num_chairs')).first()
+ >>> company = (
+ ... Company.objects.filter(num_employees__gt=F("num_chairs"))
+ ... .annotate(chairs_needed=F("num_employees") - F("num_chairs"))
+ ... .first()
+ ... )
>>> company.num_employees
120
>>> company.num_chairs
@@ -48,7 +49,7 @@ Some examples
70
# Create a new company using expressions.
- >>> company = Company.objects.create(name='Google', ticker=Upper(Value('goog')))
+ >>> company = Company.objects.create(name="Google", ticker=Upper(Value("goog")))
# Be sure to refresh it if you need to access the field.
>>> company.refresh_from_db()
>>> company.ticker
@@ -109,7 +110,7 @@ describes the required operation at the database level.
Let's try this with an example. Normally, one might do something like this::
# Tintin filed a news story!
- reporter = Reporters.objects.get(name='Tintin')
+ reporter = Reporters.objects.get(name="Tintin")
reporter.stories_filed += 1
reporter.save()
@@ -119,8 +120,8 @@ the object back to the database. But instead we could also have done::
from django.db.models import F
- reporter = Reporters.objects.get(name='Tintin')
- reporter.stories_filed = F('stories_filed') + 1
+ reporter = Reporters.objects.get(name="Tintin")
+ reporter.stories_filed = F("stories_filed") + 1
reporter.save()
Although ``reporter.stories_filed = F('stories_filed') + 1`` looks like a
@@ -148,15 +149,15 @@ be used on ``QuerySets`` of object instances, with ``update()``. This reduces
the two queries we were using above - the ``get()`` and the
:meth:`~Model.save()` - to just one::
- reporter = Reporters.objects.filter(name='Tintin')
- reporter.update(stories_filed=F('stories_filed') + 1)
+ reporter = Reporters.objects.filter(name="Tintin")
+ reporter.update(stories_filed=F("stories_filed") + 1)
We can also use :meth:`~django.db.models.query.QuerySet.update()` to increment
the field value on multiple objects - which could be very much faster than
pulling them all into Python from the database, looping over them, incrementing
the field value of each one, and saving each one back to the database::
- Reporter.objects.update(stories_filed=F('stories_filed') + 1)
+ Reporter.objects.update(stories_filed=F("stories_filed") + 1)
``F()`` therefore can offer performance advantages by:
@@ -187,11 +188,11 @@ than based on its value when the instance was retrieved.
``F()`` objects assigned to model fields persist after saving the model
instance and will be applied on each :meth:`~Model.save()`. For example::
- reporter = Reporters.objects.get(name='Tintin')
- reporter.stories_filed = F('stories_filed') + 1
+ reporter = Reporters.objects.get(name="Tintin")
+ reporter.stories_filed = F("stories_filed") + 1
reporter.save()
- reporter.name = 'Tintin Jr.'
+ reporter.name = "Tintin Jr."
reporter.save()
``stories_filed`` will be updated twice in this case. If it's initially ``1``,
@@ -217,8 +218,7 @@ Using ``F()`` with annotations
``F()`` can be used to create dynamic fields on your models by combining
different fields with arithmetic::
- company = Company.objects.annotate(
- chairs_needed=F('num_employees') - F('num_chairs'))
+ company = Company.objects.annotate(chairs_needed=F("num_employees") - F("num_chairs"))
If the fields that you're combining are of different types you'll need
to tell Django what kind of field will be returned. Since ``F()`` does not
@@ -229,7 +229,9 @@ directly support ``output_field`` you will need to wrap the expression with
Ticket.objects.annotate(
expires=ExpressionWrapper(
- F('active_at') + F('duration'), output_field=DateTimeField()))
+ F("active_at") + F("duration"), output_field=DateTimeField()
+ )
+ )
When referencing relational fields such as ``ForeignKey``, ``F()`` returns the
primary key value rather than a model instance:
@@ -255,7 +257,8 @@ For example, to sort companies that haven't been contacted (``last_contacted``
is null) after companies that have been contacted::
from django.db.models import F
- Company.objects.order_by(F('last_contacted').desc(nulls_last=True))
+
+ Company.objects.order_by(F("last_contacted").desc(nulls_last=True))
Using ``F()`` with logical operations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -268,7 +271,7 @@ companies::
from django.db.models import F
- Company.objects.update(is_active=~F('is_active'))
+ Company.objects.update(is_active=~F("is_active"))
.. _func-expressions:
@@ -281,14 +284,15 @@ They can be used directly::
from django.db.models import F, Func
- queryset.annotate(field_lower=Func(F('field'), function='LOWER'))
+ queryset.annotate(field_lower=Func(F("field"), function="LOWER"))
or they can be used to build a library of database functions::
class Lower(Func):
- function = 'LOWER'
+ function = "LOWER"
+
- queryset.annotate(field_lower=Lower('field'))
+ queryset.annotate(field_lower=Lower("field"))
But both cases will result in a queryset where each model is annotated with an
extra attribute ``field_lower`` produced, roughly, from the following SQL:
@@ -350,13 +354,14 @@ The ``Func`` API is as follows:
class ConcatPair(Func):
...
- function = 'CONCAT'
+ function = "CONCAT"
...
def as_mysql(self, compiler, connection, **extra_context):
return super().as_sql(
- compiler, connection,
- function='CONCAT_WS',
+ compiler,
+ connection,
+ function="CONCAT_WS",
template="%(function)s('', %(expressions)s)",
**extra_context
)
@@ -400,7 +405,8 @@ some complex computations::
from django.db.models import Count
Company.objects.annotate(
- managers_required=(Count('num_employees') / 4) + Count('num_managers'))
+ managers_required=(Count("num_employees") / 4) + Count("num_managers")
+ )
The ``Aggregate`` API is as follows:
@@ -477,18 +483,15 @@ generated. Here's a brief example::
from django.db.models import Aggregate
+
class Sum(Aggregate):
# Supports SUM(ALL field).
- function = 'SUM'
- template = '%(function)s(%(all_values)s%(expressions)s)'
+ function = "SUM"
+ template = "%(function)s(%(all_values)s%(expressions)s)"
allow_distinct = False
def __init__(self, expression, all_values=False, **extra):
- super().__init__(
- expression,
- all_values='ALL ' if all_values else '',
- **extra
- )
+ super().__init__(expression, all_values="ALL " if all_values else "", **extra)
``Value()`` expressions
-----------------------
@@ -554,8 +557,8 @@ newest comment on that post:
.. code-block:: pycon
>>> from django.db.models import OuterRef, Subquery
- >>> newest = Comment.objects.filter(post=OuterRef('pk')).order_by('-created_at')
- >>> Post.objects.annotate(newest_commenter_email=Subquery(newest.values('email')[:1]))
+ >>> newest = Comment.objects.filter(post=OuterRef("pk")).order_by("-created_at")
+ >>> Post.objects.annotate(newest_commenter_email=Subquery(newest.values("email")[:1]))
On PostgreSQL, the SQL looks like:
@@ -592,7 +595,7 @@ parent. For example, this queryset would need to be within a nested pair of
.. code-block:: pycon
- >>> Book.objects.filter(author=OuterRef(OuterRef('pk')))
+ >>> Book.objects.filter(author=OuterRef(OuterRef("pk")))
Limiting a subquery to a single column
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -607,7 +610,7 @@ all comments for posts published within the last day:
>>> from django.utils import timezone
>>> one_day_ago = timezone.now() - timedelta(days=1)
>>> posts = Post.objects.filter(published_at__gte=one_day_ago)
- >>> Comment.objects.filter(post__in=Subquery(posts.values('pk')))
+ >>> Comment.objects.filter(post__in=Subquery(posts.values("pk")))
In this case, the subquery must use :meth:`~.QuerySet.values`
to return only a single column: the primary key of the post.
@@ -620,7 +623,7 @@ queryset is used:
.. code-block:: pycon
- >>> subquery = Subquery(newest.values('email')[:1])
+ >>> subquery = Subquery(newest.values("email")[:1])
>>> Post.objects.annotate(newest_commenter_email=subquery)
In this case, the subquery must only return a single column *and* a single
@@ -649,7 +652,7 @@ within the last day:
>>> from django.utils import timezone
>>> one_day_ago = timezone.now() - timedelta(days=1)
>>> recent_comments = Comment.objects.filter(
- ... post=OuterRef('pk'),
+ ... post=OuterRef("pk"),
... created_at__gte=one_day_ago,
... )
>>> Post.objects.annotate(recent_comment=Exists(recent_comments))
@@ -703,8 +706,8 @@ length is greater than the total length of all combined comments:
.. code-block:: pycon
>>> from django.db.models import OuterRef, Subquery, Sum
- >>> comments = Comment.objects.filter(post=OuterRef('pk')).order_by().values('post')
- >>> total_comments = comments.annotate(total=Sum('length')).values('total')
+ >>> comments = Comment.objects.filter(post=OuterRef("pk")).order_by().values("post")
+ >>> total_comments = comments.annotate(total=Sum("length")).values("total")
>>> Post.objects.filter(length__gt=Subquery(total_comments))
The initial ``filter(...)`` limits the subquery to the relevant parameters.
@@ -814,9 +817,9 @@ the same studio in the same genre and release year:
>>> from django.db.models import Avg, F, Window
>>> Movie.objects.annotate(
... avg_rating=Window(
- ... expression=Avg('rating'),
- ... partition_by=[F('studio'), F('genre')],
- ... order_by='released__year',
+ ... expression=Avg("rating"),
+ ... partition_by=[F("studio"), F("genre")],
+ ... order_by="released__year",
... ),
... )
@@ -833,18 +836,21 @@ to reduce repetition:
>>> from django.db.models import Avg, F, Max, Min, Window
>>> window = {
- ... 'partition_by': [F('studio'), F('genre')],
- ... 'order_by': 'released__year',
+ ... "partition_by": [F("studio"), F("genre")],
+ ... "order_by": "released__year",
... }
>>> Movie.objects.annotate(
... avg_rating=Window(
- ... expression=Avg('rating'), **window,
+ ... expression=Avg("rating"),
+ ... **window,
... ),
... best=Window(
- ... expression=Max('rating'), **window,
+ ... expression=Max("rating"),
+ ... **window,
... ),
... worst=Window(
- ... expression=Min('rating'), **window,
+ ... expression=Min("rating"),
+ ... **window,
... ),
... )
@@ -860,13 +866,9 @@ from groups to be included:
.. code-block:: pycon
>>> qs = Movie.objects.annotate(
- ... category_rank=Window(
- ... Rank(), partition_by='category', order_by='-rating'
- ... ),
- ... scenes_count=Count('actors'),
- ... ).filter(
- ... Q(category_rank__lte=3) | Q(title__contains='Batman')
- ... )
+ ... category_rank=Window(Rank(), partition_by="category", order_by="-rating"),
+ ... scenes_count=Count("actors"),
+ ... ).filter(Q(category_rank__lte=3) | Q(title__contains="Batman"))
>>> list(qs)
NotImplementedError: Heterogeneous disjunctive predicates against window functions
are not implemented when performing conditional aggregation.
@@ -946,9 +948,9 @@ with the average rating of a movie's two prior and two following peers:
>>> from django.db.models import Avg, F, RowRange, Window
>>> Movie.objects.annotate(
... avg_rating=Window(
- ... expression=Avg('rating'),
- ... partition_by=[F('studio'), F('genre')],
- ... order_by='released__year',
+ ... expression=Avg("rating"),
+ ... partition_by=[F("studio"), F("genre")],
+ ... order_by="released__year",
... frame=RowRange(start=-2, end=2),
... ),
... )
@@ -964,9 +966,9 @@ released between twelve months before and twelve months after the each movie:
>>> from django.db.models import Avg, F, ValueRange, Window
>>> Movie.objects.annotate(
... avg_rating=Window(
- ... expression=Avg('rating'),
- ... partition_by=[F('studio'), F('genre')],
- ... order_by='released__year',
+ ... expression=Avg("rating"),
+ ... partition_by=[F("studio"), F("genre")],
+ ... order_by="released__year",
... frame=ValueRange(start=-12, end=12),
... ),
... )
@@ -1050,7 +1052,7 @@ calling the appropriate methods on the wrapped expression.
.. code-block:: pycon
- >>> Sum(F('foo')).get_source_expressions()
+ >>> Sum(F("foo")).get_source_expressions()
[F('foo')]
.. method:: set_source_expressions(expressions)
@@ -1133,17 +1135,18 @@ an ``__init__()`` method to set some attributes::
import copy
from django.db.models import Expression
+
class Coalesce(Expression):
- template = 'COALESCE( %(expressions)s )'
+ template = "COALESCE( %(expressions)s )"
def __init__(self, expressions, output_field):
- super().__init__(output_field=output_field)
- if len(expressions) < 2:
- raise ValueError('expressions must have at least 2 elements')
- for expression in expressions:
- if not hasattr(expression, 'resolve_expression'):
- raise TypeError('%r is not an Expression' % expression)
- self.expressions = expressions
+ super().__init__(output_field=output_field)
+ if len(expressions) < 2:
+ raise ValueError("expressions must have at least 2 elements")
+ for expression in expressions:
+ if not hasattr(expression, "resolve_expression"):
+ raise TypeError("%r is not an Expression" % expression)
+ self.expressions = expressions
We do some basic validation on the parameters, including requiring at least
2 columns or values, and ensuring they are expressions. We are requiring
@@ -1154,11 +1157,15 @@ Now we implement the preprocessing and validation. Since we do not have
any of our own validation at this point, we delegate to the nested
expressions::
- def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False):
+ def resolve_expression(
+ self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False
+ ):
c = self.copy()
c.is_summary = summarize
for pos, expression in enumerate(self.expressions):
- c.expressions[pos] = expression.resolve_expression(query, allow_joins, reuse, summarize, for_save)
+ c.expressions[pos] = expression.resolve_expression(
+ query, allow_joins, reuse, summarize, for_save
+ )
return c
Next, we write the method responsible for generating the SQL::
@@ -1170,15 +1177,16 @@ Next, we write the method responsible for generating the SQL::
sql_expressions.append(sql)
sql_params.extend(params)
template = template or self.template
- data = {'expressions': ','.join(sql_expressions)}
+ data = {"expressions": ",".join(sql_expressions)}
return template % data, sql_params
+
def as_oracle(self, compiler, connection):
"""
Example of vendor specific handling (Oracle in this case).
Let's make the function name lowercase.
"""
- return self.as_sql(compiler, connection, template='coalesce( %(expressions)s )')
+ return self.as_sql(compiler, connection, template="coalesce( %(expressions)s )")
``as_sql()`` methods can support custom keyword arguments, allowing
``as_vendorname()`` methods to override data used to generate the SQL string.
@@ -1203,6 +1211,7 @@ to play nice with other query expressions::
def get_source_expressions(self):
return self.expressions
+
def set_source_expressions(self, expressions):
self.expressions = expressions
@@ -1212,12 +1221,11 @@ Let's see how it works:
>>> from django.db.models import F, Value, CharField
>>> qs = Company.objects.annotate(
- ... tagline=Coalesce([
- ... F('motto'),
- ... F('ticker_name'),
- ... F('description'),
- ... Value('No Tagline')
- ... ], output_field=CharField()))
+ ... tagline=Coalesce(
+ ... [F("motto"), F("ticker_name"), F("description"), Value("No Tagline")],
+ ... output_field=CharField(),
+ ... )
+ ... )
>>> for c in qs:
... print("%s: %s" % (c.name, c.tagline))
...
@@ -1241,8 +1249,9 @@ SQL injection::
from django.db.models import Func
+
class Position(Func):
- function = 'POSITION'
+ function = "POSITION"
template = "%(function)s('%(substring)s' in %(expressions)s)"
def __init__(self, expression, substring):
@@ -1256,8 +1265,8 @@ interpolated into the SQL string before the query is sent to the database.
Here's a corrected rewrite::
class Position(Func):
- function = 'POSITION'
- arg_joiner = ' IN '
+ function = "POSITION"
+ arg_joiner = " IN "
def __init__(self, expression, substring):
super().__init__(substring, expression)
@@ -1279,8 +1288,10 @@ class::
from django.db.models.functions import Length
+
def sqlserver_length(self, compiler, connection):
- return self.as_sql(compiler, connection, function='LEN')
+ return self.as_sql(compiler, connection, function="LEN")
+
Length.as_sqlserver = sqlserver_length
diff --git a/docs/ref/models/fields.txt b/docs/ref/models/fields.txt
index c449a1381c..c1267507b2 100644
--- a/docs/ref/models/fields.txt
+++ b/docs/ref/models/fields.txt
@@ -96,11 +96,11 @@ The first element in each tuple is the actual value to be set on the model,
and the second element is the human-readable name. For example::
YEAR_IN_SCHOOL_CHOICES = [
- ('FR', 'Freshman'),
- ('SO', 'Sophomore'),
- ('JR', 'Junior'),
- ('SR', 'Senior'),
- ('GR', 'Graduate'),
+ ("FR", "Freshman"),
+ ("SO", "Sophomore"),
+ ("JR", "Junior"),
+ ("SR", "Senior"),
+ ("GR", "Graduate"),
]
Generally, it's best to define choices inside a model class, and to
@@ -108,18 +108,19 @@ define a suitably-named constant for each value::
from django.db import models
+
class Student(models.Model):
- FRESHMAN = 'FR'
- SOPHOMORE = 'SO'
- JUNIOR = 'JR'
- SENIOR = 'SR'
- GRADUATE = 'GR'
+ FRESHMAN = "FR"
+ SOPHOMORE = "SO"
+ JUNIOR = "JR"
+ SENIOR = "SR"
+ GRADUATE = "GR"
YEAR_IN_SCHOOL_CHOICES = [
- (FRESHMAN, 'Freshman'),
- (SOPHOMORE, 'Sophomore'),
- (JUNIOR, 'Junior'),
- (SENIOR, 'Senior'),
- (GRADUATE, 'Graduate'),
+ (FRESHMAN, "Freshman"),
+ (SOPHOMORE, "Sophomore"),
+ (JUNIOR, "Junior"),
+ (SENIOR, "Senior"),
+ (GRADUATE, "Graduate"),
]
year_in_school = models.CharField(
max_length=2,
@@ -142,17 +143,21 @@ You can also collect your available choices into named groups that can
be used for organizational purposes::
MEDIA_CHOICES = [
- ('Audio', (
- ('vinyl', 'Vinyl'),
- ('cd', 'CD'),
- )
+ (
+ "Audio",
+ (
+ ("vinyl", "Vinyl"),
+ ("cd", "CD"),
+ ),
),
- ('Video', (
- ('vhs', 'VHS Tape'),
- ('dvd', 'DVD'),
- )
+ (
+ "Video",
+ (
+ ("vhs", "VHS Tape"),
+ ("dvd", "DVD"),
+ ),
),
- ('unknown', 'Unknown'),
+ ("unknown", "Unknown"),
]
The first element in each tuple is the name to apply to the group. The
@@ -194,14 +199,14 @@ choices in a concise way::
from django.utils.translation import gettext_lazy as _
- class Student(models.Model):
+ class Student(models.Model):
class YearInSchool(models.TextChoices):
- FRESHMAN = 'FR', _('Freshman')
- SOPHOMORE = 'SO', _('Sophomore')
- JUNIOR = 'JR', _('Junior')
- SENIOR = 'SR', _('Senior')
- GRADUATE = 'GR', _('Graduate')
+ FRESHMAN = "FR", _("Freshman")
+ SOPHOMORE = "SO", _("Sophomore")
+ JUNIOR = "JR", _("Junior")
+ SENIOR = "SR", _("Senior")
+ GRADUATE = "GR", _("Graduate")
year_in_school = models.CharField(
max_length=2,
@@ -254,9 +259,9 @@ title-case):
.. code-block:: pycon
>>> class Vehicle(models.TextChoices):
- ... CAR = 'C'
- ... TRUCK = 'T'
- ... JET_SKI = 'J'
+ ... CAR = "C"
+ ... TRUCK = "T"
+ ... JET_SKI = "J"
...
>>> Vehicle.JET_SKI.label
'Jet Ski'
@@ -265,7 +270,6 @@ Since the case where the enum values need to be integers is extremely common,
Django provides an ``IntegerChoices`` class. For example::
class Card(models.Model):
-
class Suit(models.IntegerChoices):
DIAMOND = 1
SPADE = 2
@@ -280,10 +284,10 @@ that labels are automatically generated as highlighted above:
.. code-block:: pycon
- >>> MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
+ >>> MedalType = models.TextChoices("MedalType", "GOLD SILVER BRONZE")
>>> MedalType.choices
[('GOLD', 'Gold'), ('SILVER', 'Silver'), ('BRONZE', 'Bronze')]
- >>> Place = models.IntegerChoices('Place', 'FIRST SECOND THIRD')
+ >>> Place = models.IntegerChoices("Place", "FIRST SECOND THIRD")
>>> Place.choices
[(1, 'First'), (2, 'Second'), (3, 'Third')]
@@ -294,12 +298,12 @@ you can subclass ``Choices`` and the required concrete data type, e.g.
:class:`~datetime.date` for use with :class:`~django.db.models.DateField`::
class MoonLandings(datetime.date, models.Choices):
- APOLLO_11 = 1969, 7, 20, 'Apollo 11 (Eagle)'
- APOLLO_12 = 1969, 11, 19, 'Apollo 12 (Intrepid)'
- APOLLO_14 = 1971, 2, 5, 'Apollo 14 (Antares)'
- APOLLO_15 = 1971, 7, 30, 'Apollo 15 (Falcon)'
- APOLLO_16 = 1972, 4, 21, 'Apollo 16 (Orion)'
- APOLLO_17 = 1972, 12, 11, 'Apollo 17 (Challenger)'
+ APOLLO_11 = 1969, 7, 20, "Apollo 11 (Eagle)"
+ APOLLO_12 = 1969, 11, 19, "Apollo 12 (Intrepid)"
+ APOLLO_14 = 1971, 2, 5, "Apollo 14 (Antares)"
+ APOLLO_15 = 1971, 7, 30, "Apollo 15 (Falcon)"
+ APOLLO_16 = 1972, 4, 21, "Apollo 16 (Orion)"
+ APOLLO_17 = 1972, 12, 11, "Apollo 17 (Challenger)"
There are some additional caveats to be aware of:
@@ -311,10 +315,10 @@ There are some additional caveats to be aware of:
set the ``__empty__`` attribute on the class::
class Answer(models.IntegerChoices):
- NO = 0, _('No')
- YES = 1, _('Yes')
+ NO = 0, _("No")
+ YES = 1, _("Yes")
- __empty__ = _('(Unknown)')
+ __empty__ = _("(Unknown)")
``db_column``
-------------
@@ -386,6 +390,7 @@ callable. For example, if you want to specify a default ``dict`` for
def contact_default():
return {"email": "to1@example.com"}
+
contact_info = JSONField("ContactInfo", default=contact_default)
``lambda``\s can't be used for field options like ``default`` because they
@@ -437,7 +442,7 @@ Note that this value is *not* HTML-escaped in automatically-generated
forms. This lets you include HTML in :attr:`~Field.help_text` if you so
desire. For example::
- help_text="Please use the following format: <em>YYYY-MM-DD</em>."
+ help_text = "Please use the following format: <em>YYYY-MM-DD</em>."
Alternatively you can use plain text and
:func:`django.utils.html.escape` to escape any HTML special characters. Ensure
@@ -822,10 +827,10 @@ Has the following optional arguments:
class MyModel(models.Model):
# file will be uploaded to MEDIA_ROOT/uploads
- upload = models.FileField(upload_to='uploads/')
+ upload = models.FileField(upload_to="uploads/")
# or...
# file will be saved to MEDIA_ROOT/uploads/2015/01/30
- upload = models.FileField(upload_to='uploads/%Y/%m/%d/')
+ upload = models.FileField(upload_to="uploads/%Y/%m/%d/")
If you are using the default
:class:`~django.core.files.storage.FileSystemStorage`, the string value
@@ -861,7 +866,8 @@ Has the following optional arguments:
def user_directory_path(instance, filename):
# file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
- return 'user_{0}/{1}'.format(instance.user.id, filename)
+ return "user_{0}/{1}".format(instance.user.id, filename)
+
class MyModel(models.Model):
upload = models.FileField(upload_to=user_directory_path)
@@ -1023,13 +1029,15 @@ You can construct a :class:`~django.core.files.File` from an existing
Python file object like this::
from django.core.files import File
+
# Open an existing file using Python's built-in open()
- f = open('/path/to/hello.world')
+ f = open("/path/to/hello.world")
myfile = File(f)
Or you can construct one from a Python string like this::
from django.core.files.base import ContentFile
+
myfile = ContentFile("hello world")
For more information, see :doc:`/topics/files`.
@@ -1072,8 +1080,10 @@ directory on the filesystem. Has some special arguments, of which the first is
from django.conf import settings
from django.db import models
+
def images_path():
- return os.path.join(settings.LOCAL_FILE_DIR, 'images')
+ return os.path.join(settings.LOCAL_FILE_DIR, "images")
+
class MyModel(models.Model):
file = models.FilePathField(path=images_path)
@@ -1423,6 +1433,7 @@ it is recommended to use :attr:`~Field.default`::
import uuid
from django.db import models
+
class MyUUIDModel(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
# other fields
@@ -1470,13 +1481,15 @@ you can use the name of the model, rather than the model object itself::
from django.db import models
+
class Car(models.Model):
manufacturer = models.ForeignKey(
- 'Manufacturer',
+ "Manufacturer",
on_delete=models.CASCADE,
)
# ...
+
class Manufacturer(models.Model):
# ...
pass
@@ -1490,8 +1503,9 @@ concrete model and are not relative to the abstract model's ``app_label``:
from django.db import models
+
class AbstractCar(models.Model):
- manufacturer = models.ForeignKey('Manufacturer', on_delete=models.CASCADE)
+ manufacturer = models.ForeignKey("Manufacturer", on_delete=models.CASCADE)
class Meta:
abstract = True
@@ -1502,12 +1516,15 @@ concrete model and are not relative to the abstract model's ``app_label``:
from django.db import models
from products.models import AbstractCar
+
class Manufacturer(models.Model):
pass
+
class Car(AbstractCar):
pass
+
# Car.manufacturer will point to `production.Manufacturer` here.
To refer to models defined in another application, you can explicitly specify
@@ -1517,7 +1534,7 @@ need to use::
class Car(models.Model):
manufacturer = models.ForeignKey(
- 'production.Manufacturer',
+ "production.Manufacturer",
on_delete=models.CASCADE,
)
@@ -1599,9 +1616,11 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in
class Artist(models.Model):
name = models.CharField(max_length=10)
+
class Album(models.Model):
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
+
class Song(models.Model):
artist = models.ForeignKey(Artist, on_delete=models.CASCADE)
album = models.ForeignKey(Album, on_delete=models.RESTRICT)
@@ -1612,8 +1631,8 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in
.. code-block:: pycon
- >>> artist_one = Artist.objects.create(name='artist one')
- >>> artist_two = Artist.objects.create(name='artist two')
+ >>> artist_one = Artist.objects.create(name="artist one")
+ >>> artist_two = Artist.objects.create(name="artist two")
>>> album_one = Album.objects.create(artist=artist_one)
>>> album_two = Album.objects.create(artist=artist_two)
>>> song_one = Song.objects.create(artist=artist_one, album=album_one)
@@ -1647,8 +1666,10 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in
from django.contrib.auth import get_user_model
from django.db import models
+
def get_sentinel_user():
- return get_user_model().objects.get_or_create(username='deleted')[0]
+ return get_user_model().objects.get_or_create(username="deleted")[0]
+
class MyModel(models.Model):
user = models.ForeignKey(
@@ -1675,7 +1696,7 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in
staff_member = models.ForeignKey(
User,
on_delete=models.CASCADE,
- limit_choices_to={'is_staff': True},
+ limit_choices_to={"is_staff": True},
)
causes the corresponding field on the ``ModelForm`` to list only ``Users``
@@ -1686,7 +1707,8 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in
example::
def limit_pub_date_choices():
- return {'pub_date__lte': datetime.date.today()}
+ return {"pub_date__lte": datetime.date.today()}
+
limit_choices_to = limit_pub_date_choices
@@ -1724,7 +1746,7 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
- related_name='+',
+ related_name="+",
)
.. attribute:: ForeignKey.related_query_name
@@ -1744,6 +1766,7 @@ The possible values for :attr:`~ForeignKey.on_delete` are found in
)
name = models.CharField(max_length=255)
+
# That's now the name of the reverse filter
Article.objects.filter(tag__name="important")
@@ -1841,6 +1864,7 @@ that control how the relationship functions.
from django.db import models
+
class Person(models.Model):
friends = models.ManyToManyField("self")
@@ -1918,17 +1942,20 @@ that control how the relationship functions.
from django.db import models
+
class Person(models.Model):
name = models.CharField(max_length=50)
+
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(
Person,
- through='Membership',
- through_fields=('group', 'person'),
+ through="Membership",
+ through_fields=("group", "person"),
)
+
class Membership(models.Model):
group = models.ForeignKey(Group, on_delete=models.CASCADE)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
@@ -2027,6 +2054,7 @@ With the following example::
from django.conf import settings
from django.db import models
+
class MySpecialUser(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
@@ -2035,7 +2063,7 @@ With the following example::
supervisor = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
- related_name='supervisor_of',
+ related_name="supervisor_of",
)
your resulting ``User`` model will have the following attributes:
@@ -2043,9 +2071,9 @@ your resulting ``User`` model will have the following attributes:
.. code-block:: pycon
>>> user = User.objects.get(pk=1)
- >>> hasattr(user, 'myspecialuser')
+ >>> hasattr(user, "myspecialuser")
True
- >>> hasattr(user, 'supervisor_of')
+ >>> hasattr(user, "supervisor_of")
True
A ``RelatedObjectDoesNotExist`` exception is raised when accessing the reverse
diff --git a/docs/ref/models/indexes.txt b/docs/ref/models/indexes.txt
index 6d6a454ad4..d23a5fd1ce 100644
--- a/docs/ref/models/indexes.txt
+++ b/docs/ref/models/indexes.txt
@@ -35,14 +35,14 @@ expressions and database functions.
For example::
- Index(Lower('title').desc(), 'pub_date', name='lower_title_date_idx')
+ Index(Lower("title").desc(), "pub_date", name="lower_title_date_idx")
creates an index on the lowercased value of the ``title`` field in descending
order and the ``pub_date`` field in the default ascending order.
Another example::
- Index(F('height') * F('weight'), Round('weight'), name='calc_idx')
+ Index(F("height") * F("weight"), Round("weight"), name="calc_idx")
creates an index on the result of multiplying fields ``height`` and ``weight``
and the ``weight`` rounded to the nearest integer.
@@ -197,7 +197,7 @@ fields (:attr:`~Index.fields`).
For example::
- Index(name='covering_index', fields=['headline'], include=['pub_date'])
+ Index(name="covering_index", fields=["headline"], include=["pub_date"])
will allow filtering on ``headline``, also selecting ``pub_date``, while
fetching data only from the index.
diff --git a/docs/ref/models/instances.txt b/docs/ref/models/instances.txt
index 44ba15c72d..d03b05577c 100644
--- a/docs/ref/models/instances.txt
+++ b/docs/ref/models/instances.txt
@@ -36,6 +36,7 @@ need to :meth:`~Model.save()`.
from django.db import models
+
class Book(models.Model):
title = models.CharField(max_length=100)
@@ -45,6 +46,7 @@ need to :meth:`~Model.save()`.
# do something with the book
return book
+
book = Book.create("Pride and Prejudice")
#. Add a method on a custom manager (usually preferred)::
@@ -55,11 +57,13 @@ need to :meth:`~Model.save()`.
# do something with the book
return book
+
class Book(models.Model):
title = models.CharField(max_length=100)
objects = BookManager()
+
book = Book.objects.create_book("Pride and Prejudice")
Customizing model loading
@@ -88,6 +92,7 @@ are loaded from the database::
from django.db.models import DEFERRED
+
@classmethod
def from_db(cls, db, field_names, values):
# Default implementation of from_db() (subject to change and could
@@ -108,12 +113,14 @@ are loaded from the database::
)
return instance
+
def save(self, *args, **kwargs):
# Check how the current values differ from ._loaded_values. For example,
# prevent changing the creator_id of the model. (This example doesn't
# support cases where 'creator_id' is deferred).
if not self._state.adding and (
- self.creator_id != self._loaded_values['creator_id']):
+ self.creator_id != self._loaded_values["creator_id"]
+ ):
raise ValueError("Updating the value of creator isn't allowed")
super().save(*args, **kwargs)
@@ -163,7 +170,7 @@ update, you could write a test similar to this::
def test_update_result(self):
obj = MyModel.objects.create(val=1)
- MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
+ MyModel.objects.filter(pk=obj.pk).update(val=F("val") + 1)
# At this point obj.val is still 1, but the value in the database
# was updated to 2. The object's updated value needs to be reloaded
# from the database.
@@ -251,6 +258,7 @@ when you want to run one-step model validation for your own manually created
models. For example::
from django.core.exceptions import ValidationError
+
try:
article.full_clean()
except ValidationError as e:
@@ -282,14 +290,16 @@ access to more than a single field::
from django.db import models
from django.utils.translation import gettext_lazy as _
+
class Article(models.Model):
...
+
def clean(self):
# Don't allow draft entries to have a pub_date.
- if self.status == 'draft' and self.pub_date is not None:
- raise ValidationError(_('Draft entries may not have a publication date.'))
+ if self.status == "draft" and self.pub_date is not None:
+ raise ValidationError(_("Draft entries may not have a publication date."))
# Set the pub_date for published items if it hasn't been set already.
- if self.status == 'published' and self.pub_date is None:
+ if self.status == "published" and self.pub_date is None:
self.pub_date = datetime.date.today()
Note, however, that like :meth:`Model.full_clean()`, a model's ``clean()``
@@ -302,6 +312,7 @@ will be stored in a special error dictionary key,
that are tied to the entire model instead of to a specific field::
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
+
try:
article.full_clean()
except ValidationError as e:
@@ -314,19 +325,24 @@ error to the ``pub_date`` field::
class Article(models.Model):
...
+
def clean(self):
# Don't allow draft entries to have a pub_date.
- if self.status == 'draft' and self.pub_date is not None:
- raise ValidationError({'pub_date': _('Draft entries may not have a publication date.')})
+ if self.status == "draft" and self.pub_date is not None:
+ raise ValidationError(
+ {"pub_date": _("Draft entries may not have a publication date.")}
+ )
...
If you detect errors in multiple fields during ``Model.clean()``, you can also
pass a dictionary mapping field names to errors::
- raise ValidationError({
- 'title': ValidationError(_('Missing title.'), code='required'),
- 'pub_date': ValidationError(_('Invalid date.'), code='invalid'),
- })
+ raise ValidationError(
+ {
+ "title": ValidationError(_("Missing title."), code="required"),
+ "pub_date": ValidationError(_("Invalid date."), code="invalid"),
+ }
+ )
Then, ``full_clean()`` will check unique constraints on your model.
@@ -344,20 +360,22 @@ Then, ``full_clean()`` will check unique constraints on your model.
class Article(models.Model):
...
+
def clean_fields(self, exclude=None):
super().clean_fields(exclude=exclude)
- if self.status == 'draft' and self.pub_date is not None:
- if exclude and 'status' in exclude:
+ if self.status == "draft" and self.pub_date is not None:
+ if exclude and "status" in exclude:
raise ValidationError(
- _('Draft entries may not have a publication date.')
+ _("Draft entries may not have a publication date.")
)
else:
- raise ValidationError({
- 'status': _(
- 'Set status to draft if there is not a '
- 'publication date.'
- ),
- })
+ raise ValidationError(
+ {
+ "status": _(
+ "Set status to draft if there is not a " "publication date."
+ ),
+ }
+ )
.. method:: Model.validate_unique(exclude=None)
@@ -421,10 +439,10 @@ an attribute on your object the first time you call ``save()``:
.. code-block:: pycon
- >>> b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
- >>> b2.id # Returns None, because b2 doesn't have an ID yet.
+ >>> b2 = Blog(name="Cheddar Talk", tagline="Thoughts on cheese.")
+ >>> b2.id # Returns None, because b2 doesn't have an ID yet.
>>> b2.save()
- >>> b2.id # Returns the ID of your new object.
+ >>> b2.id # Returns the ID of your new object.
There's no way to tell what the value of an ID will be before you call
``save()``, because that value is calculated by your database, not by Django.
@@ -455,10 +473,10 @@ rather than relying on the auto-assignment of the ID:
.. code-block:: pycon
- >>> b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.')
- >>> b3.id # Returns 3.
+ >>> b3 = Blog(id=3, name="Cheddar Talk", tagline="Thoughts on cheese.")
+ >>> b3.id # Returns 3.
>>> b3.save()
- >>> b3.id # Returns 3.
+ >>> b3.id # Returns 3.
If you assign auto-primary-key values manually, make sure not to use an
already-existing primary-key value! If you create a new object with an explicit
@@ -468,7 +486,7 @@ changing the existing record rather than creating a new one.
Given the above ``'Cheddar Talk'`` blog example, this example would override the
previous record in the database::
- b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.')
+ b4 = Blog(id=3, name="Not Cheddar", tagline="Anything but cheese.")
b4.save() # Overrides the previous blog with ID=3!
See `How Django knows to UPDATE vs. INSERT`_, below, for the reason this
@@ -583,7 +601,7 @@ doing the arithmetic in Python like:
.. code-block:: pycon
- >>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
+ >>> product = Product.objects.get(name="Venezuelan Beaver Cheese")
>>> product.number_sold += 1
>>> product.save()
@@ -601,8 +619,8 @@ as:
.. code-block:: pycon
>>> from django.db.models import F
- >>> product = Product.objects.get(name='Venezuelan Beaver Cheese')
- >>> product.number_sold = F('number_sold') + 1
+ >>> product = Product.objects.get(name="Venezuelan Beaver Cheese")
+ >>> product.number_sold = F("number_sold") + 1
>>> product.save()
For more details, see the documentation on :class:`F expressions
@@ -620,8 +638,8 @@ This may be desirable if you want to update just one or a few fields on
an object. There will be a slight performance benefit from preventing
all of the model fields from being updated in the database. For example::
- product.name = 'Name changed again'
- product.save(update_fields=['name'])
+ product.name = "Name changed again"
+ product.save(update_fields=["name"])
The ``update_fields`` argument can be any iterable containing strings. An
empty ``update_fields`` iterable will skip the save. A value of ``None`` will
@@ -714,12 +732,13 @@ For example::
from django.db import models
+
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
- return f'{self.first_name} {self.last_name}'
+ return f"{self.first_name} {self.last_name}"
``__eq__()``
------------
@@ -736,16 +755,20 @@ For example::
from django.db import models
+
class MyModel(models.Model):
id = models.AutoField(primary_key=True)
+
class MyProxyModel(MyModel):
class Meta:
proxy = True
+
class MultitableInherited(MyModel):
pass
+
# Primary keys compared
MyModel(id=1) == MyModel(id=1)
MyModel(id=1) != MyModel(id=2)
@@ -793,7 +816,8 @@ For example::
def get_absolute_url(self):
from django.urls import reverse
- return reverse('people-detail', kwargs={'pk' : self.pk})
+
+ return reverse("people-detail", kwargs={"pk": self.pk})
One place Django uses ``get_absolute_url()`` is in the admin app. If an object
defines this method, the object-editing page will have a "View on site" link
@@ -811,7 +835,7 @@ URL, you should define ``get_absolute_url()``.
reduce possibilities of link or redirect poisoning::
def get_absolute_url(self):
- return '/%s/' % self.name
+ return "/%s/" % self.name
If ``self.name`` is ``'/example.com'`` this returns ``'//example.com/'``
which, in turn, is a valid schema relative URL but not the expected
@@ -863,11 +887,12 @@ For example::
from django.db import models
+
class Person(models.Model):
SHIRT_SIZES = [
- ('S', 'Small'),
- ('M', 'Medium'),
- ('L', 'Large'),
+ ("S", "Small"),
+ ("M", "Medium"),
+ ("L", "Large"),
]
name = models.CharField(max_length=60)
shirt_size = models.CharField(max_length=2, choices=SHIRT_SIZES)
diff --git a/docs/ref/models/lookups.txt b/docs/ref/models/lookups.txt
index d71424c906..3998eb3705 100644
--- a/docs/ref/models/lookups.txt
+++ b/docs/ref/models/lookups.txt
@@ -47,7 +47,7 @@ register lookups on itself or its instances. The two prominent examples are
Registers a new lookup in the class or class instance. For example::
DateField.register_lookup(YearExact)
- User._meta.get_field('date_joined').register_lookup(MonthExact)
+ User._meta.get_field("date_joined").register_lookup(MonthExact)
will register ``YearExact`` lookup on ``DateField`` and ``MonthExact``
lookup on the ``User.date_joined`` (you can use :ref:`Field Access API
@@ -195,11 +195,11 @@ following methods:
``<lhs>__<lookup_name>=<rhs>``. Lookups can also be used directly in
``QuerySet`` filters::
- Book.objects.filter(LessThan(F('word_count'), 7500))
+ Book.objects.filter(LessThan(F("word_count"), 7500))
…or annotations::
- Book.objects.annotate(is_short_story=LessThan(F('word_count'), 7500))
+ Book.objects.annotate(is_short_story=LessThan(F("word_count"), 7500))
.. attribute:: lhs
diff --git a/docs/ref/models/meta.txt b/docs/ref/models/meta.txt
index 251705d84e..a96c563d49 100644
--- a/docs/ref/models/meta.txt
+++ b/docs/ref/models/meta.txt
@@ -49,15 +49,15 @@ Retrieving a single field instance of a model by name
>>> from django.contrib.auth.models import User
# A field on the model
- >>> User._meta.get_field('username')
+ >>> User._meta.get_field("username")
<django.db.models.fields.CharField: username>
# A field from another model that has a relation with the current model
- >>> User._meta.get_field('logentry')
+ >>> User._meta.get_field("logentry")
<ManyToOneRel: admin.logentry>
# A non existent field
- >>> User._meta.get_field('does_not_exist')
+ >>> User._meta.get_field("does_not_exist")
Traceback (most recent call last):
...
FieldDoesNotExist: User has no field named 'does_not_exist'
diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt
index 4426e8bfcd..06bf09fba0 100644
--- a/docs/ref/models/options.txt
+++ b/docs/ref/models/options.txt
@@ -27,7 +27,7 @@ Available ``Meta`` options
If a model is defined outside of an application in
:setting:`INSTALLED_APPS`, it must declare which app it belongs to::
- app_label = 'myapp'
+ app_label = "myapp"
If you want to represent a model with the format ``app_label.object_name``
or ``app_label.model_name`` you can use ``model._meta.label``
@@ -48,7 +48,7 @@ Available ``Meta`` options
The name of the database table to use for the model::
- db_table = 'music_album'
+ db_table = "music_album"
.. _table-names:
@@ -161,7 +161,7 @@ not be looking at your Django code. For example::
get_latest_by = "order_date"
# Latest by priority descending, order_date ascending.
- get_latest_by = ['-priority', 'order_date']
+ get_latest_by = ["-priority", "order_date"]
See the :meth:`~django.db.models.query.QuerySet.latest` docs for more.
@@ -218,16 +218,18 @@ not be looking at your Django code. For example::
from django.db import models
+
class Question(models.Model):
text = models.TextField()
# ...
+
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
# ...
class Meta:
- order_with_respect_to = 'question'
+ order_with_respect_to = "question"
When ``order_with_respect_to`` is set, two additional methods are provided to
retrieve and to set the order of the related objects: ``get_RELATED_order()``
@@ -283,7 +285,7 @@ not be looking at your Django code. For example::
The default ordering for the object, for use when obtaining lists of objects::
- ordering = ['-order_date']
+ ordering = ["-order_date"]
This is a tuple or list of strings and/or query expressions. Each string is
a field name with an optional "-" prefix, which indicates descending order.
@@ -292,22 +294,22 @@ not be looking at your Django code. For example::
For example, to order by a ``pub_date`` field ascending, use this::
- ordering = ['pub_date']
+ ordering = ["pub_date"]
To order by ``pub_date`` descending, use this::
- ordering = ['-pub_date']
+ ordering = ["-pub_date"]
To order by ``pub_date`` descending, then by ``author`` ascending, use this::
- ordering = ['-pub_date', 'author']
+ ordering = ["-pub_date", "author"]
You can also use :doc:`query expressions </ref/models/expressions>`. To
order by ``author`` ascending and make null values sort last, use this::
from django.db.models import F
- ordering = [F('author').asc(nulls_last=True)]
+ ordering = [F("author").asc(nulls_last=True)]
.. warning::
@@ -330,7 +332,7 @@ not be looking at your Django code. For example::
Add, change, delete, and view permissions are automatically created for each
model. This example specifies an extra permission, ``can_deliver_pizzas``::
- permissions = [('can_deliver_pizzas', 'Can deliver pizzas')]
+ permissions = [("can_deliver_pizzas", "Can deliver pizzas")]
This is a list or tuple of 2-tuples in the format ``(permission_code,
human_readable_permission_name)``.
@@ -406,14 +408,15 @@ not be looking at your Django code. For example::
from django.db import models
+
class Customer(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
class Meta:
indexes = [
- models.Index(fields=['last_name', 'first_name']),
- models.Index(fields=['first_name'], name='first_name_idx'),
+ models.Index(fields=["last_name", "first_name"]),
+ models.Index(fields=["first_name"], name="first_name_idx"),
]
``unique_together``
@@ -429,7 +432,7 @@ not be looking at your Django code. For example::
Sets of field names that, taken together, must be unique::
- unique_together = [['driver', 'restaurant']]
+ unique_together = [["driver", "restaurant"]]
This is a list of lists that must be unique when considered together.
It's used in the Django admin and is enforced at the database level (i.e., the
@@ -439,7 +442,7 @@ not be looking at your Django code. For example::
For convenience, ``unique_together`` can be a single list when dealing with
a single set of fields::
- unique_together = ['driver', 'restaurant']
+ unique_together = ["driver", "restaurant"]
A :class:`~django.db.models.ManyToManyField` cannot be included in
unique_together. (It's not clear what that would even mean!) If you
@@ -483,12 +486,13 @@ not be looking at your Django code. For example::
from django.db import models
+
class Customer(models.Model):
age = models.IntegerField()
class Meta:
constraints = [
- models.CheckConstraint(check=models.Q(age__gte=18), name='age_gte_18'),
+ models.CheckConstraint(check=models.Q(age__gte=18), name="age_gte_18"),
]
``verbose_name``
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index 3cb1011727..65fe805b2e 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -38,7 +38,7 @@ You can evaluate a ``QuerySet`` in the following ways:
``async for``::
async for e in Entry.objects.all():
- results.append(e)
+ results.append(e)
Both synchronous and asynchronous iterators of QuerySets share the same
underlying cache.
@@ -82,7 +82,7 @@ You can evaluate a ``QuerySet`` in the following ways:
``True``, otherwise ``False``. For example::
if Entry.objects.filter(headline="Test"):
- print("There is at least one Entry with the headline Test")
+ print("There is at least one Entry with the headline Test")
Note: If you only want to determine if at least one result exists (and don't
need the actual objects), it's more efficient to use :meth:`~QuerySet.exists`.
@@ -108,9 +108,9 @@ any results loaded) using some code like this:
.. code-block:: pycon
>>> import pickle
- >>> query = pickle.loads(s) # Assuming 's' is the pickled string.
+ >>> query = pickle.loads(s) # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
- >>> qs.query = query # Restore the original 'query'.
+ >>> qs.query = query # Restore the original 'query'.
The ``query`` attribute is an opaque object. It represents the internals of
the query construction and is not part of the public API. However, it is safe
@@ -125,7 +125,7 @@ described here.
.. code-block:: pycon
>>> import pickle
- >>> qs = Blog.objects.values_list('id', 'name')
+ >>> qs = Blog.objects.values_list("id", "name")
>>> qs
<QuerySet [(1, 'Beatles Blog')]>
>>> reloaded_qs = Blog.objects.all()
@@ -225,7 +225,7 @@ underlying SQL statement, and the whole thing is enclosed in a ``NOT()``.
This example excludes all entries whose ``pub_date`` is later than 2005-1-3
AND whose ``headline`` is "Hello"::
- Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
+ Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline="Hello")
In SQL terms, that evaluates to:
@@ -237,7 +237,7 @@ In SQL terms, that evaluates to:
This example excludes all entries whose ``pub_date`` is later than 2005-1-3
OR whose headline is "Hello"::
- Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
+ Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline="Hello")
In SQL terms, that evaluates to:
@@ -282,7 +282,7 @@ to determine how many entries have been made in each blog:
.. code-block:: pycon
>>> from django.db.models import Count
- >>> q = Blog.objects.annotate(Count('entry'))
+ >>> q = Blog.objects.annotate(Count("entry"))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
@@ -296,7 +296,7 @@ control the name of the annotation:
.. code-block:: pycon
- >>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
+ >>> q = Blog.objects.annotate(number_of_entries=Count("entry"))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42
@@ -322,16 +322,16 @@ interested in the exact number of entries, you could do this:
.. code-block:: pycon
>>> from django.db.models import Count
- >>> blogs = Blog.objects.alias(entries=Count('entry')).filter(entries__gt=5)
+ >>> blogs = Blog.objects.alias(entries=Count("entry")).filter(entries__gt=5)
``alias()`` can be used in conjunction with :meth:`annotate`, :meth:`exclude`,
:meth:`filter`, :meth:`order_by`, and :meth:`update`. To use aliased expression
with other methods (e.g. :meth:`aggregate`), you must promote it to an
annotation::
- Blog.objects.alias(entries=Count('entry')).annotate(
- entries=F('entries'),
- ).aggregate(Sum('entries'))
+ Blog.objects.alias(entries=Count("entry")).annotate(
+ entries=F("entries"),
+ ).aggregate(Sum("entries"))
:meth:`filter` and :meth:`order_by` can take expressions directly, but
expression construction and usage often does not happen in the same place (for
@@ -351,14 +351,14 @@ override this on a per-``QuerySet`` basis by using the ``order_by`` method.
Example::
- Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
+ Entry.objects.filter(pub_date__year=2005).order_by("-pub_date", "headline")
The result above will be ordered by ``pub_date`` descending, then by
``headline`` ascending. The negative sign in front of ``"-pub_date"`` indicates
*descending* order. Ascending order is implied. To order randomly, use ``"?"``,
like so::
- Entry.objects.order_by('?')
+ Entry.objects.order_by("?")
Note: ``order_by('?')`` queries may be expensive and slow, depending on the
database backend you're using.
@@ -368,7 +368,7 @@ querying across model relations. That is, the name of the field, followed by a
double underscore (``__``), followed by the name of the field in the new model,
and so on for as many models as you want to join. For example::
- Entry.objects.order_by('blog__name', 'headline')
+ Entry.objects.order_by("blog__name", "headline")
If you try to order by a field that is a relation to another model, Django will
use the default ordering on the related model, or order by the related model's
@@ -376,22 +376,22 @@ primary key if there is no :attr:`Meta.ordering
<django.db.models.Options.ordering>` specified. For example, since the ``Blog``
model has no default ordering specified::
- Entry.objects.order_by('blog')
+ Entry.objects.order_by("blog")
...is identical to::
- Entry.objects.order_by('blog__id')
+ Entry.objects.order_by("blog__id")
If ``Blog`` had ``ordering = ['name']``, then the first queryset would be
identical to::
- Entry.objects.order_by('blog__name')
+ Entry.objects.order_by("blog__name")
You can also order by :doc:`query expressions </ref/models/expressions>` by
calling :meth:`~.Expression.asc` or :meth:`~.Expression.desc` on the
expression::
- Entry.objects.order_by(Coalesce('summary', 'headline').desc())
+ Entry.objects.order_by(Coalesce("summary", "headline").desc())
:meth:`~.Expression.asc` and :meth:`~.Expression.desc` have arguments
(``nulls_first`` and ``nulls_last``) that control how null values are sorted.
@@ -408,14 +408,15 @@ related model ordering can change the expected results.
Consider this case::
class Event(Model):
- parent = models.ForeignKey(
- 'self',
- on_delete=models.CASCADE,
- related_name='children',
- )
- date = models.DateField()
+ parent = models.ForeignKey(
+ "self",
+ on_delete=models.CASCADE,
+ related_name="children",
+ )
+ date = models.DateField()
+
- Event.objects.order_by('children__date')
+ Event.objects.order_by("children__date")
Here, there could potentially be multiple ordering data for each ``Event``;
each ``Event`` with multiple ``children`` will be returned multiple times
@@ -437,7 +438,7 @@ You can order by a field converted to lowercase with
:class:`~django.db.models.functions.Lower` which will achieve case-consistent
ordering::
- Entry.objects.order_by(Lower('headline').desc())
+ Entry.objects.order_by(Lower("headline").desc())
If you don't want any ordering to be applied to a query, not even the default
ordering, call :meth:`order_by()` with no parameters.
@@ -449,7 +450,7 @@ You can tell if a query is ordered or not by checking the
Each ``order_by()`` call will clear any previous ordering. For example, this
query will be ordered by ``pub_date`` and not ``headline``::
- Entry.objects.order_by('headline').order_by('pub_date')
+ Entry.objects.order_by("headline").order_by("pub_date")
.. warning::
@@ -545,19 +546,19 @@ Examples (those after the first will only work on PostgreSQL):
>>> Author.objects.distinct()
[...]
- >>> Entry.objects.order_by('pub_date').distinct('pub_date')
+ >>> Entry.objects.order_by("pub_date").distinct("pub_date")
[...]
- >>> Entry.objects.order_by('blog').distinct('blog')
+ >>> Entry.objects.order_by("blog").distinct("blog")
[...]
- >>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
+ >>> Entry.objects.order_by("author", "pub_date").distinct("author", "pub_date")
[...]
- >>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
+ >>> Entry.objects.order_by("blog__name", "mod_date").distinct("blog__name", "mod_date")
[...]
- >>> Entry.objects.order_by('author', 'pub_date').distinct('author')
+ >>> Entry.objects.order_by("author", "pub_date").distinct("author")
[...]
.. note::
@@ -568,7 +569,7 @@ Examples (those after the first will only work on PostgreSQL):
the ``Blog`` model defined an :attr:`~django.db.models.Options.ordering` by
``name``::
- Entry.objects.order_by('blog').distinct('blog')
+ Entry.objects.order_by("blog").distinct("blog")
...wouldn't work because the query would be ordered by ``blog__name`` thus
mismatching the ``DISTINCT ON`` expression. You'd have to explicitly order
@@ -592,11 +593,11 @@ objects:
.. code-block:: pycon
# This list contains a Blog object.
- >>> Blog.objects.filter(name__startswith='Beatles')
+ >>> Blog.objects.filter(name__startswith="Beatles")
<QuerySet [<Blog: Beatles Blog>]>
# This list contains a dictionary.
- >>> Blog.objects.filter(name__startswith='Beatles').values()
+ >>> Blog.objects.filter(name__startswith="Beatles").values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
The ``values()`` method takes optional positional arguments, ``*fields``, which
@@ -611,7 +612,7 @@ Example:
>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
- >>> Blog.objects.values('id', 'name')
+ >>> Blog.objects.values("id", "name")
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>
The ``values()`` method also takes optional keyword arguments,
@@ -620,7 +621,7 @@ The ``values()`` method also takes optional keyword arguments,
.. code-block:: pycon
>>> from django.db.models.functions import Lower
- >>> Blog.objects.values(lower_name=Lower('name'))
+ >>> Blog.objects.values(lower_name=Lower("name"))
<QuerySet [{'lower_name': 'beatles blog'}]>
You can use built-in and :doc:`custom lookups </howto/custom-lookups>` in
@@ -631,7 +632,7 @@ ordering. For example:
>>> from django.db.models import CharField
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
- >>> Blog.objects.values('name__lower')
+ >>> Blog.objects.values("name__lower")
<QuerySet [{'name__lower': 'beatles blog'}]>
An aggregate within a ``values()`` clause is applied before other arguments
@@ -641,9 +642,9 @@ add it to an earlier ``values()`` clause instead. For example:
.. code-block:: pycon
>>> from django.db.models import Count
- >>> Blog.objects.values('entry__authors', entries=Count('entry'))
+ >>> Blog.objects.values("entry__authors", entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 20}, {'entry__authors': 1, 'entries': 13}]>
- >>> Blog.objects.values('entry__authors').annotate(entries=Count('entry'))
+ >>> Blog.objects.values("entry__authors").annotate(entries=Count("entry"))
<QuerySet [{'entry__authors': 1, 'entries': 33}]>
A few subtleties that are worth mentioning:
@@ -664,10 +665,10 @@ A few subtleties that are worth mentioning:
>>> Entry.objects.values()
<QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]>
- >>> Entry.objects.values('blog')
+ >>> Entry.objects.values("blog")
<QuerySet [{'blog': 1}, ...]>
- >>> Entry.objects.values('blog_id')
+ >>> Entry.objects.values("blog_id")
<QuerySet [{'blog_id': 1}, ...]>
* When using ``values()`` together with :meth:`distinct()`, be aware that
@@ -693,15 +694,15 @@ A few subtleties that are worth mentioning:
>>> from django.db.models import CharField, Count
>>> from django.db.models.functions import Lower
>>> CharField.register_lookup(Lower)
- >>> Blog.objects.values('entry__authors__name__lower').annotate(entries=Count('entry'))
+ >>> Blog.objects.values("entry__authors__name__lower").annotate(entries=Count("entry"))
<QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
- >>> Blog.objects.values(
- ... entry__authors__name__lower=Lower('entry__authors__name')
- ... ).annotate(entries=Count('entry'))
+ >>> Blog.objects.values(entry__authors__name__lower=Lower("entry__authors__name")).annotate(
+ ... entries=Count("entry")
+ ... )
<QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
- >>> Blog.objects.annotate(
- ... entry__authors__name__lower=Lower('entry__authors__name')
- ... ).values('entry__authors__name__lower').annotate(entries=Count('entry'))
+ >>> Blog.objects.annotate(entry__authors__name__lower=Lower("entry__authors__name")).values(
+ ... "entry__authors__name__lower"
+ ... ).annotate(entries=Count("entry"))
<QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
It is useful when you know you're only going to need values from a small number
@@ -711,8 +712,8 @@ instance object. It's more efficient to select only the fields you need to use.
Finally, note that you can call ``filter()``, ``order_by()``, etc. after the
``values()`` call, that means that these two calls are identical::
- Blog.objects.values().order_by('id')
- Blog.objects.order_by('id').values()
+ Blog.objects.values().order_by("id")
+ Blog.objects.order_by("id").values()
The people who made Django prefer to put all the SQL-affecting methods first,
followed (optionally) by any output-affecting methods (such as ``values()``),
@@ -724,7 +725,7 @@ You can also refer to fields on related models with reverse relations through
.. code-block:: pycon
- >>> Blog.objects.values('name', 'entry__headline')
+ >>> Blog.objects.values("name", "entry__headline")
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
{'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>
@@ -756,10 +757,10 @@ first item is the first field, etc. For example:
.. code-block:: pycon
- >>> Entry.objects.values_list('id', 'headline')
+ >>> Entry.objects.values_list("id", "headline")
<QuerySet [(1, 'First entry'), ...]>
>>> from django.db.models.functions import Lower
- >>> Entry.objects.values_list('id', Lower('headline'))
+ >>> Entry.objects.values_list("id", Lower("headline"))
<QuerySet [(1, 'first entry'), ...]>
If you only pass in a single field, you can also pass in the ``flat``
@@ -768,10 +769,10 @@ rather than one-tuples. An example should make the difference clearer:
.. code-block:: pycon
- >>> Entry.objects.values_list('id').order_by('id')
+ >>> Entry.objects.values_list("id").order_by("id")
<QuerySet[(1,), (2,), (3,), ...]>
- >>> Entry.objects.values_list('id', flat=True).order_by('id')
+ >>> Entry.objects.values_list("id", flat=True).order_by("id")
<QuerySet [1, 2, 3, ...]>
It is an error to pass in ``flat`` when there is more than one field.
@@ -781,7 +782,7 @@ You can pass ``named=True`` to get results as a
.. code-block:: pycon
- >>> Entry.objects.values_list('id', 'headline', named=True)
+ >>> Entry.objects.values_list("id", "headline", named=True)
<QuerySet [Row(id=1, headline='First entry'), ...]>
Using a named tuple may make use of the results more readable, at the expense
@@ -795,7 +796,7 @@ achieve that, use ``values_list()`` followed by a ``get()`` call:
.. code-block:: pycon
- >>> Entry.objects.values_list('headline', flat=True).get(pk=1)
+ >>> Entry.objects.values_list("headline", flat=True).get(pk=1)
'First entry'
``values()`` and ``values_list()`` are both intended as optimizations for a
@@ -809,7 +810,7 @@ For example, notice the behavior when querying across a
.. code-block:: pycon
- >>> Author.objects.values_list('name', 'entry__headline')
+ >>> Author.objects.values_list("name", "entry__headline")
<QuerySet [('Noam Chomsky', 'Impressions of Gaza'),
('George Orwell', 'Why Socialists Do Not Believe in Fun'),
('George Orwell', 'In Defence of English Cooking'),
@@ -823,7 +824,7 @@ not having any author:
.. code-block:: pycon
- >>> Entry.objects.values_list('authors')
+ >>> Entry.objects.values_list("authors")
<QuerySet [('Noam Chomsky',), ('George Orwell',), (None,)]>
.. admonition:: Special values for ``JSONField`` on SQLite
@@ -863,17 +864,17 @@ Examples:
.. code-block:: pycon
- >>> Entry.objects.dates('pub_date', 'year')
+ >>> Entry.objects.dates("pub_date", "year")
[datetime.date(2005, 1, 1)]
- >>> Entry.objects.dates('pub_date', 'month')
+ >>> Entry.objects.dates("pub_date", "month")
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
- >>> Entry.objects.dates('pub_date', 'week')
+ >>> Entry.objects.dates("pub_date", "week")
[datetime.date(2005, 2, 14), datetime.date(2005, 3, 14)]
- >>> Entry.objects.dates('pub_date', 'day')
+ >>> Entry.objects.dates("pub_date", "day")
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
- >>> Entry.objects.dates('pub_date', 'day', order='DESC')
+ >>> Entry.objects.dates("pub_date", "day", order="DESC")
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
- >>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
+ >>> Entry.objects.filter(headline__contains="Lennon").dates("pub_date", "day")
[datetime.date(2005, 3, 20)]
``datetimes()``
@@ -977,9 +978,9 @@ resulting ``QuerySet``. For example:
.. code-block:: pycon
- >>> qs1 = Author.objects.values_list('name')
- >>> qs2 = Entry.objects.values_list('headline')
- >>> qs1.union(qs2).order_by('name')
+ >>> qs1 = Author.objects.values_list("name")
+ >>> qs2 = Entry.objects.values_list("headline")
+ >>> qs1.union(qs2).order_by("name")
In addition, only ``LIMIT``, ``OFFSET``, ``COUNT(*)``, ``ORDER BY``, and
specifying columns (i.e. slicing, :meth:`count`, :meth:`exists`,
@@ -1036,7 +1037,7 @@ The following examples illustrate the difference between plain lookups and
And here's ``select_related`` lookup::
# Hits the database.
- e = Entry.objects.select_related('blog').get(id=5)
+ e = Entry.objects.select_related("blog").get(id=5)
# Doesn't hit the database, because e.blog has been prepopulated
# in the previous query.
@@ -1049,7 +1050,7 @@ You can use ``select_related()`` with any queryset of objects::
# Find all the blogs with entries scheduled to be published in the future.
blogs = set()
- for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog'):
+ for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related("blog"):
# Without select_related(), this would make a database query for each
# loop iteration in order to fetch the related blog for each entry.
blogs.add(e.blog)
@@ -1057,18 +1058,20 @@ You can use ``select_related()`` with any queryset of objects::
The order of ``filter()`` and ``select_related()`` chaining isn't important.
These querysets are equivalent::
- Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog')
- Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())
+ Entry.objects.filter(pub_date__gt=timezone.now()).select_related("blog")
+ Entry.objects.select_related("blog").filter(pub_date__gt=timezone.now())
You can follow foreign keys in a similar way to querying them. If you have the
following models::
from django.db import models
+
class City(models.Model):
# ...
pass
+
class Person(models.Model):
# ...
hometown = models.ForeignKey(
@@ -1078,6 +1081,7 @@ following models::
null=True,
)
+
class Book(models.Model):
# ...
author = models.ForeignKey(Person, on_delete=models.CASCADE)
@@ -1086,14 +1090,14 @@ following models::
will cache the related ``Person`` *and* the related ``City``::
# Hits the database with joins to the author and hometown tables.
- b = Book.objects.select_related('author__hometown').get(id=4)
- p = b.author # Doesn't hit the database.
- c = p.hometown # Doesn't hit the database.
+ b = Book.objects.select_related("author__hometown").get(id=4)
+ p = b.author # Doesn't hit the database.
+ c = p.hometown # Doesn't hit the database.
# Without select_related()...
b = Book.objects.get(id=4) # Hits the database.
- p = b.author # Hits the database.
- c = p.hometown # Hits the database.
+ p = b.author # Hits the database.
+ c = p.hometown # Hits the database.
You can refer to any :class:`~django.db.models.ForeignKey` or
:class:`~django.db.models.OneToOneField` relation in the list of fields
@@ -1158,9 +1162,11 @@ For example, suppose you have these models::
from django.db import models
+
class Topping(models.Model):
name = models.CharField(max_length=30)
+
class Pizza(models.Model):
name = models.CharField(max_length=50)
toppings = models.ManyToManyField(Topping)
@@ -1238,14 +1244,16 @@ You can also use the normal join syntax to do related fields of related
fields. Suppose we have an additional model to the example above::
class Restaurant(models.Model):
- pizzas = models.ManyToManyField(Pizza, related_name='restaurants')
- best_pizza = models.ForeignKey(Pizza, related_name='championed_by', on_delete=models.CASCADE)
+ pizzas = models.ManyToManyField(Pizza, related_name="restaurants")
+ best_pizza = models.ForeignKey(
+ Pizza, related_name="championed_by", on_delete=models.CASCADE
+ )
The following are all legal:
.. code-block:: pycon
- >>> Restaurant.objects.prefetch_related('pizzas__toppings')
+ >>> Restaurant.objects.prefetch_related("pizzas__toppings")
This will prefetch all pizzas belonging to restaurants, and all toppings
belonging to those pizzas. This will result in a total of 3 database queries -
@@ -1253,7 +1261,7 @@ one for the restaurants, one for the pizzas, and one for the toppings.
.. code-block:: pycon
- >>> Restaurant.objects.prefetch_related('best_pizza__toppings')
+ >>> Restaurant.objects.prefetch_related("best_pizza__toppings")
This will fetch the best pizza and all the toppings for the best pizza for each
restaurant. This will be done in 3 database queries - one for the restaurants,
@@ -1264,7 +1272,7 @@ to reduce the query count to 2:
.. code-block:: pycon
- >>> Restaurant.objects.select_related('best_pizza').prefetch_related('best_pizza__toppings')
+ >>> Restaurant.objects.select_related("best_pizza").prefetch_related("best_pizza__toppings")
Since the prefetch is executed after the main query (which includes the joins
needed by ``select_related``), it is able to detect that the ``best_pizza``
@@ -1379,20 +1387,20 @@ database selected by the outer query. All of the following are valid:
.. code-block:: pycon
>>> # Both inner and outer queries will use the 'replica' database
- >>> Restaurant.objects.prefetch_related('pizzas__toppings').using('replica')
+ >>> Restaurant.objects.prefetch_related("pizzas__toppings").using("replica")
>>> Restaurant.objects.prefetch_related(
- ... Prefetch('pizzas__toppings'),
- ... ).using('replica')
+ ... Prefetch("pizzas__toppings"),
+ ... ).using("replica")
>>>
>>> # Inner will use the 'replica' database; outer will use 'default' database
>>> Restaurant.objects.prefetch_related(
- ... Prefetch('pizzas__toppings', queryset=Toppings.objects.using('replica')),
+ ... Prefetch("pizzas__toppings", queryset=Toppings.objects.using("replica")),
... )
>>>
>>> # Inner will use 'replica' database; outer will use 'cold-storage' database
>>> Restaurant.objects.prefetch_related(
- ... Prefetch('pizzas__toppings', queryset=Toppings.objects.using('replica')),
- ... ).using('cold-storage')
+ ... Prefetch("pizzas__toppings", queryset=Toppings.objects.using("replica")),
+ ... ).using("cold-storage")
.. note::
@@ -1449,7 +1457,7 @@ generated by a ``QuerySet``.
.. code-block:: pycon
>>> qs.extra(
- ... select={'val': "select col from sometable where othercol = %s"},
+ ... select={"val": "select col from sometable where othercol = %s"},
... select_params=(someparam,),
... )
@@ -1496,7 +1504,7 @@ of the arguments is required, but you should use at least one of them.
Example::
- Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
+ Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"})
As a result, each ``Entry`` object will have an extra attribute,
``is_recent``, a boolean representing whether the entry's ``pub_date``
@@ -1517,7 +1525,7 @@ of the arguments is required, but you should use at least one of them.
Blog.objects.extra(
select={
- 'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
+ "entry_count": "SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id"
},
)
@@ -1543,8 +1551,8 @@ of the arguments is required, but you should use at least one of them.
This will work, for example::
Blog.objects.extra(
- select={'a': '%s', 'b': '%s'},
- select_params=('one', 'two'),
+ select={"a": "%s", "b": "%s"},
+ select_params=("one", "two"),
)
If you need to use a literal ``%s`` inside your select string, use
@@ -1602,8 +1610,8 @@ of the arguments is required, but you should use at least one of them.
For example::
- q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
- q = q.extra(order_by = ['-is_recent'])
+ q = Entry.objects.extra(select={"is_recent": "pub_date > '2006-01-01'"})
+ q = q.extra(order_by=["-is_recent"])
This would sort all the items for which ``is_recent`` is true to the
front of the result set (``True`` sorts before ``False`` in a
@@ -1621,7 +1629,7 @@ of the arguments is required, but you should use at least one of them.
Example::
- Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
+ Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
Always use ``params`` instead of embedding values directly into
``where`` because ``params`` will ensure values are quoted correctly
@@ -1634,7 +1642,7 @@ of the arguments is required, but you should use at least one of them.
Good::
- Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
+ Entry.objects.extra(where=["headline=%s"], params=["Lennon"])
.. warning::
@@ -1729,18 +1737,20 @@ one, doing so will result in an error.
class Meta:
managed = False
- db_table = 'app_largetable'
+ db_table = "app_largetable"
+
class ManagedModel(models.Model):
f1 = models.CharField(max_length=10)
f2 = models.CharField(max_length=10)
class Meta:
- db_table = 'app_largetable'
+ db_table = "app_largetable"
+
# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
- ManagedModel.objects.defer('f2')
+ ManagedModel.objects.defer("f2")
If many fields need to be duplicated in the unmanaged model, it may be best
to create an abstract model with the shared fields and then have the
@@ -1830,7 +1840,7 @@ For example:
>>> Entry.objects.all()
# queries the database with the 'backup' alias
- >>> Entry.objects.using('backup')
+ >>> Entry.objects.using("backup")
``select_for_update()``
~~~~~~~~~~~~~~~~~~~~~~~
@@ -1878,7 +1888,7 @@ to refer to the queryset's model.
<multi-table-inheritance>`, you must specify parent link fields (by default
``<parent_model_name>_ptr``) in the ``of`` argument. For example::
- Restaurant.objects.select_for_update(of=('self', 'place_ptr'))
+ Restaurant.objects.select_for_update(of=("self", "place_ptr"))
.. admonition:: Using ``select_for_update(of=(...))`` with specified fields
@@ -1896,7 +1906,7 @@ You can't use ``select_for_update()`` on nullable relations:
.. code-block:: pycon
- >>> Person.objects.select_related('hometown').select_for_update()
+ >>> Person.objects.select_related("hometown").select_for_update()
Traceback (most recent call last):
...
django.db.utils.NotSupportedError: FOR UPDATE cannot be applied to the nullable side of an outer join
@@ -1906,7 +1916,7 @@ them:
.. code-block:: pycon
- >>> Person.objects.select_related('hometown').select_for_update().exclude(hometown=None)
+ >>> Person.objects.select_related("hometown").select_for_update().exclude(hometown=None)
<QuerySet [<Person: ...)>, ...]>
The ``postgresql``, ``oracle``, and ``mysql`` database backends support
@@ -1980,6 +1990,7 @@ The following are equivalent::
Model.objects.filter(x=1) & Model.objects.filter(y=2)
Model.objects.filter(x=1, y=2)
from django.db.models import Q
+
Model.objects.filter(Q(x=1) & Q(y=2))
SQL equivalent:
@@ -1997,6 +2008,7 @@ The following are equivalent::
Model.objects.filter(x=1) | Model.objects.filter(y=2)
from django.db.models import Q
+
Model.objects.filter(Q(x=1) | Q(y=2))
SQL equivalent:
@@ -2017,6 +2029,7 @@ The following are equivalent::
Model.objects.filter(x=1) ^ Model.objects.filter(y=2)
from django.db.models import Q
+
Model.objects.filter(Q(x=1) ^ Q(y=2))
SQL equivalent:
@@ -2081,13 +2094,13 @@ without any arguments to return the object for that row::
If ``get()`` doesn't find any object, it raises a :exc:`Model.DoesNotExist
<django.db.models.Model.DoesNotExist>` exception::
- Entry.objects.get(id=-999) # raises Entry.DoesNotExist
+ Entry.objects.get(id=-999) # raises Entry.DoesNotExist
If ``get()`` finds more than one object, it raises a
:exc:`Model.MultipleObjectsReturned
<django.db.models.Model.MultipleObjectsReturned>` exception::
- Entry.objects.get(name='A Duplicated Name') # raises Entry.MultipleObjectsReturned
+ Entry.objects.get(name="A Duplicated Name") # raises Entry.MultipleObjectsReturned
Both these exception classes are attributes of the model class, and specific to
that model. If you want to handle such exceptions from several ``get()`` calls
@@ -2149,9 +2162,9 @@ This is meant to prevent duplicate objects from being created when requests are
made in parallel, and as a shortcut to boilerplatish code. For example::
try:
- obj = Person.objects.get(first_name='John', last_name='Lennon')
+ obj = Person.objects.get(first_name="John", last_name="Lennon")
except Person.DoesNotExist:
- obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
+ obj = Person(first_name="John", last_name="Lennon", birthday=date(1940, 10, 9))
obj.save()
Here, with concurrent requests, multiple attempts to save a ``Person`` with
@@ -2159,9 +2172,9 @@ the same parameters may be made. To avoid this race condition, the above
example can be rewritten using ``get_or_create()`` like so::
obj, created = Person.objects.get_or_create(
- first_name='John',
- last_name='Lennon',
- defaults={'birthday': date(1940, 10, 9)},
+ first_name="John",
+ last_name="Lennon",
+ defaults={"birthday": date(1940, 10, 9)},
)
Any keyword arguments passed to ``get_or_create()`` — *except* an optional one
@@ -2185,8 +2198,8 @@ exists, and create the latter otherwise::
from django.db.models import Q
obj, created = Person.objects.filter(
- Q(first_name='Bob') | Q(first_name='Robert'),
- ).get_or_create(last_name='Marley', defaults={'first_name': 'Bob'})
+ Q(first_name="Bob") | Q(first_name="Robert"),
+ ).get_or_create(last_name="Marley", defaults={"first_name": "Bob"})
If multiple objects are found, ``get_or_create()`` raises
:exc:`~django.core.exceptions.MultipleObjectsReturned`. If an object is *not*
@@ -2194,7 +2207,7 @@ found, ``get_or_create()`` will instantiate and save a new object, returning a
tuple of the new object and ``True``. The new object will be created roughly
according to this algorithm::
- params = {k: v for k, v in kwargs.items() if '__' not in k}
+ params = {k: v for k, v in kwargs.items() if "__" not in k}
params.update({k: v() if callable(v) else v for k, v in defaults.items()})
obj = self.model(**params)
obj.save()
@@ -2211,7 +2224,7 @@ handles some extra edge-conditions; if you're interested, read the code.
If you have a field named ``defaults`` and want to use it as an exact lookup in
``get_or_create()``, use ``'defaults__exact'``, like so::
- Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})
+ Foo.objects.get_or_create(defaults__exact="bar", defaults={"defaults": "baz"})
The ``get_or_create()`` method has similar error behavior to :meth:`create()`
when you're using manually specified primary keys. If an object needs to be
@@ -2236,6 +2249,7 @@ whenever a request to a page has a side effect on your data. For more, see
class Chapter(models.Model):
title = models.CharField(max_length=255, unique=True)
+
class Book(models.Model):
title = models.CharField(max_length=256)
chapters = models.ManyToManyField(Chapter)
@@ -2286,15 +2300,15 @@ the given ``kwargs``. If a match is found, it updates the fields passed in the
This is meant as a shortcut to boilerplatish code. For example::
- defaults = {'first_name': 'Bob'}
- create_defaults = {'first_name': 'Bob', 'birthday': date(1940, 10, 9)}
+ defaults = {"first_name": "Bob"}
+ create_defaults = {"first_name": "Bob", "birthday": date(1940, 10, 9)}
try:
- obj = Person.objects.get(first_name='John', last_name='Lennon')
+ obj = Person.objects.get(first_name="John", last_name="Lennon")
for key, value in defaults.items():
setattr(obj, key, value)
obj.save()
except Person.DoesNotExist:
- new_values = {'first_name': 'John', 'last_name': 'Lennon'}
+ new_values = {"first_name": "John", "last_name": "Lennon"}
new_values.update(create_defaults)
obj = Person(**new_values)
obj.save()
@@ -2303,9 +2317,10 @@ This pattern gets quite unwieldy as the number of fields in a model goes up.
The above example can be rewritten using ``update_or_create()`` like so::
obj, created = Person.objects.update_or_create(
- first_name='John', last_name='Lennon',
- defaults={'first_name': 'Bob'},
- create_defaults={'first_name': 'Bob', 'birthday': date(1940, 10, 9)},
+ first_name="John",
+ last_name="Lennon",
+ defaults={"first_name": "Bob"},
+ create_defaults={"first_name": "Bob", "birthday": date(1940, 10, 9)},
)
For a detailed description of how names passed in ``kwargs`` are resolved, see
@@ -2342,10 +2357,12 @@ are), and returns created objects as a list, in the same order as provided:
.. code-block:: pycon
- >>> objs = Entry.objects.bulk_create([
- ... Entry(headline='This is a test'),
- ... Entry(headline='This is only a test'),
- ... ])
+ >>> objs = Entry.objects.bulk_create(
+ ... [
+ ... Entry(headline="This is a test"),
+ ... Entry(headline="This is only a test"),
+ ... ]
+ ... )
This has a number of caveats though:
@@ -2366,7 +2383,7 @@ This has a number of caveats though:
from itertools import islice
batch_size = 100
- objs = (Entry(headline='Test %s' % i) for i in range(1000))
+ objs = (Entry(headline="Test %s" % i) for i in range(1000))
while True:
batch = list(islice(objs, batch_size))
if not batch:
@@ -2417,12 +2434,12 @@ updated:
.. code-block:: pycon
>>> objs = [
- ... Entry.objects.create(headline='Entry 1'),
- ... Entry.objects.create(headline='Entry 2'),
+ ... Entry.objects.create(headline="Entry 1"),
+ ... Entry.objects.create(headline="Entry 2"),
... ]
- >>> objs[0].headline = 'This is entry 1'
- >>> objs[1].headline = 'This is entry 2'
- >>> Entry.objects.bulk_update(objs, ['headline'])
+ >>> objs[0].headline = "This is entry 1"
+ >>> objs[1].headline = "This is entry 2"
+ >>> Entry.objects.bulk_update(objs, ["headline"])
2
:meth:`.QuerySet.update` is used to save the changes, so this is more efficient
@@ -2466,7 +2483,7 @@ Example::
Entry.objects.count()
# Returns the number of entries whose headline contains 'Lennon'
- Entry.objects.filter(headline__contains='Lennon').count()
+ Entry.objects.filter(headline__contains="Lennon").count()
A ``count()`` call performs a ``SELECT COUNT(*)`` behind the scenes, so you
should always use ``count()`` rather than loading all of the record into Python
@@ -2511,9 +2528,9 @@ Example:
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
- >>> Blog.objects.in_bulk(['beatles_blog'], field_name='slug')
+ >>> Blog.objects.in_bulk(["beatles_blog"], field_name="slug")
{'beatles_blog': <Blog: Beatles Blog>}
- >>> Blog.objects.distinct('name').in_bulk(field_name='name')
+ >>> Blog.objects.distinct("name").in_bulk(field_name="name")
{'Beatles Blog': <Blog: Beatles Blog>, 'Cheddar Talk': <Blog: Cheddar Talk>, 'Django Weblog': <Blog: Django Weblog>}
If you pass ``in_bulk()`` an empty list, you'll get an empty dictionary.
@@ -2625,13 +2642,13 @@ Returns the latest object in the table based on the given field(s).
This example returns the latest ``Entry`` in the table, according to the
``pub_date`` field::
- Entry.objects.latest('pub_date')
+ Entry.objects.latest("pub_date")
You can also choose the latest based on several fields. For example, to select
the ``Entry`` with the earliest ``expire_date`` when two entries have the same
``pub_date``::
- Entry.objects.latest('pub_date', '-expire_date')
+ Entry.objects.latest("pub_date", "-expire_date")
The negative sign in ``'-expire_date'`` means to sort ``expire_date`` in
*descending* order. Since ``latest()`` gets the last result, the ``Entry`` with
@@ -2658,7 +2675,7 @@ readability.
You may want to filter out null values::
- Entry.objects.filter(pub_date__isnull=False).latest('pub_date')
+ Entry.objects.filter(pub_date__isnull=False).latest("pub_date")
``earliest()``
~~~~~~~~~~~~~~
@@ -2686,13 +2703,13 @@ aggregation results as described in :ref:`aggregation-ordering-interaction`.
Example::
- p = Article.objects.order_by('title', 'pub_date').first()
+ p = Article.objects.order_by("title", "pub_date").first()
Note that ``first()`` is a convenience method, the following code sample is
equivalent to the above example::
try:
- p = Article.objects.order_by('title', 'pub_date')[0]
+ p = Article.objects.order_by("title", "pub_date")[0]
except IndexError:
p = None
@@ -2735,7 +2752,7 @@ number of authors that have contributed blog entries:
.. code-block:: pycon
>>> from django.db.models import Count
- >>> q = Blog.objects.aggregate(Count('entry'))
+ >>> q = Blog.objects.aggregate(Count("entry"))
{'entry__count': 16}
By using a keyword argument to specify the aggregate function, you can
@@ -2743,7 +2760,7 @@ control the name of the aggregation value that is returned:
.. code-block:: pycon
- >>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
+ >>> q = Blog.objects.aggregate(number_of_entries=Count("entry"))
{'number_of_entries': 16}
For an in-depth discussion of aggregation, see :doc:`the topic guide on
@@ -2802,13 +2819,13 @@ not. This tries to perform the query in the simplest and fastest way possible.
To check whether a queryset contains a specific item::
if some_queryset.contains(obj):
- print('Entry contained in queryset')
+ print("Entry contained in queryset")
This will be faster than the following which requires evaluating and iterating
through the entire queryset::
if obj in some_queryset:
- print('Entry contained in queryset')
+ print("Entry contained in queryset")
Like :meth:`exists`, if ``some_queryset`` has not yet been evaluated, but you
know that it will be at some point, then using ``some_queryset.contains(obj)``
@@ -2841,7 +2858,9 @@ here we update the ``comments_on`` and ``headline`` fields:
.. code-block:: pycon
- >>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')
+ >>> Entry.objects.filter(pub_date__year=2010).update(
+ ... comments_on=False, headline="This is old"
+ ... )
The ``update()`` method is applied instantly, and the only restriction on the
:class:`.QuerySet` that is updated is that it can only update columns in the
@@ -2849,7 +2868,7 @@ model's main table, not on related models. You can't do this, for example:
.. code-block:: pycon
- >>> Entry.objects.update(blog__name='foo') # Won't work!
+ >>> Entry.objects.update(blog__name="foo") # Won't work!
Filtering based on related fields is still possible, though:
@@ -2867,7 +2886,7 @@ The ``update()`` method returns the number of affected rows:
>>> Entry.objects.filter(id=64).update(comments_on=True)
1
- >>> Entry.objects.filter(slug='nonexistent-slug').update(comments_on=True)
+ >>> Entry.objects.filter(slug="nonexistent-slug").update(comments_on=True)
0
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
@@ -2909,7 +2928,7 @@ Chaining ``order_by()`` with ``update()`` is supported only on MariaDB and
MySQL, and is ignored for different databases. This is useful for updating a
unique field in the order that is specified without conflicts. For example::
- Entry.objects.order_by('-number').update(number=F('number') + 1)
+ Entry.objects.order_by("-number").update(number=F("number") + 1)
.. note::
@@ -3006,7 +3025,7 @@ For example, when using PostgreSQL:
.. code-block:: pycon
- >>> print(Blog.objects.filter(title='My Blog').explain())
+ >>> print(Blog.objects.filter(title="My Blog").explain())
Seq Scan on blog (cost=0.00..35.50 rows=10 width=12)
Filter: (title = 'My Blog'::bpchar)
@@ -3027,7 +3046,7 @@ Pass these flags as keyword arguments. For example, when using PostgreSQL:
.. code-block:: pycon
- >>> print(Blog.objects.filter(title='My Blog').explain(verbose=True, analyze=True))
+ >>> print(Blog.objects.filter(title="My Blog").explain(verbose=True, analyze=True))
Seq Scan on public.blog (cost=0.00..35.50 rows=10 width=12) (actual time=0.004..0.004 rows=10 loops=1)
Output: id, title
Filter: (blog.title = 'My Blog'::bpchar)
@@ -3097,7 +3116,7 @@ details).
Example::
- Blog.objects.get(name__iexact='beatles blog')
+ Blog.objects.get(name__iexact="beatles blog")
Blog.objects.get(name__iexact=None)
SQL equivalents:
@@ -3125,7 +3144,7 @@ Case-sensitive containment test.
Example::
- Entry.objects.get(headline__contains='Lennon')
+ Entry.objects.get(headline__contains="Lennon")
SQL equivalent:
@@ -3152,7 +3171,7 @@ Case-insensitive containment test.
Example::
- Entry.objects.get(headline__icontains='Lennon')
+ Entry.objects.get(headline__icontains="Lennon")
SQL equivalent:
@@ -3176,7 +3195,7 @@ case, but strings (being iterables) are accepted.
Examples::
Entry.objects.filter(id__in=[1, 3, 4])
- Entry.objects.filter(headline__in='abc')
+ Entry.objects.filter(headline__in="abc")
SQL equivalents:
@@ -3188,7 +3207,7 @@ SQL equivalents:
You can also use a queryset to dynamically evaluate the list of values
instead of providing a list of literal values::
- inner_qs = Blog.objects.filter(name__contains='Cheddar')
+ inner_qs = Blog.objects.filter(name__contains="Cheddar")
entries = Entry.objects.filter(blog__in=inner_qs)
This queryset will be evaluated as subselect statement:
@@ -3202,14 +3221,14 @@ as the value to an ``__in`` lookup, you need to ensure you are only extracting
one field in the result. For example, this will work (filtering on the blog
names)::
- inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
+ inner_qs = Blog.objects.filter(name__contains="Ch").values("name")
entries = Entry.objects.filter(blog__name__in=inner_qs)
This example will raise an exception, since the inner query is trying to
extract two field values, where only one is expected::
# Bad code! Will raise a TypeError.
- inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
+ inner_qs = Blog.objects.filter(name__contains="Ch").values("name", "id")
entries = Entry.objects.filter(blog__name__in=inner_qs)
.. _nested-queries-performance:
@@ -3223,8 +3242,7 @@ extract two field values, where only one is expected::
and then pass that into the second query. That is, execute two queries
instead of one::
- values = Blog.objects.filter(
- name__contains='Cheddar').values_list('pk', flat=True)
+ values = Blog.objects.filter(name__contains="Cheddar").values_list("pk", flat=True)
entries = Entry.objects.filter(blog__in=list(values))
Note the ``list()`` call around the Blog ``QuerySet`` to force execution of
@@ -3278,7 +3296,7 @@ Case-sensitive starts-with.
Example::
- Entry.objects.filter(headline__startswith='Lennon')
+ Entry.objects.filter(headline__startswith="Lennon")
SQL equivalent:
@@ -3298,7 +3316,7 @@ Case-insensitive starts-with.
Example::
- Entry.objects.filter(headline__istartswith='Lennon')
+ Entry.objects.filter(headline__istartswith="Lennon")
SQL equivalent:
@@ -3320,7 +3338,7 @@ Case-sensitive ends-with.
Example::
- Entry.objects.filter(headline__endswith='Lennon')
+ Entry.objects.filter(headline__endswith="Lennon")
SQL equivalent:
@@ -3343,7 +3361,7 @@ Case-insensitive ends-with.
Example::
- Entry.objects.filter(headline__iendswith='Lennon')
+ Entry.objects.filter(headline__iendswith="Lennon")
SQL equivalent:
@@ -3366,6 +3384,7 @@ Range test (inclusive).
Example::
import datetime
+
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))
@@ -3743,7 +3762,7 @@ the regular expression syntax is therefore that of Python's ``re`` module.
Example::
- Entry.objects.get(title__regex=r'^(An?|The) +')
+ Entry.objects.get(title__regex=r"^(An?|The) +")
SQL equivalents:
@@ -3769,7 +3788,7 @@ Case-insensitive regular expression match.
Example::
- Entry.objects.get(title__iregex=r'^(an?|the) +')
+ Entry.objects.get(title__iregex=r"^(an?|the) +")
SQL equivalents:
@@ -4048,7 +4067,7 @@ lookups or :class:`Prefetch` objects you want to prefetch for. For example:
>>> from django.db.models import prefetch_related_objects
>>> restaurants = fetch_top_restaurants_from_cache() # A list of Restaurants
- >>> prefetch_related_objects(restaurants, 'pizzas__toppings')
+ >>> prefetch_related_objects(restaurants, "pizzas__toppings")
When using multiple databases with ``prefetch_related_objects``, the prefetch
query will use the database associated with the model instance. This can be
@@ -4079,10 +4098,11 @@ For example, to find restaurants that have vegetarian pizzas with
>>> from django.db.models import FilteredRelation, Q
>>> Restaurant.objects.annotate(
- ... pizzas_vegetarian=FilteredRelation(
- ... 'pizzas', condition=Q(pizzas__vegetarian=True),
- ... ),
- ... ).filter(pizzas_vegetarian__name__icontains='mozzarella')
+ ... pizzas_vegetarian=FilteredRelation(
+ ... "pizzas",
+ ... condition=Q(pizzas__vegetarian=True),
+ ... ),
+ ... ).filter(pizzas_vegetarian__name__icontains="mozzarella")
If there are a large number of pizzas, this queryset performs better than:
@@ -4090,7 +4110,7 @@ If there are a large number of pizzas, this queryset performs better than:
>>> Restaurant.objects.filter(
... pizzas__vegetarian=True,
- ... pizzas__name__icontains='mozzarella',
+ ... pizzas__name__icontains="mozzarella",
... )
because the filtering in the ``WHERE`` clause of the first queryset will only
diff --git a/docs/ref/models/relations.txt b/docs/ref/models/relations.txt
index 43bcb45830..98177010b8 100644
--- a/docs/ref/models/relations.txt
+++ b/docs/ref/models/relations.txt
@@ -14,10 +14,12 @@ Related objects reference
from django.db import models
+
class Blog(models.Model):
# ...
pass
+
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE, null=True)
@@ -31,6 +33,7 @@ Related objects reference
# ...
pass
+
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
@@ -50,7 +53,7 @@ Related objects reference
>>> b = Blog.objects.get(id=1)
>>> e = Entry.objects.get(id=234)
- >>> b.entry_set.add(e) # Associates Entry e with Blog b.
+ >>> b.entry_set.add(e) # Associates Entry e with Blog b.
In the example above, in the case of a
:class:`~django.db.models.ForeignKey` relationship,
@@ -97,9 +100,7 @@ Related objects reference
>>> b = Blog.objects.get(id=1)
>>> e = b.entry_set.create(
- ... headline='Hello',
- ... body_text='Hi',
- ... pub_date=datetime.date(2005, 1, 1)
+ ... headline="Hello", body_text="Hi", pub_date=datetime.date(2005, 1, 1)
... )
# No need to call e.save() at this point -- it's already been saved.
@@ -109,12 +110,7 @@ Related objects reference
.. code-block:: pycon
>>> b = Blog.objects.get(id=1)
- >>> e = Entry(
- ... blog=b,
- ... headline='Hello',
- ... body_text='Hi',
- ... pub_date=datetime.date(2005, 1, 1)
- ... )
+ >>> e = Entry(blog=b, headline="Hello", body_text="Hi", pub_date=datetime.date(2005, 1, 1))
>>> e.save(force_insert=True)
Note that there's no need to specify the keyword argument of the model
@@ -138,7 +134,7 @@ Related objects reference
>>> b = Blog.objects.get(id=1)
>>> e = Entry.objects.get(id=234)
- >>> b.entry_set.remove(e) # Disassociates Entry e from Blog b.
+ >>> b.entry_set.remove(e) # Disassociates Entry e from Blog b.
Similar to :meth:`add()`, ``e.save()`` is called in the example above
to perform the update. Using ``remove()`` with a many-to-many
diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt
index b1a177cca9..9b0ed76e4d 100644
--- a/docs/ref/request-response.txt
+++ b/docs/ref/request-response.txt
@@ -73,9 +73,9 @@ All attributes should be considered read-only, unless stated otherwise.
A string representing the HTTP method used in the request. This is
guaranteed to be uppercase. For example::
- if request.method == 'GET':
+ if request.method == "GET":
do_something()
- elif request.method == 'POST':
+ elif request.method == "POST":
do_something_else()
.. attribute:: HttpRequest.encoding
@@ -186,19 +186,19 @@ All attributes should be considered read-only, unless stated otherwise.
>>> request.headers
{'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6', ...}
- >>> 'User-Agent' in request.headers
+ >>> "User-Agent" in request.headers
True
- >>> 'user-agent' in request.headers
+ >>> "user-agent" in request.headers
True
- >>> request.headers['User-Agent']
+ >>> request.headers["User-Agent"]
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
- >>> request.headers['user-agent']
+ >>> request.headers["user-agent"]
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
- >>> request.headers.get('User-Agent')
+ >>> request.headers.get("User-Agent")
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
- >>> request.headers.get('user-agent')
+ >>> request.headers.get("user-agent")
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)
For use in, for example, Django templates, headers can also be looked up
@@ -277,9 +277,9 @@ middleware class is listed in :setting:`MIDDLEWARE`.
:attr:`~django.contrib.auth.models.User.is_authenticated`, like so::
if request.user.is_authenticated:
- ... # Do something for logged-in users.
+ ... # Do something for logged-in users.
else:
- ... # Do something for anonymous users.
+ ... # Do something for anonymous users.
Methods
-------
@@ -304,9 +304,9 @@ Methods
class MultipleProxyMiddleware:
FORWARDED_FOR_FIELDS = [
- 'HTTP_X_FORWARDED_FOR',
- 'HTTP_X_FORWARDED_HOST',
- 'HTTP_X_FORWARDED_SERVER',
+ "HTTP_X_FORWARDED_FOR",
+ "HTTP_X_FORWARDED_HOST",
+ "HTTP_X_FORWARDED_SERVER",
]
def __init__(self, get_response):
@@ -319,8 +319,8 @@ Methods
"""
for field in self.FORWARDED_FOR_FIELDS:
if field in request.META:
- if ',' in request.META[field]:
- parts = request.META[field].split(',')
+ if "," in request.META[field]:
+ parts = request.META[field].split(",")
request.META[field] = parts[-1].strip()
return self.get_response(request)
@@ -389,22 +389,19 @@ Methods
.. code-block:: pycon
- >>> request.get_signed_cookie('name')
+ >>> request.get_signed_cookie("name")
'Tony'
- >>> request.get_signed_cookie('name', salt='name-salt')
+ >>> request.get_signed_cookie("name", salt="name-salt")
'Tony' # assuming cookie was set using the same salt
- >>> request.get_signed_cookie('nonexistent-cookie')
- ...
+ >>> request.get_signed_cookie("nonexistent-cookie")
KeyError: 'nonexistent-cookie'
- >>> request.get_signed_cookie('nonexistent-cookie', False)
+ >>> request.get_signed_cookie("nonexistent-cookie", False)
False
- >>> request.get_signed_cookie('cookie-that-was-tampered-with')
- ...
+ >>> request.get_signed_cookie("cookie-that-was-tampered-with")
BadSignature: ...
- >>> request.get_signed_cookie('name', max_age=60)
- ...
+ >>> request.get_signed_cookie("name", max_age=60)
SignatureExpired: Signature age 1677.3839159 > 60 seconds
- >>> request.get_signed_cookie('name', False, max_age=60)
+ >>> request.get_signed_cookie("name", False, max_age=60)
False
See :doc:`cryptographic signing </topics/signing>` for more information.
@@ -421,7 +418,7 @@ Methods
.. code-block:: pycon
- >>> request.accepts('text/html')
+ >>> request.accepts("text/html")
True
Most browsers send ``Accept: */*`` by default, so this would return
@@ -453,6 +450,7 @@ Methods
:class:`~xml.etree.ElementTree.ElementTree`::
import xml.etree.ElementTree as ET
+
for element in ET.iterparse(request):
process(element)
@@ -504,7 +502,7 @@ a subclass of dictionary. Exceptions are outlined here:
.. code-block:: pycon
- >>> QueryDict.fromkeys(['a', 'a', 'b'], value='val')
+ >>> QueryDict.fromkeys(["a", "a", "b"], value="val")
<QueryDict: {'a': ['val', 'val'], 'b': ['val']}>
.. method:: QueryDict.__getitem__(key)
@@ -544,11 +542,11 @@ a subclass of dictionary. Exceptions are outlined here:
.. code-block:: pycon
- >>> q = QueryDict('a=1', mutable=True)
- >>> q.update({'a': '2'})
- >>> q.getlist('a')
+ >>> q = QueryDict("a=1", mutable=True)
+ >>> q.update({"a": "2"})
+ >>> q.getlist("a")
['1', '2']
- >>> q['a'] # returns the last
+ >>> q["a"] # returns the last
'2'
.. method:: QueryDict.items()
@@ -559,7 +557,7 @@ a subclass of dictionary. Exceptions are outlined here:
.. code-block:: pycon
- >>> q = QueryDict('a=1&a=2&a=3')
+ >>> q = QueryDict("a=1&a=2&a=3")
>>> list(q.items())
[('a', '3')]
@@ -571,7 +569,7 @@ a subclass of dictionary. Exceptions are outlined here:
.. code-block:: pycon
- >>> q = QueryDict('a=1&a=2&a=3')
+ >>> q = QueryDict("a=1&a=2&a=3")
>>> list(q.values())
['3']
@@ -608,7 +606,7 @@ In addition, ``QueryDict`` has the following methods:
.. code-block:: pycon
- >>> q = QueryDict('a=1&a=2&a=3')
+ >>> q = QueryDict("a=1&a=2&a=3")
>>> q.lists()
[('a', ['1', '2', '3'])]
@@ -619,8 +617,8 @@ In addition, ``QueryDict`` has the following methods:
.. code-block:: pycon
- >>> q = QueryDict('a=1&a=2&a=3', mutable=True)
- >>> q.pop('a')
+ >>> q = QueryDict("a=1&a=2&a=3", mutable=True)
+ >>> q.pop("a")
['1', '2', '3']
.. method:: QueryDict.popitem()
@@ -632,7 +630,7 @@ In addition, ``QueryDict`` has the following methods:
.. code-block:: pycon
- >>> q = QueryDict('a=1&a=2&a=3', mutable=True)
+ >>> q = QueryDict("a=1&a=2&a=3", mutable=True)
>>> q.popitem()
('a', ['1', '2', '3'])
@@ -644,7 +642,7 @@ In addition, ``QueryDict`` has the following methods:
.. code-block:: pycon
- >>> q = QueryDict('a=1&a=3&a=5')
+ >>> q = QueryDict("a=1&a=3&a=5")
>>> q.dict()
{'a': '5'}
@@ -654,7 +652,7 @@ In addition, ``QueryDict`` has the following methods:
.. code-block:: pycon
- >>> q = QueryDict('a=2&b=3&b=5')
+ >>> q = QueryDict("a=2&b=3&b=5")
>>> q.urlencode()
'a=2&b=3&b=5'
@@ -664,8 +662,8 @@ In addition, ``QueryDict`` has the following methods:
.. code-block:: pycon
>>> q = QueryDict(mutable=True)
- >>> q['next'] = '/a&b/'
- >>> q.urlencode(safe='/')
+ >>> q["next"] = "/a&b/"
+ >>> q.urlencode(safe="/")
'next=/a%26b/'
``HttpResponse`` objects
@@ -694,8 +692,8 @@ or :class:`memoryview`, to the :class:`HttpResponse` constructor:
>>> from django.http import HttpResponse
>>> response = HttpResponse("Here's the text of the web page.")
>>> response = HttpResponse("Text only, please.", content_type="text/plain")
- >>> response = HttpResponse(b'Bytestrings are also accepted.')
- >>> response = HttpResponse(memoryview(b'Memoryview as well.'))
+ >>> response = HttpResponse(b"Bytestrings are also accepted.")
+ >>> response = HttpResponse(memoryview(b"Memoryview as well."))
But if you want to add content incrementally, you can use ``response`` as a
file-like object:
@@ -728,16 +726,16 @@ To set or remove a header field in your response, use
.. code-block:: pycon
>>> response = HttpResponse()
- >>> response.headers['Age'] = 120
- >>> del response.headers['Age']
+ >>> response.headers["Age"] = 120
+ >>> del response.headers["Age"]
You can also manipulate headers by treating your response like a dictionary:
.. code-block:: pycon
>>> response = HttpResponse()
- >>> response['Age'] = 120
- >>> del response['Age']
+ >>> response["Age"] = 120
+ >>> del response["Age"]
This proxies to ``HttpResponse.headers``, and is the original interface offered
by ``HttpResponse``.
@@ -749,7 +747,7 @@ You can also set headers on instantiation:
.. code-block:: pycon
- >>> response = HttpResponse(headers={'Age': 120})
+ >>> response = HttpResponse(headers={"Age": 120})
For setting the ``Cache-Control`` and ``Vary`` header fields, it is recommended
to use the :func:`~django.utils.cache.patch_cache_control` and
@@ -770,10 +768,13 @@ you might return a Microsoft Excel spreadsheet:
.. code-block:: pycon
- >>> response = HttpResponse(my_data, headers={
- ... 'Content-Type': 'application/vnd.ms-excel',
- ... 'Content-Disposition': 'attachment; filename="foo.xls"',
- ... })
+ >>> response = HttpResponse(
+ ... my_data,
+ ... headers={
+ ... "Content-Type": "application/vnd.ms-excel",
+ ... "Content-Disposition": 'attachment; filename="foo.xls"',
+ ... },
+ ... )
There's nothing Django-specific about the ``Content-Disposition`` header, but
it's easy to forget the syntax, so we've included it here.
@@ -1111,7 +1112,7 @@ Typical usage could look like:
.. code-block:: pycon
>>> from django.http import JsonResponse
- >>> response = JsonResponse({'foo': 'bar'})
+ >>> response = JsonResponse({"foo": "bar"})
>>> response.content
b'{"foo": "bar"}'
@@ -1297,7 +1298,7 @@ a file open in binary mode like so:
.. code-block:: pycon
>>> from django.http import FileResponse
- >>> response = FileResponse(open('myfile.png', 'rb'))
+ >>> response = FileResponse(open("myfile.png", "rb"))
The file will be closed automatically, so don't open it with a context manager.
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 50e6241cff..41387886c0 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -33,8 +33,8 @@ a model object and return its URL. This is a way of inserting or overriding
``get_absolute_url()`` methods on a per-installation basis. Example::
ABSOLUTE_URL_OVERRIDES = {
- 'blogs.blog': lambda o: "/blogs/%s/" % o.slug,
- 'news.story': lambda o: "/stories/%s/%s/" % (o.pub_year, o.slug),
+ "blogs.blog": lambda o: "/blogs/%s/" % o.slug,
+ "news.story": lambda o: "/stories/%s/%s/" % (o.pub_year, o.slug),
}
The model name used in this setting should be all lowercase, regardless of the
@@ -54,7 +54,7 @@ people the details of exceptions raised in the request/response cycle.
Each item in the list should be a tuple of (Full name, email address). Example::
- [('John', 'john@example.com'), ('Mary', 'mary@example.com')]
+ [("John", "john@example.com"), ("Mary", "mary@example.com")]
.. setting:: ALLOWED_HOSTS
@@ -123,8 +123,8 @@ The :setting:`APPEND_SLASH` setting is only used if
Default::
{
- 'default': {
- 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+ "default": {
+ "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
}
}
@@ -169,7 +169,7 @@ compose a prefix, version and key into a final cache key. The default
implementation is equivalent to the function::
def make_key(key, key_prefix, version):
- return ':'.join([key_prefix, str(version), key])
+ return ":".join([key_prefix, str(version), key])
You may use any key function you want, as long as it has the same
argument signature.
@@ -201,9 +201,9 @@ file system cache, a host and port for a memcache server, or an identifying
name for a local memory cache. e.g.::
CACHES = {
- 'default': {
- 'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
- 'LOCATION': '/var/tmp/django_cache',
+ "default": {
+ "BACKEND": "django.core.cache.backends.filebased.FileBasedCache",
+ "LOCATION": "/var/tmp/django_cache",
}
}
@@ -492,9 +492,9 @@ The simplest possible settings file is for a single-database setup using
SQLite. This can be configured using the following::
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': 'mydatabase',
+ "default": {
+ "ENGINE": "django.db.backends.sqlite3",
+ "NAME": "mydatabase",
}
}
@@ -504,13 +504,13 @@ the :setting:`ENGINE <DATABASE-ENGINE>` setting below on how to specify
other database types. This example is for PostgreSQL::
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql',
- 'NAME': 'mydatabase',
- 'USER': 'mydatabaseuser',
- 'PASSWORD': 'mypassword',
- 'HOST': '127.0.0.1',
- 'PORT': '5432',
+ "default": {
+ "ENGINE": "django.db.backends.postgresql",
+ "NAME": "mydatabase",
+ "USER": "mydatabaseuser",
+ "PASSWORD": "mypassword",
+ "HOST": "127.0.0.1",
+ "PORT": "5432",
}
}
@@ -567,7 +567,7 @@ localhost. Not used with SQLite.
If this value starts with a forward slash (``'/'``) and you're using MySQL,
MySQL will connect via a Unix socket to the specified socket. For example::
- "HOST": '/var/run/mysql'
+ "HOST": "/var/run/mysql"
If you're using MySQL and this value *doesn't* start with a forward slash, then
this value is assumed to be the host.
@@ -737,12 +737,12 @@ creation and use of test databases, see :ref:`the-test-database`.
Here's an example with a test database configuration::
DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.postgresql',
- 'USER': 'mydatabaseuser',
- 'NAME': 'mydatabase',
- 'TEST': {
- 'NAME': 'mytestdatabase',
+ "default": {
+ "ENGINE": "django.db.backends.postgresql",
+ "USER": "mydatabaseuser",
+ "NAME": "mydatabase",
+ "TEST": {
+ "NAME": "mytestdatabase",
},
},
}
@@ -1118,17 +1118,17 @@ See also :setting:`DATETIME_FORMAT`, :setting:`TIME_FORMAT` and :setting:`SHORT_
Default::
[
- '%Y-%m-%d', # '2006-10-25'
- '%m/%d/%Y', # '10/25/2006'
- '%m/%d/%y', # '10/25/06'
- '%b %d %Y', # 'Oct 25 2006'
- '%b %d, %Y', # 'Oct 25, 2006'
- '%d %b %Y', # '25 Oct 2006'
- '%d %b, %Y', # '25 Oct, 2006'
- '%B %d %Y', # 'October 25 2006'
- '%B %d, %Y', # 'October 25, 2006'
- '%d %B %Y', # '25 October 2006'
- '%d %B, %Y', # '25 October, 2006'
+ "%Y-%m-%d", # '2006-10-25'
+ "%m/%d/%Y", # '10/25/2006'
+ "%m/%d/%y", # '10/25/06'
+ "%b %d %Y", # 'Oct 25 2006'
+ "%b %d, %Y", # 'Oct 25, 2006'
+ "%d %b %Y", # '25 Oct 2006'
+ "%d %b, %Y", # '25 Oct, 2006'
+ "%B %d %Y", # 'October 25 2006'
+ "%B %d, %Y", # 'October 25, 2006'
+ "%d %B %Y", # '25 October 2006'
+ "%d %B, %Y", # '25 October, 2006'
]
A list of formats that will be accepted when inputting data on a date field.
@@ -1162,15 +1162,15 @@ See also :setting:`DATE_FORMAT`, :setting:`TIME_FORMAT` and :setting:`SHORT_DATE
Default::
[
- '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
- '%Y-%m-%d %H:%M:%S.%f', # '2006-10-25 14:30:59.000200'
- '%Y-%m-%d %H:%M', # '2006-10-25 14:30'
- '%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
- '%m/%d/%Y %H:%M:%S.%f', # '10/25/2006 14:30:59.000200'
- '%m/%d/%Y %H:%M', # '10/25/2006 14:30'
- '%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
- '%m/%d/%y %H:%M:%S.%f', # '10/25/06 14:30:59.000200'
- '%m/%d/%y %H:%M', # '10/25/06 14:30'
+ "%Y-%m-%d %H:%M:%S", # '2006-10-25 14:30:59'
+ "%Y-%m-%d %H:%M:%S.%f", # '2006-10-25 14:30:59.000200'
+ "%Y-%m-%d %H:%M", # '2006-10-25 14:30'
+ "%m/%d/%Y %H:%M:%S", # '10/25/2006 14:30:59'
+ "%m/%d/%Y %H:%M:%S.%f", # '10/25/2006 14:30:59.000200'
+ "%m/%d/%Y %H:%M", # '10/25/2006 14:30'
+ "%m/%d/%y %H:%M:%S", # '10/25/06 14:30:59'
+ "%m/%d/%y %H:%M:%S.%f", # '10/25/06 14:30:59.000200'
+ "%m/%d/%y %H:%M", # '10/25/06 14:30'
]
A list of formats that will be accepted when inputting data on a datetime
@@ -1550,8 +1550,8 @@ attempt.
Default::
[
- 'django.core.files.uploadhandler.MemoryFileUploadHandler',
- 'django.core.files.uploadhandler.TemporaryFileUploadHandler',
+ "django.core.files.uploadhandler.MemoryFileUploadHandler",
+ "django.core.files.uploadhandler.TemporaryFileUploadHandler",
]
A list of handlers to use for uploading. Changing this setting allows complete
@@ -1721,8 +1721,8 @@ like:
You can also set this setting to a list of Python paths, for example::
FORMAT_MODULE_PATH = [
- 'mysite.formats',
- 'some_app.formats',
+ "mysite.formats",
+ "some_app.formats",
]
When Django searches for a certain format, it will go through all given Python
@@ -1977,8 +1977,8 @@ Here's a sample settings file::
from django.utils.translation import gettext_lazy as _
LANGUAGES = [
- ('de', _('German')),
- ('en', _('English')),
+ ("de", _("German")),
+ ("en", _("English")),
]
.. setting:: LANGUAGES_BIDI
@@ -2011,8 +2011,8 @@ See :ref:`how-django-discovers-translations`.
Example::
LOCALE_PATHS = [
- '/home/www/project/common_files/locale',
- '/var/local/translations/locale',
+ "/home/www/project/common_files/locale",
+ "/var/local/translations/locale",
]
Django will look within each of these paths for the ``<locale_code>/LC_MESSAGES``
@@ -2142,7 +2142,7 @@ the default package name for migration modules is ``migrations``.
Example::
- {'blog': 'blog.db_migrations'}
+ {"blog": "blog.db_migrations"}
In this case, migrations pertaining to the ``blog`` app will be contained in
the ``blog.db_migrations`` package.
@@ -2417,7 +2417,7 @@ Django whether the request came in via HTTPS, and set
Set a tuple with two elements -- the name of the header to look for and the
required value. For example::
- SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
+ SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
This tells Django to trust the ``X-Forwarded-Proto`` header that comes from our
proxy and that the request is guaranteed to be secure (i.e., it originally came
@@ -2522,7 +2522,7 @@ A dictionary of modules containing serializer definitions (provided as
strings), keyed by a string identifier for that serialization type. For
example, to define a YAML serializer, use::
- SERIALIZATION_MODULES = {'yaml': 'path.to.yaml_serializer'}
+ SERIALIZATION_MODULES = {"yaml": "path.to.yaml_serializer"}
.. setting:: SERVER_EMAIL
@@ -2660,8 +2660,8 @@ Here's a setup that tells the Django template engine to load templates from the
TEMPLATES = [
{
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'APP_DIRS': True,
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "APP_DIRS": True,
},
]
@@ -2802,9 +2802,9 @@ See also :setting:`DATE_FORMAT` and :setting:`DATETIME_FORMAT`.
Default::
[
- '%H:%M:%S', # '14:30:59'
- '%H:%M:%S.%f', # '14:30:59.000200'
- '%H:%M', # '14:30'
+ "%H:%M:%S", # '14:30:59'
+ "%H:%M:%S.%f", # '14:30:59.000200'
+ "%H:%M", # '14:30'
]
A list of formats that will be accepted when inputting data on a time field.
@@ -3094,10 +3094,10 @@ See :ref:`auth_password_storage`.
Default::
[
- 'django.contrib.auth.hashers.PBKDF2PasswordHasher',
- 'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
- 'django.contrib.auth.hashers.Argon2PasswordHasher',
- 'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
+ "django.contrib.auth.hashers.PBKDF2PasswordHasher",
+ "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher",
+ "django.contrib.auth.hashers.Argon2PasswordHasher",
+ "django.contrib.auth.hashers.BCryptSHA256PasswordHasher",
]
.. setting:: AUTH_PASSWORD_VALIDATORS
@@ -3135,6 +3135,7 @@ framework. See :ref:`message levels <message-level>` for more details.
avoid the potential for circular imports, e.g.::
from django.contrib.messages import constants as message_constants
+
MESSAGE_LEVEL = message_constants.DEBUG
If desired, you may specify the numeric values for the constants directly
@@ -3170,11 +3171,11 @@ and :setting:`SESSION_COOKIE_HTTPONLY` when setting their cookies.
Default::
{
- messages.DEBUG: 'debug',
- messages.INFO: 'info',
- messages.SUCCESS: 'success',
- messages.WARNING: 'warning',
- messages.ERROR: 'error',
+ messages.DEBUG: "debug",
+ messages.INFO: "info",
+ messages.SUCCESS: "success",
+ messages.WARNING: "warning",
+ messages.ERROR: "error",
}
This sets the mapping of message level to message tag, which is typically
@@ -3189,7 +3190,8 @@ to override. See :ref:`message-displaying` above for more details.
avoid the potential for circular imports, e.g.::
from django.contrib.messages import constants as message_constants
- MESSAGE_TAGS = {message_constants.INFO: ''}
+
+ MESSAGE_TAGS = {message_constants.INFO: ""}
If desired, you may specify the numeric values for the constants directly
according to the values in the above :ref:`constants table
@@ -3574,8 +3576,8 @@ For an example, see :ref:`staticfiles-from-cdn`.
Default::
[
- 'django.contrib.staticfiles.finders.FileSystemFinder',
- 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+ "django.contrib.staticfiles.finders.FileSystemFinder",
+ "django.contrib.staticfiles.finders.AppDirectoriesFinder",
]
The list of finder backends that know how to find static files in
diff --git a/docs/ref/signals.txt b/docs/ref/signals.txt
index a0433863f4..553e376d21 100644
--- a/docs/ref/signals.txt
+++ b/docs/ref/signals.txt
@@ -311,6 +311,7 @@ like this::
# ...
pass
+
class Pizza(models.Model):
# ...
toppings = models.ManyToManyField(Topping)
@@ -319,10 +320,12 @@ If we connected a handler like this::
from django.db.models.signals import m2m_changed
+
def toppings_changed(sender, **kwargs):
# Do something
pass
+
m2m_changed.connect(toppings_changed, sender=Pizza.toppings.through)
and then did something like this:
@@ -529,10 +532,12 @@ For example, you could register a callback in an
from django.apps import AppConfig
from django.db.models.signals import post_migrate
+
def my_callback(sender, **kwargs):
# Your specific logic here
pass
+
class MyAppConfig(AppConfig):
...
diff --git a/docs/ref/template-response.txt b/docs/ref/template-response.txt
index 059d651957..a9b9feeb59 100644
--- a/docs/ref/template-response.txt
+++ b/docs/ref/template-response.txt
@@ -224,13 +224,13 @@ the content of the response manually:
# Set up a rendered TemplateResponse
>>> from django.template.response import TemplateResponse
- >>> t = TemplateResponse(request, 'original.html', {})
+ >>> t = TemplateResponse(request, "original.html", {})
>>> t.render()
>>> print(t.content)
Original content
# Re-rendering doesn't change content
- >>> t.template_name = 'new.html'
+ >>> t.template_name = "new.html"
>>> t.render()
>>> print(t.content)
Original content
@@ -267,13 +267,15 @@ the template response::
from django.template.response import TemplateResponse
+
def my_render_callback(response):
# Do content-sensitive processing
do_post_processing()
+
def my_view(request):
# Create a response
- response = TemplateResponse(request, 'mytemplate.html', {})
+ response = TemplateResponse(request, "mytemplate.html", {})
# Register the callback
response.add_post_render_callback(my_render_callback)
# Return the response
@@ -298,5 +300,8 @@ template and a context containing a queryset::
from django.template.response import TemplateResponse
+
def blog_index(request):
- return TemplateResponse(request, 'entry_list.html', {'entries': Entry.objects.all()})
+ return TemplateResponse(
+ request, "entry_list.html", {"entries": Entry.objects.all()}
+ )
diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt
index e080388ff4..a095dd5953 100644
--- a/docs/ref/templates/api.txt
+++ b/docs/ref/templates/api.txt
@@ -121,8 +121,8 @@ overridden by what's passed by
Engine(
libraries={
- 'myapp_tags': 'path.to.myapp.tags',
- 'admin.urls': 'django.contrib.admin.templatetags.admin_urls',
+ "myapp_tags": "path.to.myapp.tags",
+ "admin.urls": "django.contrib.admin.templatetags.admin_urls",
},
)
@@ -133,7 +133,7 @@ overridden by what's passed by
add to :doc:`built-ins </ref/templates/builtins>`. For example::
Engine(
- builtins=['myapp.builtins'],
+ builtins=["myapp.builtins"],
)
Tags and filters from built-in libraries can be used without first calling
@@ -255,7 +255,9 @@ logic. Here are a few examples:
>>> t.render(Context(d))
"My name is Joe."
- >>> class PersonClass: pass
+ >>> class PersonClass:
+ ... pass
+ ...
>>> p = PersonClass()
>>> p.first_name = "Ron"
>>> p.last_name = "Nasty"
@@ -275,6 +277,7 @@ it. Example:
>>> class PersonClass2:
... def name(self):
... return "Samantha"
+ ...
>>> t = Template("My name is {{ person.name }}.")
>>> t.render(Context({"person": PersonClass2}))
"My name is Samantha."
@@ -296,6 +299,7 @@ straight lookups. Here are some things to keep in mind:
>>> class PersonClass3:
... def first_name(self):
... raise AssertionError("foo")
+ ...
>>> p = PersonClass3()
>>> t.render(Context({"person": p}))
Traceback (most recent call last):
@@ -304,9 +308,11 @@ straight lookups. Here are some things to keep in mind:
>>> class SilentAssertionError(Exception):
... silent_variable_failure = True
+ ...
>>> class PersonClass4:
... def first_name(self):
... raise SilentAssertionError
+ ...
>>> p = PersonClass4()
>>> t.render(Context({"person": p}))
"My name is ."
@@ -344,6 +350,8 @@ straight lookups. Here are some things to keep in mind:
def sensitive_function(self):
self.database_record.delete()
+
+
sensitive_function.alters_data = True
* Occasionally you may want to turn off this feature for other reasons,
@@ -437,15 +445,15 @@ dictionary syntax:
>>> from django.template import Context
>>> c = Context({"foo": "bar"})
- >>> c['foo']
+ >>> c["foo"]
'bar'
- >>> del c['foo']
- >>> c['foo']
+ >>> del c["foo"]
+ >>> c["foo"]
Traceback (most recent call last):
...
KeyError: 'foo'
- >>> c['newvariable'] = 'hello'
- >>> c['newvariable']
+ >>> c["newvariable"] = "hello"
+ >>> c["newvariable"]
'hello'
.. method:: Context.get(key, otherwise=None)
@@ -469,18 +477,18 @@ If you ``pop()`` too much, it'll raise
.. code-block:: pycon
>>> c = Context()
- >>> c['foo'] = 'first level'
+ >>> c["foo"] = "first level"
>>> c.push()
{}
- >>> c['foo'] = 'second level'
- >>> c['foo']
+ >>> c["foo"] = "second level"
+ >>> c["foo"]
'second level'
>>> c.pop()
{'foo': 'second level'}
- >>> c['foo']
+ >>> c["foo"]
'first level'
- >>> c['foo'] = 'overwritten'
- >>> c['foo']
+ >>> c["foo"] = "overwritten"
+ >>> c["foo"]
'overwritten'
>>> c.pop()
Traceback (most recent call last):
@@ -571,13 +579,16 @@ against ``dict``::
class ContextTest(unittest.TestCase):
def test_against_dictionary(self):
c1 = Context()
- c1['update'] = 'value'
- self.assertEqual(c1.flatten(), {
- 'True': True,
- 'None': None,
- 'False': False,
- 'update': 'value',
- })
+ c1["update"] = "value"
+ self.assertEqual(
+ c1.flatten(),
+ {
+ "True": True,
+ "None": None,
+ "False": False,
+ "update": "value",
+ },
+ )
.. _subclassing-context-requestcontext:
@@ -591,9 +602,12 @@ Django comes with a special ``Context`` class,
normal ``django.template.Context``. The first difference is that it takes an
:class:`~django.http.HttpRequest` as its first argument. For example::
- c = RequestContext(request, {
- 'foo': 'bar',
- })
+ c = RequestContext(
+ request,
+ {
+ "foo": "bar",
+ },
+ )
The second difference is that it automatically populates the context with a
few variables, according to the engine's ``context_processors`` configuration
@@ -606,10 +620,10 @@ settings file, the default template engine contains the following context
processors::
[
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
+ "django.template.context_processors.debug",
+ "django.template.context_processors.request",
+ "django.contrib.auth.context_processors.auth",
+ "django.contrib.messages.context_processors.messages",
]
In addition to these, :class:`RequestContext` always enables
@@ -650,14 +664,20 @@ example, the :class:`RequestContext` instance gets an ``ip_address`` variable::
from django.http import HttpResponse
from django.template import RequestContext, Template
+
def ip_address_processor(request):
- return {'ip_address': request.META['REMOTE_ADDR']}
+ return {"ip_address": request.META["REMOTE_ADDR"]}
+
def client_ip_view(request):
- template = Template('{{ title }}: {{ ip_address }}')
- context = RequestContext(request, {
- 'title': 'Your IP Address',
- }, [ip_address_processor])
+ template = Template("{{ title }}: {{ ip_address }}")
+ context = RequestContext(
+ request,
+ {
+ "title": "Your IP Address",
+ },
+ [ip_address_processor],
+ )
return HttpResponse(template.render(context))
.. _context-processors:
@@ -780,6 +800,7 @@ context::
from django.conf import settings
+
def from_email(request):
return {
"DEFAULT_FROM_EMAIL": settings.DEFAULT_FROM_EMAIL,
@@ -814,10 +835,10 @@ directories::
TEMPLATES = [
{
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [
- '/home/html/templates/lawrence.com',
- '/home/html/templates/default',
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [
+ "/home/html/templates/lawrence.com",
+ "/home/html/templates/default",
],
},
]
@@ -856,25 +877,29 @@ loaders that come with Django:
This loader is enabled by default. However it won't find any templates
until you set :setting:`DIRS <TEMPLATES-DIRS>` to a non-empty list::
- TEMPLATES = [{
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [BASE_DIR / 'templates'],
- }]
+ TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [BASE_DIR / "templates"],
+ }
+ ]
You can also override ``'DIRS'`` and specify specific directories for a
particular filesystem loader::
- TEMPLATES = [{
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'OPTIONS': {
- 'loaders': [
- (
- 'django.template.loaders.filesystem.Loader',
- [BASE_DIR / 'templates'],
- ),
- ],
- },
- }]
+ TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "OPTIONS": {
+ "loaders": [
+ (
+ "django.template.loaders.filesystem.Loader",
+ [BASE_DIR / "templates"],
+ ),
+ ],
+ },
+ }
+ ]
``django.template.loaders.app_directories.Loader``
@@ -889,7 +914,7 @@ loaders that come with Django:
For example, for this setting::
- INSTALLED_APPS = ['myproject.polls', 'myproject.music']
+ INSTALLED_APPS = ["myproject.polls", "myproject.music"]
...then ``get_template('foo.html')`` will look for ``foo.html`` in these
directories, in this order:
@@ -914,10 +939,12 @@ loaders that come with Django:
You can enable this loader by setting :setting:`APP_DIRS
<TEMPLATES-APP_DIRS>` to ``True``::
- TEMPLATES = [{
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'APP_DIRS': True,
- }]
+ TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "APP_DIRS": True,
+ }
+ ]
``django.template.loaders.cached.Loader``
@@ -939,19 +966,24 @@ loaders that come with Django:
You can manually specify template caching with some custom template loaders
using settings like this::
- TEMPLATES = [{
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [BASE_DIR / 'templates'],
- 'OPTIONS': {
- 'loaders': [
- ('django.template.loaders.cached.Loader', [
- 'django.template.loaders.filesystem.Loader',
- 'django.template.loaders.app_directories.Loader',
- 'path.to.custom.Loader',
- ]),
- ],
- },
- }]
+ TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "DIRS": [BASE_DIR / "templates"],
+ "OPTIONS": {
+ "loaders": [
+ (
+ "django.template.loaders.cached.Loader",
+ [
+ "django.template.loaders.filesystem.Loader",
+ "django.template.loaders.app_directories.Loader",
+ "path.to.custom.Loader",
+ ],
+ ),
+ ],
+ },
+ }
+ ]
.. note::
@@ -970,16 +1002,21 @@ loaders that come with Django:
This loader takes a dictionary of templates as its first argument::
- TEMPLATES = [{
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'OPTIONS': {
- 'loaders': [
- ('django.template.loaders.locmem.Loader', {
- 'index.html': 'content here',
- }),
- ],
- },
- }]
+ TEMPLATES = [
+ {
+ "BACKEND": "django.template.backends.django.DjangoTemplates",
+ "OPTIONS": {
+ "loaders": [
+ (
+ "django.template.loaders.locmem.Loader",
+ {
+ "index.html": "content here",
+ },
+ ),
+ ],
+ },
+ }
+ ]
This loader is disabled by default.
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index d7df35ec66..2c8e67f9e3 100644
--- a/docs/ref/templates/builtins.txt
+++ b/docs/ref/templates/builtins.txt
@@ -945,11 +945,11 @@ is a list of cities represented by dictionaries containing ``"name"``,
.. code-block:: python
cities = [
- {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'},
- {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'},
- {'name': 'New York', 'population': '20,000,000', 'country': 'USA'},
- {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'},
- {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},
+ {"name": "Mumbai", "population": "19,000,000", "country": "India"},
+ {"name": "Calcutta", "population": "15,000,000", "country": "India"},
+ {"name": "New York", "population": "20,000,000", "country": "USA"},
+ {"name": "Chicago", "population": "7,000,000", "country": "USA"},
+ {"name": "Tokyo", "population": "33,000,000", "country": "Japan"},
]
...and you'd like to display a hierarchical list that is ordered by country,
@@ -1031,11 +1031,11 @@ grouped together):
.. code-block:: python
cities = [
- {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'},
- {'name': 'New York', 'population': '20,000,000', 'country': 'USA'},
- {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'},
- {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'},
- {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},
+ {"name": "Mumbai", "population": "19,000,000", "country": "India"},
+ {"name": "New York", "population": "20,000,000", "country": "USA"},
+ {"name": "Calcutta", "population": "15,000,000", "country": "India"},
+ {"name": "Chicago", "population": "7,000,000", "country": "USA"},
+ {"name": "Tokyo", "population": "33,000,000", "country": "Japan"},
]
With this input for ``cities``, the example ``{% regroup %}`` template code
@@ -1255,14 +1255,14 @@ takes a client ID (here, ``client()`` is a method inside the views file
.. code-block:: python
- path('client/<int:id>/', app_views.client, name='app-views-client')
+ path("client/<int:id>/", app_views.client, name="app-views-client")
If this app's URLconf is included into the project's URLconf under a path
such as this:
.. code-block:: python
- path('clients/', include('project_name.app_name.urls'))
+ path("clients/", include("project_name.app_name.urls"))
...then, in a template, you can create a link to this view like this::
@@ -1699,9 +1699,9 @@ If ``value`` is:
.. code-block:: python
[
- {'name': 'zed', 'age': 19},
- {'name': 'amy', 'age': 22},
- {'name': 'joe', 'age': 31},
+ {"name": "zed", "age": 19},
+ {"name": "amy", "age": 22},
+ {"name": "joe", "age": 31},
]
then the output would be:
@@ -1709,9 +1709,9 @@ then the output would be:
.. code-block:: python
[
- {'name': 'amy', 'age': 22},
- {'name': 'joe', 'age': 31},
- {'name': 'zed', 'age': 19},
+ {"name": "amy", "age": 22},
+ {"name": "joe", "age": 31},
+ {"name": "zed", "age": 19},
]
You can also do more complicated things like:
@@ -1727,9 +1727,9 @@ If ``books`` is:
.. code-block:: python
[
- {'title': '1984', 'author': {'name': 'George', 'age': 45}},
- {'title': 'Timequake', 'author': {'name': 'Kurt', 'age': 75}},
- {'title': 'Alice', 'author': {'name': 'Lewis', 'age': 33}},
+ {"title": "1984", "author": {"name": "George", "age": 45}},
+ {"title": "Timequake", "author": {"name": "Kurt", "age": 75}},
+ {"title": "Alice", "author": {"name": "Lewis", "age": 33}},
]
then the output would be:
@@ -1752,9 +1752,9 @@ If ``value`` is:
.. code-block:: python
[
- ('a', '42'),
- ('c', 'string'),
- ('b', 'foo'),
+ ("a", "42"),
+ ("c", "string"),
+ ("b", "foo"),
]
then the output would be:
@@ -1762,9 +1762,9 @@ then the output would be:
.. code-block:: python
[
- ('a', '42'),
- ('b', 'foo'),
- ('c', 'string'),
+ ("a", "42"),
+ ("b", "foo"),
+ ("c", "string"),
]
You must pass the index as an integer rather than a string. The following
diff --git a/docs/ref/unicode.txt b/docs/ref/unicode.txt
index b73814c861..81a0b08aad 100644
--- a/docs/ref/unicode.txt
+++ b/docs/ref/unicode.txt
@@ -180,9 +180,9 @@ An example might clarify things here:
>>> from urllib.parse import quote
>>> from django.utils.encoding import iri_to_uri
- >>> quote('Paris & Orléans')
+ >>> quote("Paris & Orléans")
'Paris%20%26%20Orl%C3%A9ans'
- >>> iri_to_uri('/favorites/François/%s' % quote('Paris & Orléans'))
+ >>> iri_to_uri("/favorites/François/%s" % quote("Paris & Orléans"))
'/favorites/Fran%C3%A7ois/Paris%20%26%20Orl%C3%A9ans'
If you look carefully, you can see that the portion that was generated by
@@ -200,9 +200,9 @@ An example to demonstrate:
.. code-block:: pycon
>>> from django.utils.encoding import uri_to_iri
- >>> uri_to_iri('/%E2%99%A5%E2%99%A5/?utf8=%E2%9C%93')
+ >>> uri_to_iri("/%E2%99%A5%E2%99%A5/?utf8=%E2%9C%93")
'/♥♥/?utf8=✓'
- >>> uri_to_iri('%A9hello%3Fworld')
+ >>> uri_to_iri("%A9hello%3Fworld")
'%A9hello%3Fworld'
In the first example, the UTF-8 characters are unquoted. In the second, the
@@ -245,8 +245,9 @@ above_. For example::
from urllib.parse import quote
from django.utils.encoding import iri_to_uri
+
def get_absolute_url(self):
- url = '/person/%s/?x=0&y=0' % quote(self.location)
+ url = "/person/%s/?x=0&y=0" % quote(self.location)
return iri_to_uri(url)
This function returns a correctly encoded URL even if ``self.location`` is
@@ -262,7 +263,8 @@ Templates
Use strings when creating templates manually::
from django.template import Template
- t2 = Template('This is a string template.')
+
+ t2 = Template("This is a string template.")
But the common case is to read templates from the filesystem. If your template
files are not stored with a UTF-8 encoding, adjust the :setting:`TEMPLATES`
@@ -303,6 +305,7 @@ environment. Check your current configuration in an interactive Python shell by
running::
import sys
+
sys.getfilesystemencoding()
This should output "UTF-8".
@@ -340,7 +343,7 @@ the ``encoding`` attribute on an ``HttpRequest`` instance. For example::
def some_view(request):
# We know that the data must be encoded as KOI8-R (for some reason).
- request.encoding = 'koi8-r'
+ request.encoding = "koi8-r"
...
You can even change the encoding after having accessed ``request.GET`` or
diff --git a/docs/ref/urlresolvers.txt b/docs/ref/urlresolvers.txt
index 264d747f4d..89564279a1 100644
--- a/docs/ref/urlresolvers.txt
+++ b/docs/ref/urlresolvers.txt
@@ -17,30 +17,32 @@ callable view object. For example, given the following ``url``::
from news import views
- path('archive/', views.archive, name='news-archive')
+ path("archive/", views.archive, name="news-archive")
you can use any of the following to reverse the URL::
# using the named URL
- reverse('news-archive')
+ reverse("news-archive")
# passing a callable object
# (This is discouraged because you can't reverse namespaced views this way.)
from news import views
+
reverse(views.archive)
If the URL accepts arguments, you may pass them in ``args``. For example::
from django.urls import reverse
+
def myview(request):
- return HttpResponseRedirect(reverse('arch-summary', args=[1945]))
+ return HttpResponseRedirect(reverse("arch-summary", args=[1945]))
You can also pass ``kwargs`` instead of ``args``. For example:
.. code-block:: pycon
- >>> reverse('admin:app_list', kwargs={'app_label': 'auth'})
+ >>> reverse("admin:app_list", kwargs={"app_label": "auth"})
'/admin/auth/'
``args`` and ``kwargs`` cannot be passed to ``reverse()`` at the same time.
@@ -71,7 +73,7 @@ use for reversing. By default, the root URLconf for the current thread is used.
.. code-block:: pycon
- >>> reverse('cities', args=['Orléans'])
+ >>> reverse("cities", args=["Orléans"])
'.../Orl%C3%A9ans/'
Applying further encoding (such as :func:`urllib.parse.quote`) to the output
@@ -190,13 +192,13 @@ A :class:`ResolverMatch` object can then be interrogated to provide
information about the URL pattern that matches a URL::
# Resolve a URL
- match = resolve('/some/path/')
+ match = resolve("/some/path/")
# Print the URL pattern that matches the URL
print(match.url_name)
A :class:`ResolverMatch` object can also be assigned to a triple::
- func, args, kwargs = resolve('/some/path/')
+ func, args, kwargs = resolve("/some/path/")
One possible use of :func:`~django.urls.resolve` would be to test whether a
view would raise a ``Http404`` error before redirecting to it::
@@ -205,19 +207,20 @@ view would raise a ``Http404`` error before redirecting to it::
from django.urls import resolve
from django.http import Http404, HttpResponseRedirect
+
def myview(request):
- next = request.META.get('HTTP_REFERER', None) or '/'
+ next = request.META.get("HTTP_REFERER", None) or "/"
response = HttpResponseRedirect(next)
# modify the request and response as required, e.g. change locale
# and set corresponding locale cookie
view, args, kwargs = resolve(urlparse(next)[2])
- kwargs['request'] = request
+ kwargs["request"] = request
try:
view(*args, **kwargs)
except Http404:
- return HttpResponseRedirect('/')
+ return HttpResponseRedirect("/")
return response
``get_script_prefix()``
diff --git a/docs/ref/urls.txt b/docs/ref/urls.txt
index 35b0e441a1..be8380ed5a 100644
--- a/docs/ref/urls.txt
+++ b/docs/ref/urls.txt
@@ -17,12 +17,12 @@ Returns an element for inclusion in ``urlpatterns``. For example::
from django.urls import include, path
urlpatterns = [
- path('index/', views.index, name='main-view'),
- path('bio/<username>/', views.bio, name='bio'),
- path('articles/<slug:title>/', views.article, name='article-detail'),
- path('articles/<slug:title>/<int:section>/', views.section, name='article-section'),
- path('blog/', include('blog.urls')),
- ...
+ path("index/", views.index, name="main-view"),
+ path("bio/<username>/", views.bio, name="bio"),
+ path("articles/<slug:title>/", views.article, name="article-detail"),
+ path("articles/<slug:title>/<int:section>/", views.section, name="article-section"),
+ path("blog/", include("blog.urls")),
+ ...,
]
The ``route`` argument should be a string or
@@ -56,10 +56,10 @@ Returns an element for inclusion in ``urlpatterns``. For example::
from django.urls import include, re_path
urlpatterns = [
- re_path(r'^index/$', views.index, name='index'),
- re_path(r'^bio/(?P<username>\w+)/$', views.bio, name='bio'),
- re_path(r'^blog/', include('blog.urls')),
- ...
+ re_path(r"^index/$", views.index, name="index"),
+ re_path(r"^bio/(?P<username>\w+)/$", views.bio, name="bio"),
+ re_path(r"^blog/", include("blog.urls")),
+ ...,
]
The ``route`` argument should be a string or
diff --git a/docs/ref/utils.txt b/docs/ref/utils.txt
index a653389cf4..c0d80406a1 100644
--- a/docs/ref/utils.txt
+++ b/docs/ref/utils.txt
@@ -184,6 +184,7 @@ The functions defined in this module share the following properties:
cache_page = decorator_from_middleware_with_args(CacheMiddleware)
+
@cache_page(3600)
def my_view(request):
pass
@@ -314,8 +315,9 @@ Sample usage:
... link="http://www.holovaty.com/test/",
... description="Testing.",
... )
- >>> with open('test.rss', 'w') as fp:
- ... feed.write(fp, 'utf-8')
+ >>> with open("test.rss", "w") as fp:
+ ... feed.write(fp, "utf-8")
+ ...
For simplifying the selection of a generator use ``feedgenerator.DefaultFeed``
which is currently ``Rss201rev2Feed``
@@ -442,12 +444,12 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004
# the model
class Person(models.Model):
-
def friends(self):
# expensive computation
...
return friends
+
# in the view:
if person.friends():
...
@@ -464,8 +466,8 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004
from django.utils.functional import cached_property
- class Person(models.Model):
+ class Person(models.Model):
@cached_property
def friends(self):
...
@@ -480,7 +482,7 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004
The cached value can be treated like an ordinary attribute of the instance::
# clear it, requiring re-computation next time it's called
- del person.friends # or delattr(person, "friends")
+ del person.friends # or delattr(person, "friends")
# set a value manually, that will persist on the instance until cleared
person.friends = ["Huckleberry Finn", "Tom Sawyer"]
@@ -506,10 +508,10 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004
value of the cached property will persist until you delete it as described
above::
- x = person.friends # calls first time
- y = person.get_friends() # calls again
- z = person.friends # does not call
- x is z # is True
+ x = person.friends # calls first time
+ y = person.get_friends() # calls again
+ z = person.friends # does not call
+ x is z # is True
.. class:: classproperty(method=None)
@@ -539,11 +541,15 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004
from django.utils.functional import keep_lazy, keep_lazy_text
+
def fancy_utility_function(s, *args, **kwargs):
# Do some conversion on string 's'
...
+
+
fancy_utility_function = keep_lazy(str)(fancy_utility_function)
+
# Or more succinctly:
@keep_lazy(str)
def fancy_utility_function(s, *args, **kwargs):
@@ -569,11 +575,13 @@ https://web.archive.org/web/20110718035220/http://diveintomark.org/archives/2004
from django.utils.functional import keep_lazy, keep_lazy_text
+
# Our previous example was:
@keep_lazy(str)
def fancy_utility_function(s, *args, **kwargs):
...
+
# Which can be rewritten as:
@keep_lazy_text
def fancy_utility_function(s, *args, **kwargs):
@@ -614,15 +622,19 @@ escaping HTML.
So, instead of writing::
- mark_safe("%s <b>%s</b> %s" % (
- some_html,
- escape(some_text),
- escape(some_other_text),
- ))
+ mark_safe(
+ "%s <b>%s</b> %s"
+ % (
+ some_html,
+ escape(some_text),
+ escape(some_other_text),
+ )
+ )
You should instead use::
- format_html("{} <b>{}</b> {}",
+ format_html(
+ "{} <b>{}</b> {}",
mark_safe(some_html),
some_text,
some_other_text,
@@ -647,10 +659,7 @@ escaping HTML.
``args_generator`` should be an iterator that returns the sequence of
``args`` that will be passed to :func:`format_html`. For example::
- format_html_join(
- '\n', "<li>{} {}</li>",
- ((u.first_name, u.last_name) for u in users)
- )
+ format_html_join("\n", "<li>{} {}</li>", ((u.first_name, u.last_name) for u in users))
.. function:: json_script(value, element_id=None, encoder=None)
@@ -766,7 +775,8 @@ Functions for working with Python modules.
example::
from django.utils.module_loading import import_string
- ValidationError = import_string('django.core.exceptions.ValidationError')
+
+ ValidationError = import_string("django.core.exceptions.ValidationError")
is equivalent to::
@@ -805,7 +815,7 @@ appropriate entities.
.. code-block:: pycon
- >>> mystr = '<b>Hello World</b> '
+ >>> mystr = "<b>Hello World</b> "
>>> mystr = mark_safe(mystr)
>>> type(mystr)
<class 'django.utils.safestring.SafeString'>
@@ -830,8 +840,10 @@ appropriate entities.
from django.utils.translation import pgettext_lazy
urlpatterns = [
- path(format_lazy('{person}/<int:pk>/', person=pgettext_lazy('URL', 'person')),
- PersonDetailView.as_view()),
+ path(
+ format_lazy("{person}/<int:pk>/", person=pgettext_lazy("URL", "person")),
+ PersonDetailView.as_view(),
+ ),
]
This example allows translators to translate part of the URL. If "person"
@@ -853,7 +865,7 @@ appropriate entities.
.. code-block:: pycon
- >>> slugify(' Joel is a slug ')
+ >>> slugify(" Joel is a slug ")
'joel-is-a-slug'
If you want to allow Unicode characters, pass ``allow_unicode=True``. For
@@ -861,7 +873,7 @@ appropriate entities.
.. code-block:: pycon
- >>> slugify('你好 World', allow_unicode=True)
+ >>> slugify("你好 World", allow_unicode=True)
'你好-world'
.. _time-zone-selection-functions:
diff --git a/docs/ref/validators.txt b/docs/ref/validators.txt
index 726e714e7e..a091d20dbb 100644
--- a/docs/ref/validators.txt
+++ b/docs/ref/validators.txt
@@ -18,11 +18,12 @@ For example, here's a validator that only allows even numbers::
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
+
def validate_even(value):
if value % 2 != 0:
raise ValidationError(
- _('%(value)s is not an even number'),
- params={'value': value},
+ _("%(value)s is not an even number"),
+ params={"value": value},
)
You can add this to a model field via the field's :attr:`~django.db.models.Field.validators`
@@ -30,6 +31,7 @@ argument::
from django.db import models
+
class MyModel(models.Model):
even_field = models.IntegerField(validators=[validate_even])
@@ -38,6 +40,7 @@ use the same validator with forms::
from django import forms
+
class MyForm(forms.Form):
even_field = forms.IntegerField(validators=[validate_even])
diff --git a/docs/ref/views.txt b/docs/ref/views.txt
index 250ab47932..b60ffc2ed8 100644
--- a/docs/ref/views.txt
+++ b/docs/ref/views.txt
@@ -33,9 +33,13 @@ built-in handling for user-uploaded files, but you can have Django serve your
if settings.DEBUG:
urlpatterns += [
- re_path(r'^media/(?P<path>.*)$', serve, {
- 'document_root': settings.MEDIA_ROOT,
- }),
+ re_path(
+ r"^media/(?P<path>.*)$",
+ serve,
+ {
+ "document_root": settings.MEDIA_ROOT,
+ },
+ ),
]
Note, the snippet assumes your :setting:`MEDIA_URL` has a value of
@@ -131,6 +135,7 @@ view you can use code like this::
from django.core.exceptions import PermissionDenied
+
def edit(request, pk):
if not request.user.is_staff:
raise PermissionDenied