summaryrefslogtreecommitdiff
path: root/docs/topics/forms/modelforms.txt
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/modelforms.txt
parent6015bab80e28aef2669f6fac53423aa65f70cb08 (diff)
Fixed #34140 -- Reformatted code blocks in docs with blacken-docs.
Diffstat (limited to 'docs/topics/forms/modelforms.txt')
-rw-r--r--docs/topics/forms/modelforms.txt160
1 files changed, 96 insertions, 64 deletions
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.