summaryrefslogtreecommitdiff
path: root/docs/topics/forms
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/topics/forms
parent6015bab80e28aef2669f6fac53423aa65f70cb08 (diff)
Fixed #34140 -- Reformatted code blocks in docs with blacken-docs.
Diffstat (limited to 'docs/topics/forms')
-rw-r--r--docs/topics/forms/formsets.txt217
-rw-r--r--docs/topics/forms/index.txt29
-rw-r--r--docs/topics/forms/media.txt58
-rw-r--r--docs/topics/forms/modelforms.txt160
4 files changed, 280 insertions, 184 deletions
diff --git a/docs/topics/forms/formsets.txt b/docs/topics/forms/formsets.txt
index 85c35dc2d0..a2e265a91f 100644
--- a/docs/topics/forms/formsets.txt
+++ b/docs/topics/forms/formsets.txt
@@ -16,6 +16,7 @@ form:
>>> class ArticleForm(forms.Form):
... title = forms.CharField()
... pub_date = forms.DateField()
+ ...
You might want to allow the user to create several articles at once. To create
a formset out of an ``ArticleForm`` you would do:
@@ -34,6 +35,7 @@ in the formset and display them as you would with a regular form:
>>> formset = ArticleFormSet()
>>> for form in formset:
... print(form)
+ ...
<div><label for="id_form-0-title">Title:</label><input type="text" name="form-0-title" id="id_form-0-title"></div>
<div><label for="id_form-0-pub_date">Pub date:</label><input type="text" name="form-0-pub_date" id="id_form-0-pub_date"></div>
@@ -71,13 +73,18 @@ example:
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
- >>> formset = ArticleFormSet(initial=[
- ... {'title': 'Django is now open source',
- ... 'pub_date': datetime.date.today(),}
- ... ])
+ >>> formset = ArticleFormSet(
+ ... initial=[
+ ... {
+ ... "title": "Django is now open source",
+ ... "pub_date": datetime.date.today(),
+ ... }
+ ... ]
+ ... )
>>> for form in formset:
... print(form)
+ ...
<div><label for="id_form-0-title">Title:</label><input type="text" name="form-0-title" value="Django is now open source" id="id_form-0-title"></div>
<div><label for="id_form-0-pub_date">Pub date:</label><input type="text" name="form-0-pub_date" value="2023-02-11" id="id_form-0-pub_date"></div>
<div><label for="id_form-1-title">Title:</label><input type="text" name="form-1-title" id="id_form-1-title"></div>
@@ -114,6 +121,7 @@ gives you the ability to limit the number of forms the formset will display:
>>> formset = ArticleFormSet()
>>> for form in formset:
... print(form)
+ ...
<div><label for="id_form-0-title">Title:</label><input type="text" name="form-0-title" id="id_form-0-title"></div>
<div><label for="id_form-0-pub_date">Pub date:</label><input type="text" name="form-0-pub_date" id="id_form-0-pub_date"></div>
@@ -153,8 +161,8 @@ protects against memory exhaustion attacks using forged ``POST`` requests:
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, absolute_max=1500)
>>> data = {
- ... 'form-TOTAL_FORMS': '1501',
- ... 'form-INITIAL_FORMS': '0',
+ ... "form-TOTAL_FORMS": "1501",
+ ... "form-INITIAL_FORMS": "0",
... }
>>> formset = ArticleFormSet(data)
>>> len(formset.forms)
@@ -182,8 +190,8 @@ all forms in the formset:
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm)
>>> data = {
- ... 'form-TOTAL_FORMS': '1',
- ... 'form-INITIAL_FORMS': '0',
+ ... "form-TOTAL_FORMS": "1",
+ ... "form-INITIAL_FORMS": "0",
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
@@ -196,12 +204,12 @@ provide an invalid article:
.. code-block:: pycon
>>> data = {
- ... 'form-TOTAL_FORMS': '2',
- ... 'form-INITIAL_FORMS': '0',
- ... 'form-0-title': 'Test',
- ... 'form-0-pub_date': '1904-06-16',
- ... 'form-1-title': 'Test',
- ... 'form-1-pub_date': '', # <-- this date is missing but required
+ ... "form-TOTAL_FORMS": "2",
+ ... "form-INITIAL_FORMS": "0",
+ ... "form-0-title": "Test",
+ ... "form-0-pub_date": "1904-06-16",
+ ... "form-1-title": "Test",
+ ... "form-1-pub_date": "", # <-- this date is missing but required
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
@@ -239,10 +247,10 @@ sent without any data):
.. code-block:: pycon
>>> data = {
- ... 'form-TOTAL_FORMS': '1',
- ... 'form-INITIAL_FORMS': '0',
- ... 'form-0-title': '',
- ... 'form-0-pub_date': '',
+ ... "form-TOTAL_FORMS": "1",
+ ... "form-INITIAL_FORMS": "0",
+ ... "form-0-title": "",
+ ... "form-0-pub_date": "",
... }
>>> formset = ArticleFormSet(data)
>>> formset.has_changed()
@@ -262,8 +270,8 @@ provide this management data, the formset will be invalid:
.. code-block:: pycon
>>> data = {
- ... 'form-0-title': 'Test',
- ... 'form-0-pub_date': '',
+ ... "form-0-title": "Test",
+ ... "form-0-pub_date": "",
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
@@ -339,7 +347,9 @@ And here is a custom error message:
.. code-block:: pycon
- >>> formset = ArticleFormSet({}, error_messages={'missing_management_form': 'Sorry, something went wrong.'})
+ >>> formset = ArticleFormSet(
+ ... {}, error_messages={"missing_management_form": "Sorry, something went wrong."}
+ ... )
>>> formset.is_valid()
False
>>> formset.non_form_errors()
@@ -368,19 +378,20 @@ is where you define your own validation that works at the formset level:
... for form in self.forms:
... if self.can_delete and self._should_delete_form(form):
... continue
- ... title = form.cleaned_data.get('title')
+ ... title = form.cleaned_data.get("title")
... if title in titles:
... raise ValidationError("Articles in a set must have distinct titles.")
... titles.append(title)
+ ...
>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
>>> data = {
- ... 'form-TOTAL_FORMS': '2',
- ... 'form-INITIAL_FORMS': '0',
- ... 'form-0-title': 'Test',
- ... 'form-0-pub_date': '1904-06-16',
- ... 'form-1-title': 'Test',
- ... 'form-1-pub_date': '1912-06-23',
+ ... "form-TOTAL_FORMS": "2",
+ ... "form-INITIAL_FORMS": "0",
+ ... "form-0-title": "Test",
+ ... "form-0-pub_date": "1904-06-16",
+ ... "form-1-title": "Test",
+ ... "form-1-pub_date": "1912-06-23",
... }
>>> formset = ArticleFormSet(data)
>>> formset.is_valid()
@@ -512,12 +523,15 @@ Lets you create a formset with the ability to order:
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, can_order=True)
- >>> formset = ArticleFormSet(initial=[
- ... {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
- ... {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
- ... ])
+ >>> formset = ArticleFormSet(
+ ... initial=[
+ ... {"title": "Article #1", "pub_date": datetime.date(2008, 5, 10)},
+ ... {"title": "Article #2", "pub_date": datetime.date(2008, 5, 11)},
+ ... ]
+ ... )
>>> for form in formset:
... print(form)
+ ...
<div><label for="id_form-0-title">Title:</label><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title"></div>
<div><label for="id_form-0-pub_date">Pub date:</label><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date"></div>
<div><label for="id_form-0-ORDER">Order:</label><input type="number" name="form-0-ORDER" value="1" id="id_form-0-ORDER"></div>
@@ -536,27 +550,31 @@ happen when the user changes these values:
.. code-block:: pycon
>>> data = {
- ... 'form-TOTAL_FORMS': '3',
- ... 'form-INITIAL_FORMS': '2',
- ... 'form-0-title': 'Article #1',
- ... 'form-0-pub_date': '2008-05-10',
- ... 'form-0-ORDER': '2',
- ... 'form-1-title': 'Article #2',
- ... 'form-1-pub_date': '2008-05-11',
- ... 'form-1-ORDER': '1',
- ... 'form-2-title': 'Article #3',
- ... 'form-2-pub_date': '2008-05-01',
- ... 'form-2-ORDER': '0',
+ ... "form-TOTAL_FORMS": "3",
+ ... "form-INITIAL_FORMS": "2",
+ ... "form-0-title": "Article #1",
+ ... "form-0-pub_date": "2008-05-10",
+ ... "form-0-ORDER": "2",
+ ... "form-1-title": "Article #2",
+ ... "form-1-pub_date": "2008-05-11",
+ ... "form-1-ORDER": "1",
+ ... "form-2-title": "Article #3",
+ ... "form-2-pub_date": "2008-05-01",
+ ... "form-2-ORDER": "0",
... }
- >>> formset = ArticleFormSet(data, initial=[
- ... {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
- ... {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
- ... ])
+ >>> formset = ArticleFormSet(
+ ... data,
+ ... initial=[
+ ... {"title": "Article #1", "pub_date": datetime.date(2008, 5, 10)},
+ ... {"title": "Article #2", "pub_date": datetime.date(2008, 5, 11)},
+ ... ],
+ ... )
>>> formset.is_valid()
True
>>> for form in formset.ordered_forms:
... print(form.cleaned_data)
+ ...
{'pub_date': datetime.date(2008, 5, 1), 'ORDER': 0, 'title': 'Article #3'}
{'pub_date': datetime.date(2008, 5, 11), 'ORDER': 1, 'title': 'Article #2'}
{'pub_date': datetime.date(2008, 5, 10), 'ORDER': 2, 'title': 'Article #1'}
@@ -583,8 +601,11 @@ Set ``ordering_widget`` to specify the widget class to be used with
>>> from myapp.forms import ArticleForm
>>> class BaseArticleFormSet(BaseFormSet):
... ordering_widget = HiddenInput
+ ...
- >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet, can_order=True)
+ >>> ArticleFormSet = formset_factory(
+ ... ArticleForm, formset=BaseArticleFormSet, can_order=True
+ ... )
``get_ordering_widget``
^^^^^^^^^^^^^^^^^^^^^^^
@@ -600,9 +621,12 @@ use with ``can_order``:
>>> from myapp.forms import ArticleForm
>>> class BaseArticleFormSet(BaseFormSet):
... def get_ordering_widget(self):
- ... return HiddenInput(attrs={'class': 'ordering'})
+ ... return HiddenInput(attrs={"class": "ordering"})
+ ...
- >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet, can_order=True)
+ >>> ArticleFormSet = formset_factory(
+ ... ArticleForm, formset=BaseArticleFormSet, can_order=True
+ ... )
``can_delete``
--------------
@@ -618,12 +642,15 @@ Lets you create a formset with the ability to select forms for deletion:
>>> from django.forms import formset_factory
>>> from myapp.forms import ArticleForm
>>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True)
- >>> formset = ArticleFormSet(initial=[
- ... {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
- ... {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
- ... ])
+ >>> formset = ArticleFormSet(
+ ... initial=[
+ ... {"title": "Article #1", "pub_date": datetime.date(2008, 5, 10)},
+ ... {"title": "Article #2", "pub_date": datetime.date(2008, 5, 11)},
+ ... ]
+ ... )
>>> for form in formset:
... print(form)
+ ...
<div><label for="id_form-0-title">Title:</label><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title"></div>
<div><label for="id_form-0-pub_date">Pub date:</label><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date"></div>
<div><label for="id_form-0-DELETE">Delete:</label><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE"></div>
@@ -641,23 +668,26 @@ delete fields you can access them with ``deleted_forms``:
.. code-block:: pycon
>>> data = {
- ... 'form-TOTAL_FORMS': '3',
- ... 'form-INITIAL_FORMS': '2',
- ... 'form-0-title': 'Article #1',
- ... 'form-0-pub_date': '2008-05-10',
- ... 'form-0-DELETE': 'on',
- ... 'form-1-title': 'Article #2',
- ... 'form-1-pub_date': '2008-05-11',
- ... 'form-1-DELETE': '',
- ... 'form-2-title': '',
- ... 'form-2-pub_date': '',
- ... 'form-2-DELETE': '',
+ ... "form-TOTAL_FORMS": "3",
+ ... "form-INITIAL_FORMS": "2",
+ ... "form-0-title": "Article #1",
+ ... "form-0-pub_date": "2008-05-10",
+ ... "form-0-DELETE": "on",
+ ... "form-1-title": "Article #2",
+ ... "form-1-pub_date": "2008-05-11",
+ ... "form-1-DELETE": "",
+ ... "form-2-title": "",
+ ... "form-2-pub_date": "",
+ ... "form-2-DELETE": "",
... }
- >>> formset = ArticleFormSet(data, initial=[
- ... {'title': 'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
- ... {'title': 'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
- ... ])
+ >>> formset = ArticleFormSet(
+ ... data,
+ ... initial=[
+ ... {"title": "Article #1", "pub_date": datetime.date(2008, 5, 10)},
+ ... {"title": "Article #2", "pub_date": datetime.date(2008, 5, 11)},
+ ... ],
+ ... )
>>> [form.cleaned_data for form in formset.deleted_forms]
[{'DELETE': True, 'pub_date': datetime.date(2008, 5, 10), 'title': 'Article #1'}]
@@ -676,6 +706,7 @@ them:
>>> instances = formset.save(commit=False)
>>> for obj in formset.deleted_objects:
... obj.delete()
+ ...
On the other hand, if you are using a plain ``FormSet``, it's up to you to
handle ``formset.deleted_forms``, perhaps in your formset's ``save()`` method,
@@ -703,8 +734,11 @@ Set ``deletion_widget`` to specify the widget class to be used with
>>> from myapp.forms import ArticleForm
>>> class BaseArticleFormSet(BaseFormSet):
... deletion_widget = HiddenInput
+ ...
- >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet, can_delete=True)
+ >>> ArticleFormSet = formset_factory(
+ ... ArticleForm, formset=BaseArticleFormSet, can_delete=True
+ ... )
``get_deletion_widget``
^^^^^^^^^^^^^^^^^^^^^^^
@@ -720,9 +754,12 @@ use with ``can_delete``:
>>> from myapp.forms import ArticleForm
>>> class BaseArticleFormSet(BaseFormSet):
... def get_deletion_widget(self):
- ... return HiddenInput(attrs={'class': 'deletion'})
+ ... return HiddenInput(attrs={"class": "deletion"})
+ ...
- >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet, can_delete=True)
+ >>> ArticleFormSet = formset_factory(
+ ... ArticleForm, formset=BaseArticleFormSet, can_delete=True
+ ... )
``can_delete_extra``
--------------------
@@ -751,11 +788,13 @@ fields/attributes of the order and deletion fields:
... def add_fields(self, form, index):
... super().add_fields(form, index)
... form.fields["my_field"] = forms.CharField()
+ ...
>>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
>>> formset = ArticleFormSet()
>>> for form in formset:
... print(form)
+ ...
<div><label for="id_form-0-title">Title:</label><input type="text" name="form-0-title" id="id_form-0-title"></div>
<div><label for="id_form-0-pub_date">Pub date:</label><input type="text" name="form-0-pub_date" id="id_form-0-pub_date"></div>
<div><label for="id_form-0-my_field">My field:</label><input type="text" name="form-0-my_field" id="id_form-0-my_field"></div>
@@ -778,9 +817,10 @@ You can pass this parameter when instantiating the formset:
... def __init__(self, *args, user, **kwargs):
... self.user = user
... super().__init__(*args, **kwargs)
+ ...
>>> ArticleFormSet = formset_factory(MyArticleForm)
- >>> formset = ArticleFormSet(form_kwargs={'user': request.user})
+ >>> formset = ArticleFormSet(form_kwargs={"user": request.user})
The ``form_kwargs`` may also depend on the specific form instance. The formset
base class provides a ``get_form_kwargs`` method. The method takes a single
@@ -795,8 +835,9 @@ argument - the index of the form in the formset. The index is ``None`` for the
>>> class BaseArticleFormSet(BaseFormSet):
... def get_form_kwargs(self, index):
... kwargs = super().get_form_kwargs(index)
- ... kwargs['custom_kwarg'] = index
+ ... kwargs["custom_kwarg"] = index
... return kwargs
+ ...
>>> ArticleFormSet = formset_factory(MyArticleForm, formset=BaseArticleFormSet)
>>> formset = ArticleFormSet()
@@ -924,16 +965,17 @@ use the management form inside the template. Let's look at a sample view::
from django.shortcuts import render
from myapp.forms import ArticleForm
+
def manage_articles(request):
ArticleFormSet = formset_factory(ArticleForm)
- if request.method == 'POST':
+ if request.method == "POST":
formset = ArticleFormSet(request.POST, request.FILES)
if formset.is_valid():
# do something with the formset.cleaned_data
pass
else:
formset = ArticleFormSet()
- return render(request, 'manage_articles.html', {'formset': formset})
+ return render(request, "manage_articles.html", {"formset": formset})
The ``manage_articles.html`` template might look like this:
@@ -1009,22 +1051,27 @@ a look at how this might be accomplished::
from django.shortcuts import render
from myapp.forms import ArticleForm, BookForm
+
def manage_articles(request):
ArticleFormSet = formset_factory(ArticleForm)
BookFormSet = formset_factory(BookForm)
- if request.method == 'POST':
- article_formset = ArticleFormSet(request.POST, request.FILES, prefix='articles')
- book_formset = BookFormSet(request.POST, request.FILES, prefix='books')
+ if request.method == "POST":
+ article_formset = ArticleFormSet(request.POST, request.FILES, prefix="articles")
+ book_formset = BookFormSet(request.POST, request.FILES, prefix="books")
if article_formset.is_valid() and book_formset.is_valid():
# do something with the cleaned_data on the formsets.
pass
else:
- article_formset = ArticleFormSet(prefix='articles')
- book_formset = BookFormSet(prefix='books')
- return render(request, 'manage_articles.html', {
- 'article_formset': article_formset,
- 'book_formset': book_formset,
- })
+ article_formset = ArticleFormSet(prefix="articles")
+ book_formset = BookFormSet(prefix="books")
+ return render(
+ request,
+ "manage_articles.html",
+ {
+ "article_formset": article_formset,
+ "book_formset": book_formset,
+ },
+ )
You would then render the formsets as normal. It is important to point out
that you need to pass ``prefix`` on both the POST and non-POST cases so that
diff --git a/docs/topics/forms/index.txt b/docs/topics/forms/index.txt
index 3d409f5f06..fec2b03251 100644
--- a/docs/topics/forms/index.txt
+++ b/docs/topics/forms/index.txt
@@ -231,8 +231,9 @@ it in Django is this:
from django import forms
+
class NameForm(forms.Form):
- your_name = forms.CharField(label='Your name', max_length=100)
+ your_name = forms.CharField(label="Your name", max_length=100)
This defines a :class:`Form` class with a single field (``your_name``). We've
applied a human-friendly label to the field, which will appear in the
@@ -284,9 +285,10 @@ want it to be published:
from .forms import NameForm
+
def get_name(request):
# if this is a POST request we need to process the form data
- if request.method == 'POST':
+ if request.method == "POST":
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
@@ -294,13 +296,13 @@ want it to be published:
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
- return HttpResponseRedirect('/thanks/')
+ return HttpResponseRedirect("/thanks/")
# if a GET (or any other method) we'll create a blank form
else:
form = NameForm()
- return render(request, 'name.html', {'form': form})
+ return render(request, "name.html", {"form": form})
If we arrive at this view with a ``GET`` request, it will create an empty form
instance and place it in the template context to be rendered. This is what we
@@ -408,6 +410,7 @@ to implement "contact me" functionality on a personal website:
from django import forms
+
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
@@ -458,17 +461,17 @@ Here's how the form data could be processed in the view that handles this form:
from django.core.mail import send_mail
if form.is_valid():
- subject = form.cleaned_data['subject']
- message = form.cleaned_data['message']
- sender = form.cleaned_data['sender']
- cc_myself = form.cleaned_data['cc_myself']
+ subject = form.cleaned_data["subject"]
+ message = form.cleaned_data["message"]
+ sender = form.cleaned_data["sender"]
+ cc_myself = form.cleaned_data["cc_myself"]
- recipients = ['info@example.com']
+ recipients = ["info@example.com"]
if cc_myself:
recipients.append(sender)
send_mail(subject, message, sender, recipients)
- return HttpResponseRedirect('/thanks/')
+ return HttpResponseRedirect("/thanks/")
.. tip::
@@ -532,9 +535,11 @@ Then you can configure the :setting:`FORM_RENDERER` setting:
from django.forms.renderers import TemplatesSetting
+
class CustomFormRenderer(TemplatesSetting):
form_template_name = "form_snippet.html"
+
FORM_RENDERER = "project.settings.CustomFormRenderer"
… or for a single form::
@@ -549,8 +554,8 @@ the :meth:`.Form.render`. Here's an example of this being used in a view::
def index(request):
form = MyForm()
rendered_form = form.render("form_snippet.html")
- context = {'form': rendered_form}
- return render(request, 'index.html', context)
+ context = {"form": rendered_form}
+ return render(request, "index.html", context)
See :ref:`ref-forms-api-outputting-html` for more details.
diff --git a/docs/topics/forms/media.txt b/docs/topics/forms/media.txt
index ab37a19182..5fdd37437e 100644
--- a/docs/topics/forms/media.txt
+++ b/docs/topics/forms/media.txt
@@ -53,12 +53,13 @@ Here's an example::
from django import forms
+
class CalendarWidget(forms.TextInput):
class Media:
css = {
- 'all': ['pretty.css'],
+ "all": ["pretty.css"],
}
- js = ['animations.js', 'actions.js']
+ js = ["animations.js", "actions.js"]
This code defines a ``CalendarWidget``, which will be based on ``TextInput``.
Every time the CalendarWidget is used on a form, that form will be directed
@@ -98,8 +99,8 @@ provide two CSS options -- one for the screen, and one for print::
class Media:
css = {
- 'screen': ['pretty.css'],
- 'print': ['newspaper.css'],
+ "screen": ["pretty.css"],
+ "print": ["newspaper.css"],
}
If a group of CSS files are appropriate for multiple output media types,
@@ -109,9 +110,9 @@ requirements::
class Media:
css = {
- 'screen': ['pretty.css'],
- 'tv,projector': ['lo_res.css'],
- 'print': ['newspaper.css'],
+ "screen": ["pretty.css"],
+ "tv,projector": ["lo_res.css"],
+ "print": ["newspaper.css"],
}
If this last CSS definition were to be rendered, it would become the following HTML:
@@ -145,9 +146,10 @@ example above:
>>> class FancyCalendarWidget(CalendarWidget):
... class Media:
... css = {
- ... 'all': ['fancy.css'],
+ ... "all": ["fancy.css"],
... }
- ... js = ['whizbang.js']
+ ... js = ["whizbang.js"]
+ ...
>>> w = FancyCalendarWidget()
>>> print(w.media)
@@ -167,9 +169,10 @@ an ``extend=False`` declaration to the ``Media`` declaration:
... class Media:
... extend = False
... css = {
- ... 'all': ['fancy.css'],
+ ... "all": ["fancy.css"],
... }
- ... js = ['whizbang.js']
+ ... js = ["whizbang.js"]
+ ...
>>> w = FancyCalendarWidget()
>>> print(w.media)
@@ -198,8 +201,9 @@ be defined in a dynamic fashion::
class CalendarWidget(forms.TextInput):
@property
def media(self):
- return forms.Media(css={'all': ['pretty.css']},
- js=['animations.js', 'actions.js'])
+ return forms.Media(
+ css={"all": ["pretty.css"]}, js=["animations.js", "actions.js"]
+ )
See the section on `Media objects`_ for more details on how to construct
return values for dynamic ``media`` properties.
@@ -235,9 +239,10 @@ was ``None``:
>>> class CalendarWidget(forms.TextInput):
... class Media:
... css = {
- ... 'all': ['/css/pretty.css'],
+ ... "all": ["/css/pretty.css"],
... }
- ... js = ['animations.js', 'http://othersite.com/actions.js']
+ ... js = ["animations.js", "http://othersite.com/actions.js"]
+ ...
>>> w = CalendarWidget()
>>> print(w.media)
@@ -283,10 +288,12 @@ outputting the complete HTML ``<script>`` or ``<link>`` tag content:
... class JSPath:
... def __str__(self):
... return '<script src="https://example.org/asset.js" rel="stylesheet">'
+ ...
>>> class SomeWidget(forms.TextInput):
... class Media:
... js = [JSPath()]
+ ...
``Media`` objects
=================
@@ -313,7 +320,7 @@ operator to filter out a medium of interest. For example:
<script src="http://static.example.com/animations.js"></script>
<script src="http://static.example.com/actions.js"></script>
- >>> print(w.media['css'])
+ >>> print(w.media["css"])
<link href="http://static.example.com/pretty.css" media="all" rel="stylesheet">
When you use the subscript operator, the value that is returned is a
@@ -332,13 +339,15 @@ specified by both:
>>> class CalendarWidget(forms.TextInput):
... class Media:
... css = {
- ... 'all': ['pretty.css'],
+ ... "all": ["pretty.css"],
... }
- ... js = ['animations.js', 'actions.js']
+ ... js = ["animations.js", "actions.js"]
+ ...
>>> class OtherWidget(forms.TextInput):
... class Media:
- ... js = ['whizbang.js']
+ ... js = ["whizbang.js"]
+ ...
>>> w1 = CalendarWidget()
>>> w2 = OtherWidget()
@@ -365,10 +374,12 @@ For example:
>>> from django import forms
>>> class CalendarWidget(forms.TextInput):
... class Media:
- ... js = ['jQuery.js', 'calendar.js', 'noConflict.js']
+ ... js = ["jQuery.js", "calendar.js", "noConflict.js"]
+ ...
>>> class TimeWidget(forms.TextInput):
... class Media:
- ... js = ['jQuery.js', 'time.js', 'noConflict.js']
+ ... js = ["jQuery.js", "time.js", "noConflict.js"]
+ ...
>>> w1 = CalendarWidget()
>>> w2 = TimeWidget()
>>> print(w1.media + w2.media)
@@ -400,6 +411,7 @@ are part of the form:
>>> class ContactForm(forms.Form):
... date = DateField(widget=CalendarWidget)
... name = CharField(max_length=40, widget=OtherWidget)
+ ...
>>> f = ContactForm()
>>> f.media
@@ -416,11 +428,11 @@ CSS for form layout -- add a ``Media`` declaration to the form:
>>> class ContactForm(forms.Form):
... date = DateField(widget=CalendarWidget)
... name = CharField(max_length=40, widget=OtherWidget)
- ...
... class Media:
... css = {
- ... 'all': ['layout.css'],
+ ... "all": ["layout.css"],
... }
+ ...
>>> f = ContactForm()
>>> f.media
diff --git a/docs/topics/forms/modelforms.txt b/docs/topics/forms/modelforms.txt
index 50fb12ef6e..7f3c042f30 100644
--- a/docs/topics/forms/modelforms.txt
+++ b/docs/topics/forms/modelforms.txt
@@ -28,7 +28,8 @@ For example:
>>> class ArticleForm(ModelForm):
... class Meta:
... model = Article
- ... fields = ['pub_date', 'headline', 'content', 'reporter']
+ ... fields = ["pub_date", "headline", "content", "reporter"]
+ ...
# Creating a form to add an article.
>>> form = ArticleForm()
@@ -173,11 +174,12 @@ Consider this set of models::
from django.forms import ModelForm
TITLE_CHOICES = [
- ('MR', 'Mr.'),
- ('MRS', 'Mrs.'),
- ('MS', 'Ms.'),
+ ("MR", "Mr."),
+ ("MRS", "Mrs."),
+ ("MS", "Ms."),
]
+
class Author(models.Model):
name = models.CharField(max_length=100)
title = models.CharField(max_length=3, choices=TITLE_CHOICES)
@@ -186,19 +188,22 @@ Consider this set of models::
def __str__(self):
return self.name
+
class Book(models.Model):
name = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
+
class AuthorForm(ModelForm):
class Meta:
model = Author
- fields = ['name', 'title', 'birth_date']
+ fields = ["name", "title", "birth_date"]
+
class BookForm(ModelForm):
class Meta:
model = Book
- fields = ['name', 'authors']
+ fields = ["name", "authors"]
With these models, the ``ModelForm`` subclasses above would be roughly
@@ -207,6 +212,7 @@ we'll discuss in a moment.)::
from django import forms
+
class AuthorForm(forms.Form):
name = forms.CharField(max_length=100)
title = forms.CharField(
@@ -215,6 +221,7 @@ we'll discuss in a moment.)::
)
birth_date = forms.DateField(required=False)
+
class BookForm(forms.Form):
name = forms.CharField(max_length=100)
authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all())
@@ -305,11 +312,12 @@ to the ``error_messages`` dictionary of the ``ModelForm``’s inner ``Meta`` cla
from django.core.exceptions import NON_FIELD_ERRORS
from django.forms import ModelForm
+
class ArticleForm(ModelForm):
class Meta:
error_messages = {
NON_FIELD_ERRORS: {
- 'unique_together': "%(model_name)s's %(field_labels)s are not unique.",
+ "unique_together": "%(model_name)s's %(field_labels)s are not unique.",
}
}
@@ -388,7 +396,7 @@ you've manually saved the instance produced by the form, you can invoke
>>> new_author = f.save(commit=False)
# Modify the author in some way.
- >>> new_author.some_field = 'some_value'
+ >>> new_author.some_field = "some_value"
# Save the new instance.
>>> new_author.save()
@@ -440,10 +448,11 @@ these security concerns do not apply to you:
from django.forms import ModelForm
+
class AuthorForm(ModelForm):
class Meta:
model = Author
- fields = '__all__'
+ fields = "__all__"
2. Set the ``exclude`` attribute of the ``ModelForm``’s inner ``Meta`` class to
a list of fields to be excluded from the form.
@@ -453,7 +462,7 @@ these security concerns do not apply to you:
class PartialAuthorForm(ModelForm):
class Meta:
model = Author
- exclude = ['title']
+ exclude = ["title"]
Since the ``Author`` model has the 3 fields ``name``, ``title`` and
``birth_date``, this will result in the fields ``name`` and ``birth_date``
@@ -481,7 +490,7 @@ include that field.
avoid this failure, you must instantiate your model with initial
values for the missing, but required fields::
- author = Author(title='Mr')
+ author = Author(title="Mr")
form = PartialAuthorForm(request.POST, instance=author)
form.save()
@@ -490,7 +499,7 @@ include that field.
form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
- author.title = 'Mr'
+ author.title = "Mr"
author.save()
See the `section on saving forms`_ for more details on using
@@ -519,12 +528,13 @@ For example, if you want the ``CharField`` for the ``name`` attribute of
from django.forms import ModelForm, Textarea
from myapp.models import Author
+
class AuthorForm(ModelForm):
class Meta:
model = Author
- fields = ['name', 'title', 'birth_date']
+ fields = ["name", "title", "birth_date"]
widgets = {
- 'name': Textarea(attrs={'cols': 80, 'rows': 20}),
+ "name": Textarea(attrs={"cols": 80, "rows": 20}),
}
The ``widgets`` dictionary accepts either widget instances (e.g.,
@@ -540,19 +550,20 @@ the ``name`` field::
from django.utils.translation import gettext_lazy as _
+
class AuthorForm(ModelForm):
class Meta:
model = Author
- fields = ['name', 'title', 'birth_date']
+ fields = ["name", "title", "birth_date"]
labels = {
- 'name': _('Writer'),
+ "name": _("Writer"),
}
help_texts = {
- 'name': _('Some useful help text.'),
+ "name": _("Some useful help text."),
}
error_messages = {
- 'name': {
- 'max_length': _("This writer's name is too long."),
+ "name": {
+ "max_length": _("This writer's name is too long."),
},
}
@@ -565,12 +576,13 @@ field, you could do the following::
from django.forms import ModelForm
from myapp.models import Article
+
class ArticleForm(ModelForm):
class Meta:
model = Article
- fields = ['pub_date', 'headline', 'content', 'reporter', 'slug']
+ fields = ["pub_date", "headline", "content", "reporter", "slug"]
field_classes = {
- 'slug': MySlugFormField,
+ "slug": MySlugFormField,
}
or::
@@ -578,11 +590,13 @@ or::
from django.forms import ModelForm
from myapp.models import Article
+
def formfield_for_dbfield(db_field, **kwargs):
if db_field.name == "slug":
return MySlugFormField()
return db_field.formfield(**kwargs)
+
class ArticleForm(ModelForm):
class Meta:
model = Article
@@ -599,12 +613,13 @@ the field declaratively and setting its ``validators`` parameter::
from django.forms import CharField, ModelForm
from myapp.models import Article
+
class ArticleForm(ModelForm):
slug = CharField(validators=[validate_slug])
class Meta:
model = Article
- fields = ['pub_date', 'headline', 'content', 'reporter', 'slug']
+ fields = ["pub_date", "headline", "content", "reporter", "slug"]
.. note::
@@ -635,7 +650,7 @@ the field declaratively and setting its ``validators`` parameter::
max_length=200,
null=True,
blank=True,
- help_text='Use puns liberally',
+ help_text="Use puns liberally",
)
content = models.TextField()
@@ -647,12 +662,12 @@ the field declaratively and setting its ``validators`` parameter::
headline = MyFormField(
max_length=200,
required=False,
- help_text='Use puns liberally',
+ help_text="Use puns liberally",
)
class Meta:
model = Article
- fields = ['headline', 'content']
+ fields = ["headline", "content"]
You must ensure that the type of the form field can be used to set the
contents of the corresponding model field. When they are not compatible,
@@ -695,6 +710,7 @@ using the previous ``ArticleForm`` class:
>>> class EnhancedArticleForm(ArticleForm):
... def clean_pub_date(self):
... ...
+ ...
This creates a form that behaves identically to ``ArticleForm``, except there's
some extra validation and cleaning for the ``pub_date`` field.
@@ -706,7 +722,8 @@ the ``Meta.fields`` or ``Meta.exclude`` lists:
>>> class RestrictedArticleForm(EnhancedArticleForm):
... class Meta(ArticleForm.Meta):
- ... exclude = ['body']
+ ... exclude = ["body"]
+ ...
This adds the extra method from the ``EnhancedArticleForm`` and modifies
the original ``ArticleForm.Meta`` to remove one field.
@@ -744,8 +761,8 @@ and values from an attached model instance. For example:
>>> article = Article.objects.get(pk=1)
>>> article.headline
'My headline'
- >>> form = ArticleForm(initial={'headline': 'Initial headline'}, instance=article)
- >>> form['headline'].value()
+ >>> form = ArticleForm(initial={"headline": "Initial headline"}, instance=article)
+ >>> form["headline"].value()
'Initial headline'
.. _modelforms-factory:
@@ -770,8 +787,7 @@ specifying the widgets to be used for a given field:
.. code-block:: pycon
>>> from django.forms import Textarea
- >>> Form = modelform_factory(Book, form=BookForm,
- ... widgets={"title": Textarea()})
+ >>> Form = modelform_factory(Book, form=BookForm, widgets={"title": Textarea()})
The fields to include can be specified using the ``fields`` and ``exclude``
keyword arguments, or the corresponding attributes on the ``ModelForm`` inner
@@ -799,7 +815,7 @@ convenient. Let's reuse the ``Author`` model from above:
>>> from django.forms import modelformset_factory
>>> from myapp.models import Author
- >>> AuthorFormSet = modelformset_factory(Author, fields=['name', 'title'])
+ >>> AuthorFormSet = modelformset_factory(Author, fields=["name", "title"])
Using ``fields`` restricts the formset to use only the given fields.
Alternatively, you can take an "opt-out" approach, specifying which fields to
@@ -807,7 +823,7 @@ exclude:
.. code-block:: pycon
- >>> AuthorFormSet = modelformset_factory(Author, exclude=['birth_date'])
+ >>> AuthorFormSet = modelformset_factory(Author, exclude=["birth_date"])
This will create a formset that is capable of working with the data associated
with the ``Author`` model. It works just like a regular formset:
@@ -848,7 +864,7 @@ queryset that includes all objects in the model (e.g.,
.. code-block:: pycon
- >>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O'))
+ >>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith="O"))
Alternatively, you can create a subclass that sets ``self.queryset`` in
``__init__``::
@@ -856,17 +872,19 @@ Alternatively, you can create a subclass that sets ``self.queryset`` in
from django.forms import BaseModelFormSet
from myapp.models import Author
+
class BaseAuthorFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
- self.queryset = Author.objects.filter(name__startswith='O')
+ self.queryset = Author.objects.filter(name__startswith="O")
Then, pass your ``BaseAuthorFormSet`` class to the factory function:
.. code-block:: pycon
>>> AuthorFormSet = modelformset_factory(
- ... Author, fields=['name', 'title'], formset=BaseAuthorFormSet)
+ ... Author, fields=["name", "title"], formset=BaseAuthorFormSet
+ ... )
If you want to return a formset that doesn't include *any* preexisting
instances of the model, you can specify an empty QuerySet:
@@ -886,7 +904,7 @@ you can create a custom model form that has custom validation::
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
- fields = ['name', 'title']
+ fields = ["name", "title"]
def clean_name(self):
# custom validation for the name field
@@ -911,8 +929,10 @@ class of a ``ModelForm`` works:
.. code-block:: pycon
>>> AuthorFormSet = modelformset_factory(
- ... Author, fields=['name', 'title'],
- ... widgets={'name': Textarea(attrs={'cols': 80, 'rows': 20})})
+ ... Author,
+ ... fields=["name", "title"],
+ ... widgets={"name": Textarea(attrs={"cols": 80, "rows": 20})},
+ ... )
Enabling localization for fields with ``localized_fields``
----------------------------------------------------------
@@ -975,6 +995,7 @@ Pass ``commit=False`` to return the unsaved model instances:
>>> for instance in instances:
... # do something with instance
... instance.save()
+ ...
This gives you the ability to attach data to the instances before saving them
to the database. If your formset contains a ``ManyToManyField``, you'll also
@@ -1001,11 +1022,11 @@ extra forms displayed.
.. code-block:: pycon
- >>> Author.objects.order_by('name')
+ >>> Author.objects.order_by("name")
<QuerySet [<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>]>
- >>> AuthorFormSet = modelformset_factory(Author, fields=['name'], max_num=1)
- >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
+ >>> AuthorFormSet = modelformset_factory(Author, fields=["name"], max_num=1)
+ >>> formset = AuthorFormSet(queryset=Author.objects.order_by("name"))
>>> [x.name for x in formset.get_queryset()]
['Charles Baudelaire', 'Paul Verlaine', 'Walt Whitman']
@@ -1020,10 +1041,11 @@ so long as the total number of forms does not exceed ``max_num``:
.. code-block:: pycon
- >>> AuthorFormSet = modelformset_factory(Author, fields=['name'], max_num=4, extra=2)
- >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name'))
+ >>> AuthorFormSet = modelformset_factory(Author, fields=["name"], max_num=4, extra=2)
+ >>> formset = AuthorFormSet(queryset=Author.objects.order_by("name"))
>>> for form in formset:
... print(form)
+ ...
<div><label for="id_form-0-name">Name:</label><input id="id_form-0-name" type="text" name="form-0-name" value="Charles Baudelaire" maxlength="100"><input type="hidden" name="form-0-id" value="1" id="id_form-0-id"></div>
<div><label for="id_form-1-name">Name:</label><input id="id_form-1-name" type="text" name="form-1-name" value="Paul Verlaine" maxlength="100"><input type="hidden" name="form-1-id" value="3" id="id_form-1-id"></div>
<div><label for="id_form-2-name">Name:</label><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100"><input type="hidden" name="form-2-id" value="2" id="id_form-2-id"></div>
@@ -1044,7 +1066,7 @@ objects:
>>> AuthorFormSet = modelformset_factory(
... Author,
- ... fields=['name', 'title'],
+ ... fields=["name", "title"],
... edit_only=True,
... )
@@ -1061,16 +1083,17 @@ formset to edit ``Author`` model instances::
from django.shortcuts import render
from myapp.models import Author
+
def manage_authors(request):
- AuthorFormSet = modelformset_factory(Author, fields=['name', 'title'])
- if request.method == 'POST':
+ AuthorFormSet = modelformset_factory(Author, fields=["name", "title"])
+ if request.method == "POST":
formset = AuthorFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
# do something.
else:
formset = AuthorFormSet()
- return render(request, 'manage_authors.html', {'formset': formset})
+ return render(request, "manage_authors.html", {"formset": formset})
As you can see, the view logic of a model formset isn't drastically different
than that of a "normal" formset. The only difference is that we call
@@ -1091,6 +1114,7 @@ class's ``clean`` method::
from django.forms import BaseModelFormSet
+
class MyModelFormSet(BaseModelFormSet):
def clean(self):
super().clean()
@@ -1107,13 +1131,14 @@ to modify a value in ``ModelFormSet.clean()`` you must modify
from django.forms import BaseModelFormSet
+
class MyModelFormSet(BaseModelFormSet):
def clean(self):
super().clean()
for form in self.forms:
- name = form.cleaned_data['name'].upper()
- form.cleaned_data['name'] = name
+ name = form.cleaned_data["name"].upper()
+ form.cleaned_data["name"] = name
# update the instance value.
form.instance.name = name
@@ -1127,12 +1152,14 @@ formset::
from django.shortcuts import render
from myapp.models import Author
+
def manage_authors(request):
- AuthorFormSet = modelformset_factory(Author, fields=['name', 'title'])
- queryset = Author.objects.filter(name__startswith='O')
+ AuthorFormSet = modelformset_factory(Author, fields=["name", "title"])
+ queryset = Author.objects.filter(name__startswith="O")
if request.method == "POST":
formset = AuthorFormSet(
- request.POST, request.FILES,
+ request.POST,
+ request.FILES,
queryset=queryset,
)
if formset.is_valid():
@@ -1140,7 +1167,7 @@ formset::
# Do something.
else:
formset = AuthorFormSet(queryset=queryset)
- return render(request, 'manage_authors.html', {'formset': formset})
+ return render(request, "manage_authors.html", {"formset": formset})
Note that we pass the ``queryset`` argument in both the ``POST`` and ``GET``
cases in this example.
@@ -1222,9 +1249,11 @@ you have these two models::
from django.db import models
+
class Author(models.Model):
name = models.CharField(max_length=100)
+
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=100)
@@ -1235,8 +1264,8 @@ a particular author, you could do this:
.. code-block:: pycon
>>> from django.forms import inlineformset_factory
- >>> BookFormSet = inlineformset_factory(Author, Book, fields=['title'])
- >>> author = Author.objects.get(name='Mike Royko')
+ >>> BookFormSet = inlineformset_factory(Author, Book, fields=["title"])
+ >>> author = Author.objects.get(name="Mike Royko")
>>> formset = BookFormSet(instance=author)
``BookFormSet``'s :ref:`prefix <formset-prefix>` is ``'book_set'``
@@ -1264,6 +1293,7 @@ For example, if you want to override ``clean()``::
from django.forms import BaseInlineFormSet
+
class CustomInlineFormSet(BaseInlineFormSet):
def clean(self):
super().clean()
@@ -1280,9 +1310,10 @@ Then when you create your inline formset, pass in the optional argument
.. code-block:: pycon
>>> from django.forms import inlineformset_factory
- >>> BookFormSet = inlineformset_factory(Author, Book, fields=['title'],
- ... formset=CustomInlineFormSet)
- >>> author = Author.objects.get(name='Mike Royko')
+ >>> BookFormSet = inlineformset_factory(
+ ... Author, Book, fields=["title"], formset=CustomInlineFormSet
+ ... )
+ >>> author = Author.objects.get(name="Mike Royko")
>>> formset = BookFormSet(instance=author)
More than one foreign key to the same model
@@ -1296,12 +1327,12 @@ the following model::
from_friend = models.ForeignKey(
Friend,
on_delete=models.CASCADE,
- related_name='from_friends',
+ related_name="from_friends",
)
to_friend = models.ForeignKey(
Friend,
on_delete=models.CASCADE,
- related_name='friends',
+ related_name="friends",
)
length_in_months = models.IntegerField()
@@ -1310,8 +1341,9 @@ To resolve this, you can use ``fk_name`` to
.. code-block:: pycon
- >>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name='from_friend',
- ... fields=['to_friend', 'length_in_months'])
+ >>> FriendshipFormSet = inlineformset_factory(
+ ... Friend, Friendship, fk_name="from_friend", fields=["to_friend", "length_in_months"]
+ ... )
Using an inline formset in a view
---------------------------------
@@ -1321,7 +1353,7 @@ of a model. Here's how you can do that::
def manage_books(request, author_id):
author = Author.objects.get(pk=author_id)
- BookInlineFormSet = inlineformset_factory(Author, Book, fields=['title'])
+ BookInlineFormSet = inlineformset_factory(Author, Book, fields=["title"])
if request.method == "POST":
formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
if formset.is_valid():
@@ -1330,7 +1362,7 @@ of a model. Here's how you can do that::
return HttpResponseRedirect(author.get_absolute_url())
else:
formset = BookInlineFormSet(instance=author)
- return render(request, 'manage_books.html', {'formset': formset})
+ return render(request, "manage_books.html", {"formset": formset})
Notice how we pass ``instance`` in both the ``POST`` and ``GET`` cases.