diff options
Diffstat (limited to 'docs/ref/forms')
| -rw-r--r-- | docs/ref/forms/api.txt | 219 | ||||
| -rw-r--r-- | docs/ref/forms/fields.txt | 102 | ||||
| -rw-r--r-- | docs/ref/forms/renderers.txt | 3 | ||||
| -rw-r--r-- | docs/ref/forms/validation.txt | 66 | ||||
| -rw-r--r-- | docs/ref/forms/widgets.txt | 71 |
5 files changed, 270 insertions, 191 deletions
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 -></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 |
