Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/django/forms/fields.py: 41%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

774 statements  

1""" 

2Field classes. 

3""" 

4 

5import copy 

6import datetime 

7import json 

8import math 

9import operator 

10import os 

11import re 

12import uuid 

13from decimal import Decimal, DecimalException 

14from io import BytesIO 

15from urllib.parse import urlsplit, urlunsplit 

16 

17from django.core import validators 

18from django.core.exceptions import ValidationError 

19from django.forms.boundfield import BoundField 

20from django.forms.utils import from_current_timezone, to_current_timezone 

21from django.forms.widgets import ( 

22 FILE_INPUT_CONTRADICTION, 

23 CheckboxInput, 

24 ClearableFileInput, 

25 DateInput, 

26 DateTimeInput, 

27 EmailInput, 

28 FileInput, 

29 HiddenInput, 

30 MultipleHiddenInput, 

31 NullBooleanSelect, 

32 NumberInput, 

33 Select, 

34 SelectMultiple, 

35 SplitDateTimeWidget, 

36 SplitHiddenDateTimeWidget, 

37 Textarea, 

38 TextInput, 

39 TimeInput, 

40 URLInput, 

41) 

42from django.utils import formats 

43from django.utils.choices import normalize_choices 

44from django.utils.dateparse import parse_datetime, parse_duration 

45from django.utils.duration import duration_string 

46from django.utils.ipv6 import MAX_IPV6_ADDRESS_LENGTH, clean_ipv6_address 

47from django.utils.regex_helper import _lazy_re_compile 

48from django.utils.translation import gettext_lazy as _ 

49from django.utils.translation import ngettext_lazy 

50 

51__all__ = ( 

52 "Field", 

53 "CharField", 

54 "IntegerField", 

55 "DateField", 

56 "TimeField", 

57 "DateTimeField", 

58 "DurationField", 

59 "RegexField", 

60 "EmailField", 

61 "FileField", 

62 "ImageField", 

63 "URLField", 

64 "BooleanField", 

65 "NullBooleanField", 

66 "ChoiceField", 

67 "MultipleChoiceField", 

68 "ComboField", 

69 "MultiValueField", 

70 "FloatField", 

71 "DecimalField", 

72 "SplitDateTimeField", 

73 "GenericIPAddressField", 

74 "FilePathField", 

75 "JSONField", 

76 "SlugField", 

77 "TypedChoiceField", 

78 "TypedMultipleChoiceField", 

79 "UUIDField", 

80) 

81 

82 

83class Field: 

84 widget = TextInput # Default widget to use when rendering this type of Field. 

85 hidden_widget = ( 

86 HiddenInput # Default widget to use when rendering this as "hidden". 

87 ) 

88 default_validators = [] # Default set of validators 

89 # Add an 'invalid' entry to default_error_message if you want a specific 

90 # field error message not raised by the field validators. 

91 default_error_messages = { 

92 "required": _("This field is required."), 

93 } 

94 empty_values = list(validators.EMPTY_VALUES) 

95 bound_field_class = None 

96 

97 def __init__( 

98 self, 

99 *, 

100 required=True, 

101 widget=None, 

102 label=None, 

103 initial=None, 

104 help_text="", 

105 error_messages=None, 

106 show_hidden_initial=False, 

107 validators=(), 

108 localize=False, 

109 disabled=False, 

110 label_suffix=None, 

111 template_name=None, 

112 bound_field_class=None, 

113 ): 

114 # required -- Boolean that specifies whether the field is required. 

115 # True by default. 

116 # widget -- A Widget class, or instance of a Widget class, that should 

117 # be used for this Field when displaying it. Each Field has a 

118 # default Widget that it'll use if you don't specify this. In 

119 # most cases, the default widget is TextInput. 

120 # label -- A verbose name for this field, for use in displaying this 

121 # field in a form. By default, Django will use a "pretty" 

122 # version of the form field name, if the Field is part of a 

123 # Form. 

124 # initial -- A value to use in this Field's initial display. This value 

125 # is *not* used as a fallback if data isn't given. 

126 # help_text -- An optional string to use as "help text" for this Field. 

127 # error_messages -- An optional dictionary to override the default 

128 # messages that the field will raise. 

129 # show_hidden_initial -- Boolean that specifies if it is needed to render a 

130 # hidden widget with initial value after widget. 

131 # validators -- List of additional validators to use 

132 # localize -- Boolean that specifies if the field should be localized. 

133 # disabled -- Boolean that specifies whether the field is disabled, that 

134 # is its widget is shown in the form but not editable. 

135 # label_suffix -- Suffix to be added to the label. Overrides 

136 # form's label_suffix. 

137 # bound_field_class -- BoundField class to use in Field.get_bound_field. 

138 self.required, self.label, self.initial = required, label, initial 

139 self.show_hidden_initial = show_hidden_initial 

140 self.help_text = help_text 

141 self.disabled = disabled 

142 self.label_suffix = label_suffix 

143 self.bound_field_class = bound_field_class or self.bound_field_class 

144 widget = widget or self.widget 

145 if isinstance(widget, type): 

146 widget = widget() 

147 else: 

148 widget = copy.deepcopy(widget) 

149 

150 # Trigger the localization machinery if needed. 

151 self.localize = localize 

152 if self.localize: 

153 widget.is_localized = True 

154 

155 # Let the widget know whether it should display as required. 

156 widget.is_required = self.required 

157 

158 # Hook into self.widget_attrs() for any Field-specific HTML attributes. 

159 extra_attrs = self.widget_attrs(widget) 

160 if extra_attrs: 

161 widget.attrs.update(extra_attrs) 

162 

163 self.widget = widget 

164 

165 messages = {} 

166 for c in reversed(self.__class__.__mro__): 

167 messages.update(getattr(c, "default_error_messages", {})) 

168 messages.update(error_messages or {}) 

169 self.error_messages = messages 

170 

171 self.validators = [*self.default_validators, *validators] 

172 self.template_name = template_name 

173 

174 super().__init__() 

175 

176 def prepare_value(self, value): 

177 return value 

178 

179 def to_python(self, value): 

180 return value 

181 

182 def validate(self, value): 

183 if value in self.empty_values and self.required: 

184 raise ValidationError(self.error_messages["required"], code="required") 

185 

186 def run_validators(self, value): 

187 if value in self.empty_values: 

188 return 

189 errors = [] 

190 for v in self.validators: 

191 try: 

192 v(value) 

193 except ValidationError as e: 

194 if hasattr(e, "code") and e.code in self.error_messages: 

195 e.message = self.error_messages[e.code] 

196 errors.extend(e.error_list) 

197 if errors: 

198 raise ValidationError(errors) 

199 

200 def clean(self, value): 

201 """ 

202 Validate the given value and return its "cleaned" value as an 

203 appropriate Python object. Raise ValidationError for any errors. 

204 """ 

205 value = self.to_python(value) 

206 self.validate(value) 

207 self.run_validators(value) 

208 return value 

209 

210 def bound_data(self, data, initial): 

211 """ 

212 Return the value that should be shown for this field on render of a 

213 bound form, given the submitted POST data for the field and the initial 

214 data, if any. 

215 

216 For most fields, this will simply be data; FileFields need to handle it 

217 a bit differently. 

218 """ 

219 if self.disabled: 

220 return initial 

221 return data 

222 

223 def widget_attrs(self, widget): 

224 """ 

225 Given a Widget instance (*not* a Widget class), return a dictionary of 

226 any HTML attributes that should be added to the Widget, based on this 

227 Field. 

228 """ 

229 return {} 

230 

231 def has_changed(self, initial, data): 

232 """Return True if data differs from initial.""" 

233 # Always return False if the field is disabled since self.bound_data 

234 # always uses the initial value in this case. 

235 if self.disabled: 

236 return False 

237 try: 

238 data = self.to_python(data) 

239 if hasattr(self, "_coerce"): 

240 return self._coerce(data) != self._coerce(initial) 

241 except ValidationError: 

242 return True 

243 # For purposes of seeing whether something has changed, None is 

244 # the same as an empty string, if the data or initial value we get 

245 # is None, replace it with ''. 

246 initial_value = initial if initial is not None else "" 

247 data_value = data if data is not None else "" 

248 return initial_value != data_value 

249 

250 def get_bound_field(self, form, field_name): 

251 """ 

252 Return a BoundField instance that will be used when accessing the form 

253 field in a template. 

254 """ 

255 bound_field_class = ( 

256 self.bound_field_class or form.bound_field_class or BoundField 

257 ) 

258 return bound_field_class(form, self, field_name) 

259 

260 def __deepcopy__(self, memo): 

261 result = copy.copy(self) 

262 memo[id(self)] = result 

263 result.widget = copy.deepcopy(self.widget, memo) 

264 result.error_messages = self.error_messages.copy() 

265 result.validators = self.validators[:] 

266 return result 

267 

268 def _clean_bound_field(self, bf): 

269 value = bf.initial if self.disabled else bf.data 

270 return self.clean(value) 

271 

272 

273class CharField(Field): 

274 def __init__( 

275 self, *, max_length=None, min_length=None, strip=True, empty_value="", **kwargs 

276 ): 

277 self.max_length = max_length 

278 self.min_length = min_length 

279 self.strip = strip 

280 self.empty_value = empty_value 

281 super().__init__(**kwargs) 

282 if min_length is not None: 

283 self.validators.append(validators.MinLengthValidator(int(min_length))) 

284 if max_length is not None: 

285 self.validators.append(validators.MaxLengthValidator(int(max_length))) 

286 self.validators.append(validators.ProhibitNullCharactersValidator()) 

287 

288 def to_python(self, value): 

289 """Return a string.""" 

290 if value not in self.empty_values: 

291 value = str(value) 

292 if self.strip: 

293 value = value.strip() 

294 if value in self.empty_values: 

295 return self.empty_value 

296 return value 

297 

298 def widget_attrs(self, widget): 

299 attrs = super().widget_attrs(widget) 

300 if self.max_length is not None and not widget.is_hidden: 

301 # The HTML attribute is maxlength, not max_length. 

302 attrs["maxlength"] = str(self.max_length) 

303 if self.min_length is not None and not widget.is_hidden: 

304 # The HTML attribute is minlength, not min_length. 

305 attrs["minlength"] = str(self.min_length) 

306 return attrs 

307 

308 

309class IntegerField(Field): 

310 widget = NumberInput 

311 default_error_messages = { 

312 "invalid": _("Enter a whole number."), 

313 } 

314 re_decimal = _lazy_re_compile(r"\.0*\s*$") 

315 

316 def __init__(self, *, max_value=None, min_value=None, step_size=None, **kwargs): 

317 self.max_value, self.min_value, self.step_size = max_value, min_value, step_size 

318 if kwargs.get("localize") and self.widget == NumberInput: 

319 # Localized number input is not well supported on most browsers 

320 kwargs.setdefault("widget", super().widget) 

321 super().__init__(**kwargs) 

322 

323 if max_value is not None: 

324 self.validators.append(validators.MaxValueValidator(max_value)) 

325 if min_value is not None: 

326 self.validators.append(validators.MinValueValidator(min_value)) 

327 if step_size is not None: 

328 self.validators.append( 

329 validators.StepValueValidator(step_size, offset=min_value) 

330 ) 

331 

332 def to_python(self, value): 

333 """ 

334 Validate that int() can be called on the input. Return the result 

335 of int() or None for empty values. 

336 """ 

337 value = super().to_python(value) 

338 if value in self.empty_values: 

339 return None 

340 if self.localize: 

341 value = formats.sanitize_separators(value) 

342 # Strip trailing decimal and zeros. 

343 try: 

344 value = int(self.re_decimal.sub("", str(value))) 

345 except (ValueError, TypeError): 

346 raise ValidationError(self.error_messages["invalid"], code="invalid") 

347 return value 

348 

349 def widget_attrs(self, widget): 

350 attrs = super().widget_attrs(widget) 

351 if isinstance(widget, NumberInput): 

352 if self.min_value is not None: 

353 attrs["min"] = self.min_value 

354 if self.max_value is not None: 

355 attrs["max"] = self.max_value 

356 if self.step_size is not None: 

357 attrs["step"] = self.step_size 

358 return attrs 

359 

360 

361class FloatField(IntegerField): 

362 default_error_messages = { 

363 "invalid": _("Enter a number."), 

364 } 

365 

366 def to_python(self, value): 

367 """ 

368 Validate that float() can be called on the input. Return the result 

369 of float() or None for empty values. 

370 """ 

371 value = super(IntegerField, self).to_python(value) 

372 if value in self.empty_values: 

373 return None 

374 if self.localize: 

375 value = formats.sanitize_separators(value) 

376 try: 

377 value = float(value) 

378 except (ValueError, TypeError): 

379 raise ValidationError(self.error_messages["invalid"], code="invalid") 

380 return value 

381 

382 def validate(self, value): 

383 super().validate(value) 

384 if value in self.empty_values: 

385 return 

386 if not math.isfinite(value): 

387 raise ValidationError(self.error_messages["invalid"], code="invalid") 

388 

389 def widget_attrs(self, widget): 

390 attrs = super().widget_attrs(widget) 

391 if isinstance(widget, NumberInput) and "step" not in widget.attrs: 

392 if self.step_size is not None: 

393 step = str(self.step_size) 

394 else: 

395 step = "any" 

396 attrs.setdefault("step", step) 

397 return attrs 

398 

399 

400class DecimalField(IntegerField): 

401 default_error_messages = { 

402 "invalid": _("Enter a number."), 

403 } 

404 

405 def __init__( 

406 self, 

407 *, 

408 max_value=None, 

409 min_value=None, 

410 max_digits=None, 

411 decimal_places=None, 

412 **kwargs, 

413 ): 

414 self.max_digits, self.decimal_places = max_digits, decimal_places 

415 super().__init__(max_value=max_value, min_value=min_value, **kwargs) 

416 self.validators.append(validators.DecimalValidator(max_digits, decimal_places)) 

417 

418 def to_python(self, value): 

419 """ 

420 Validate that the input is a decimal number. Return a Decimal 

421 instance or None for empty values. Ensure that there are no more 

422 than max_digits in the number and no more than decimal_places digits 

423 after the decimal point. 

424 """ 

425 if value in self.empty_values: 

426 return None 

427 if self.localize: 

428 value = formats.sanitize_separators(value) 

429 try: 

430 value = Decimal(str(value)) 

431 except DecimalException: 

432 raise ValidationError(self.error_messages["invalid"], code="invalid") 

433 return value 

434 

435 def validate(self, value): 

436 super().validate(value) 

437 if value in self.empty_values: 

438 return 

439 if not value.is_finite(): 

440 raise ValidationError( 

441 self.error_messages["invalid"], 

442 code="invalid", 

443 params={"value": value}, 

444 ) 

445 

446 def widget_attrs(self, widget): 

447 attrs = super().widget_attrs(widget) 

448 if isinstance(widget, NumberInput) and "step" not in widget.attrs: 

449 if self.decimal_places is not None: 

450 # Use exponential notation for small values since they might 

451 # be parsed as 0 otherwise. ref #20765 

452 step = str(Decimal(1).scaleb(-self.decimal_places)).lower() 

453 else: 

454 step = "any" 

455 attrs.setdefault("step", step) 

456 return attrs 

457 

458 

459class BaseTemporalField(Field): 

460 def __init__(self, *, input_formats=None, **kwargs): 

461 super().__init__(**kwargs) 

462 if input_formats is not None: 

463 self.input_formats = input_formats 

464 

465 def to_python(self, value): 

466 value = value.strip() 

467 # Try to strptime against each input format. 

468 for format in self.input_formats: 

469 try: 

470 return self.strptime(value, format) 

471 except (ValueError, TypeError): 

472 continue 

473 raise ValidationError(self.error_messages["invalid"], code="invalid") 

474 

475 def strptime(self, value, format): 

476 raise NotImplementedError("Subclasses must define this method.") 

477 

478 

479class DateField(BaseTemporalField): 

480 widget = DateInput 

481 input_formats = formats.get_format_lazy("DATE_INPUT_FORMATS") 

482 default_error_messages = { 

483 "invalid": _("Enter a valid date."), 

484 } 

485 

486 def to_python(self, value): 

487 """ 

488 Validate that the input can be converted to a date. Return a Python 

489 datetime.date object. 

490 """ 

491 if value in self.empty_values: 

492 return None 

493 if isinstance(value, datetime.datetime): 

494 return value.date() 

495 if isinstance(value, datetime.date): 

496 return value 

497 return super().to_python(value) 

498 

499 def strptime(self, value, format): 

500 return datetime.datetime.strptime(value, format).date() 

501 

502 

503class TimeField(BaseTemporalField): 

504 widget = TimeInput 

505 input_formats = formats.get_format_lazy("TIME_INPUT_FORMATS") 

506 default_error_messages = {"invalid": _("Enter a valid time.")} 

507 

508 def to_python(self, value): 

509 """ 

510 Validate that the input can be converted to a time. Return a Python 

511 datetime.time object. 

512 """ 

513 if value in self.empty_values: 

514 return None 

515 if isinstance(value, datetime.time): 

516 return value 

517 return super().to_python(value) 

518 

519 def strptime(self, value, format): 

520 return datetime.datetime.strptime(value, format).time() 

521 

522 

523class DateTimeFormatsIterator: 

524 def __iter__(self): 

525 yield from formats.get_format("DATETIME_INPUT_FORMATS") 

526 yield from formats.get_format("DATE_INPUT_FORMATS") 

527 

528 

529class DateTimeField(BaseTemporalField): 

530 widget = DateTimeInput 

531 input_formats = DateTimeFormatsIterator() 

532 default_error_messages = { 

533 "invalid": _("Enter a valid date/time."), 

534 } 

535 

536 def prepare_value(self, value): 

537 if isinstance(value, datetime.datetime): 

538 value = to_current_timezone(value) 

539 return value 

540 

541 def to_python(self, value): 

542 """ 

543 Validate that the input can be converted to a datetime. Return a 

544 Python datetime.datetime object. 

545 """ 

546 if value in self.empty_values: 

547 return None 

548 if isinstance(value, datetime.datetime): 

549 return from_current_timezone(value) 

550 if isinstance(value, datetime.date): 

551 result = datetime.datetime(value.year, value.month, value.day) 

552 return from_current_timezone(result) 

553 try: 

554 result = parse_datetime(value.strip()) 

555 except ValueError: 

556 raise ValidationError(self.error_messages["invalid"], code="invalid") 

557 if not result: 

558 result = super().to_python(value) 

559 return from_current_timezone(result) 

560 

561 def strptime(self, value, format): 

562 return datetime.datetime.strptime(value, format) 

563 

564 

565class DurationField(Field): 

566 default_error_messages = { 

567 "invalid": _("Enter a valid duration."), 

568 "overflow": _("The number of days must be between {min_days} and {max_days}."), 

569 } 

570 

571 def prepare_value(self, value): 

572 if isinstance(value, datetime.timedelta): 

573 return duration_string(value) 

574 return value 

575 

576 def to_python(self, value): 

577 if value in self.empty_values: 

578 return None 

579 if isinstance(value, datetime.timedelta): 

580 return value 

581 try: 

582 value = parse_duration(str(value)) 

583 except OverflowError: 

584 raise ValidationError( 

585 self.error_messages["overflow"].format( 

586 min_days=datetime.timedelta.min.days, 

587 max_days=datetime.timedelta.max.days, 

588 ), 

589 code="overflow", 

590 ) 

591 if value is None: 

592 raise ValidationError(self.error_messages["invalid"], code="invalid") 

593 return value 

594 

595 

596class RegexField(CharField): 

597 def __init__(self, regex, **kwargs): 

598 """ 

599 regex can be either a string or a compiled regular expression object. 

600 """ 

601 kwargs.setdefault("strip", False) 

602 super().__init__(**kwargs) 

603 self._set_regex(regex) 

604 

605 def _get_regex(self): 

606 return self._regex 

607 

608 def _set_regex(self, regex): 

609 if isinstance(regex, str): 

610 regex = re.compile(regex) 

611 self._regex = regex 

612 if ( 

613 hasattr(self, "_regex_validator") 

614 and self._regex_validator in self.validators 

615 ): 

616 self.validators.remove(self._regex_validator) 

617 self._regex_validator = validators.RegexValidator(regex=regex) 

618 self.validators.append(self._regex_validator) 

619 

620 regex = property(_get_regex, _set_regex) 

621 

622 

623class EmailField(CharField): 

624 widget = EmailInput 

625 default_validators = [validators.validate_email] 

626 

627 def __init__(self, **kwargs): 

628 # The default maximum length of an email is 320 characters per RFC 3696 

629 # section 3. 

630 kwargs.setdefault("max_length", 320) 

631 super().__init__(strip=True, **kwargs) 

632 

633 

634class FileField(Field): 

635 widget = ClearableFileInput 

636 default_error_messages = { 

637 "invalid": _("No file was submitted. Check the encoding type on the form."), 

638 "missing": _("No file was submitted."), 

639 "empty": _("The submitted file is empty."), 

640 "max_length": ngettext_lazy( 

641 "Ensure this filename has at most %(max)d character (it has %(length)d).", 

642 "Ensure this filename has at most %(max)d characters (it has %(length)d).", 

643 "max", 

644 ), 

645 "contradiction": _( 

646 "Please either submit a file or check the clear checkbox, not both." 

647 ), 

648 } 

649 

650 def __init__(self, *, max_length=None, allow_empty_file=False, **kwargs): 

651 self.max_length = max_length 

652 self.allow_empty_file = allow_empty_file 

653 super().__init__(**kwargs) 

654 

655 def to_python(self, data): 

656 if data in self.empty_values: 

657 return None 

658 

659 # UploadedFile objects should have name and size attributes. 

660 try: 

661 file_name = data.name 

662 file_size = data.size 

663 except AttributeError: 

664 raise ValidationError(self.error_messages["invalid"], code="invalid") 

665 

666 if self.max_length is not None and len(file_name) > self.max_length: 

667 params = {"max": self.max_length, "length": len(file_name)} 

668 raise ValidationError( 

669 self.error_messages["max_length"], code="max_length", params=params 

670 ) 

671 if not file_name: 

672 raise ValidationError(self.error_messages["invalid"], code="invalid") 

673 if not self.allow_empty_file and not file_size: 

674 raise ValidationError(self.error_messages["empty"], code="empty") 

675 

676 return data 

677 

678 def clean(self, data, initial=None): 

679 # If the widget got contradictory inputs, we raise a validation error 

680 if data is FILE_INPUT_CONTRADICTION: 

681 raise ValidationError( 

682 self.error_messages["contradiction"], code="contradiction" 

683 ) 

684 # False means the field value should be cleared; further validation is 

685 # not needed. 

686 if data is False: 

687 if not self.required: 

688 return False 

689 # If the field is required, clearing is not possible (the widget 

690 # shouldn't return False data in that case anyway). False is not 

691 # in self.empty_value; if a False value makes it this far 

692 # it should be validated from here on out as None (so it will be 

693 # caught by the required check). 

694 data = None 

695 if not data and initial: 

696 return initial 

697 return super().clean(data) 

698 

699 def bound_data(self, _, initial): 

700 return initial 

701 

702 def has_changed(self, initial, data): 

703 return not self.disabled and data is not None 

704 

705 def _clean_bound_field(self, bf): 

706 value = bf.initial if self.disabled else bf.data 

707 return self.clean(value, bf.initial) 

708 

709 

710class ImageField(FileField): 

711 default_validators = [validators.validate_image_file_extension] 

712 default_error_messages = { 

713 "invalid_image": _( 

714 "Upload a valid image. The file you uploaded was either not an " 

715 "image or a corrupted image." 

716 ), 

717 } 

718 

719 def to_python(self, data): 

720 """ 

721 Check that the file-upload field data contains a valid image (GIF, JPG, 

722 PNG, etc. -- whatever Pillow supports). 

723 """ 

724 f = super().to_python(data) 

725 if f is None: 

726 return None 

727 

728 from PIL import Image 

729 

730 # We need to get a file object for Pillow. We might have a path or we might 

731 # have to read the data into memory. 

732 if hasattr(data, "temporary_file_path"): 

733 file = data.temporary_file_path() 

734 else: 

735 if hasattr(data, "read"): 

736 file = BytesIO(data.read()) 

737 else: 

738 file = BytesIO(data["content"]) 

739 

740 try: 

741 # load() could spot a truncated JPEG, but it loads the entire 

742 # image in memory, which is a DoS vector. See #3848 and #18520. 

743 image = Image.open(file) 

744 # verify() must be called immediately after the constructor. 

745 image.verify() 

746 

747 # Annotating so subclasses can reuse it for their own validation 

748 f.image = image 

749 # Pillow doesn't detect the MIME type of all formats. In those 

750 # cases, content_type will be None. 

751 f.content_type = Image.MIME.get(image.format) 

752 except Exception as exc: 

753 # Pillow doesn't recognize it as an image. 

754 raise ValidationError( 

755 self.error_messages["invalid_image"], 

756 code="invalid_image", 

757 ) from exc 

758 if hasattr(f, "seek") and callable(f.seek): 

759 f.seek(0) 

760 return f 

761 

762 def widget_attrs(self, widget): 

763 attrs = super().widget_attrs(widget) 

764 if isinstance(widget, FileInput) and "accept" not in widget.attrs: 

765 attrs.setdefault("accept", "image/*") 

766 return attrs 

767 

768 

769class URLField(CharField): 

770 widget = URLInput 

771 default_error_messages = { 

772 "invalid": _("Enter a valid URL."), 

773 } 

774 default_validators = [validators.URLValidator()] 

775 

776 def __init__(self, *, assume_scheme=None, **kwargs): 

777 self.assume_scheme = assume_scheme or "https" 

778 super().__init__(strip=True, **kwargs) 

779 

780 def to_python(self, value): 

781 def split_url(url): 

782 """ 

783 Return a list of url parts via urlsplit(), or raise 

784 ValidationError for some malformed URLs. 

785 """ 

786 try: 

787 return list(urlsplit(url)) 

788 except ValueError: 

789 # urlsplit can raise a ValueError with some 

790 # misformatted URLs. 

791 raise ValidationError(self.error_messages["invalid"], code="invalid") 

792 

793 value = super().to_python(value) 

794 if value: 

795 url_fields = split_url(value) 

796 if not url_fields[0]: 

797 # If no URL scheme given, add a scheme. 

798 url_fields[0] = self.assume_scheme 

799 if not url_fields[1]: 

800 # Assume that if no domain is provided, that the path segment 

801 # contains the domain. 

802 url_fields[1] = url_fields[2] 

803 url_fields[2] = "" 

804 # Rebuild the url_fields list, since the domain segment may now 

805 # contain the path too. 

806 url_fields = split_url(urlunsplit(url_fields)) 

807 value = urlunsplit(url_fields) 

808 return value 

809 

810 

811class BooleanField(Field): 

812 widget = CheckboxInput 

813 

814 def to_python(self, value): 

815 """Return a Python boolean object.""" 

816 # Explicitly check for the string 'False', which is what a hidden field 

817 # will submit for False. Also check for '0', since this is what 

818 # RadioSelect will provide. Because bool("True") == bool('1') == True, 

819 # we don't need to handle that explicitly. 

820 if isinstance(value, str) and value.lower() in ("false", "0"): 

821 value = False 

822 else: 

823 value = bool(value) 

824 return super().to_python(value) 

825 

826 def validate(self, value): 

827 if not value and self.required: 

828 raise ValidationError(self.error_messages["required"], code="required") 

829 

830 def has_changed(self, initial, data): 

831 if self.disabled: 

832 return False 

833 # Sometimes data or initial may be a string equivalent of a boolean 

834 # so we should run it through to_python first to get a boolean value 

835 return self.to_python(initial) != self.to_python(data) 

836 

837 

838class NullBooleanField(BooleanField): 

839 """ 

840 A field whose valid values are None, True, and False. Clean invalid values 

841 to None. 

842 """ 

843 

844 widget = NullBooleanSelect 

845 

846 def to_python(self, value): 

847 """ 

848 Explicitly check for the string 'True' and 'False', which is what a 

849 hidden field will submit for True and False, for 'true' and 'false', 

850 which are likely to be returned by JavaScript serializations of forms, 

851 and for '1' and '0', which is what a RadioField will submit. Unlike 

852 the Booleanfield, this field must check for True because it doesn't 

853 use the bool() function. 

854 """ 

855 if value in (True, "True", "true", "1"): 

856 return True 

857 elif value in (False, "False", "false", "0"): 

858 return False 

859 else: 

860 return None 

861 

862 def validate(self, value): 

863 pass 

864 

865 

866class ChoiceField(Field): 

867 widget = Select 

868 default_error_messages = { 

869 "invalid_choice": _( 

870 "Select a valid choice. %(value)s is not one of the available choices." 

871 ), 

872 } 

873 

874 def __init__(self, *, choices=(), **kwargs): 

875 super().__init__(**kwargs) 

876 self.choices = choices 

877 

878 def __deepcopy__(self, memo): 

879 result = super().__deepcopy__(memo) 

880 result._choices = copy.deepcopy(self._choices, memo) 

881 return result 

882 

883 @property 

884 def choices(self): 

885 return self._choices 

886 

887 @choices.setter 

888 def choices(self, value): 

889 # Setting choices on the field also sets the choices on the widget. 

890 # Note that the property setter for the widget will re-normalize. 

891 self._choices = self.widget.choices = normalize_choices(value) 

892 

893 def to_python(self, value): 

894 """Return a string.""" 

895 if value in self.empty_values: 

896 return "" 

897 return str(value) 

898 

899 def validate(self, value): 

900 """Validate that the input is in self.choices.""" 

901 super().validate(value) 

902 if value and not self.valid_value(value): 

903 raise ValidationError( 

904 self.error_messages["invalid_choice"], 

905 code="invalid_choice", 

906 params={"value": value}, 

907 ) 

908 

909 def valid_value(self, value): 

910 """Check to see if the provided value is a valid choice.""" 

911 text_value = str(value) 

912 for k, v in self.choices: 

913 if isinstance(v, (list, tuple)): 

914 # This is an optgroup, so look inside the group for options 

915 for k2, v2 in v: 

916 if value == k2 or text_value == str(k2): 

917 return True 

918 else: 

919 if value == k or text_value == str(k): 

920 return True 

921 return False 

922 

923 

924class TypedChoiceField(ChoiceField): 

925 def __init__(self, *, coerce=lambda val: val, empty_value="", **kwargs): 

926 self.coerce = coerce 

927 self.empty_value = empty_value 

928 super().__init__(**kwargs) 

929 

930 def _coerce(self, value): 

931 """ 

932 Validate that the value can be coerced to the right type (if not empty). 

933 """ 

934 if value == self.empty_value or value in self.empty_values: 

935 return self.empty_value 

936 try: 

937 value = self.coerce(value) 

938 except (ValueError, TypeError, ValidationError): 

939 raise ValidationError( 

940 self.error_messages["invalid_choice"], 

941 code="invalid_choice", 

942 params={"value": value}, 

943 ) 

944 return value 

945 

946 def clean(self, value): 

947 value = super().clean(value) 

948 return self._coerce(value) 

949 

950 

951class MultipleChoiceField(ChoiceField): 

952 hidden_widget = MultipleHiddenInput 

953 widget = SelectMultiple 

954 default_error_messages = { 

955 "invalid_choice": _( 

956 "Select a valid choice. %(value)s is not one of the available choices." 

957 ), 

958 "invalid_list": _("Enter a list of values."), 

959 } 

960 

961 def to_python(self, value): 

962 if not value: 

963 return [] 

964 elif not isinstance(value, (list, tuple)): 

965 raise ValidationError( 

966 self.error_messages["invalid_list"], code="invalid_list" 

967 ) 

968 return [str(val) for val in value] 

969 

970 def validate(self, value): 

971 """Validate that the input is a list or tuple.""" 

972 if self.required and not value: 

973 raise ValidationError(self.error_messages["required"], code="required") 

974 # Validate that each value in the value list is in self.choices. 

975 for val in value: 

976 if not self.valid_value(val): 

977 raise ValidationError( 

978 self.error_messages["invalid_choice"], 

979 code="invalid_choice", 

980 params={"value": val}, 

981 ) 

982 

983 def has_changed(self, initial, data): 

984 if self.disabled: 

985 return False 

986 if initial is None: 

987 initial = [] 

988 if data is None: 

989 data = [] 

990 if len(initial) != len(data): 

991 return True 

992 initial_set = {str(value) for value in initial} 

993 data_set = {str(value) for value in data} 

994 return data_set != initial_set 

995 

996 

997class TypedMultipleChoiceField(MultipleChoiceField): 

998 def __init__(self, *, coerce=lambda val: val, **kwargs): 

999 self.coerce = coerce 

1000 self.empty_value = kwargs.pop("empty_value", []) 

1001 super().__init__(**kwargs) 

1002 

1003 def _coerce(self, value): 

1004 """ 

1005 Validate that the values are in self.choices and can be coerced to the 

1006 right type. 

1007 """ 

1008 if value == self.empty_value or value in self.empty_values: 

1009 return self.empty_value 

1010 new_value = [] 

1011 for choice in value: 

1012 try: 

1013 new_value.append(self.coerce(choice)) 

1014 except (ValueError, TypeError, ValidationError): 

1015 raise ValidationError( 

1016 self.error_messages["invalid_choice"], 

1017 code="invalid_choice", 

1018 params={"value": choice}, 

1019 ) 

1020 return new_value 

1021 

1022 def clean(self, value): 

1023 value = super().clean(value) 

1024 return self._coerce(value) 

1025 

1026 def validate(self, value): 

1027 if value != self.empty_value: 

1028 super().validate(value) 

1029 elif self.required: 

1030 raise ValidationError(self.error_messages["required"], code="required") 

1031 

1032 

1033class ComboField(Field): 

1034 """ 

1035 A Field whose clean() method calls multiple Field clean() methods. 

1036 """ 

1037 

1038 def __init__(self, fields, **kwargs): 

1039 super().__init__(**kwargs) 

1040 # Set 'required' to False on the individual fields, because the 

1041 # required validation will be handled by ComboField, not by those 

1042 # individual fields. 

1043 for f in fields: 

1044 f.required = False 

1045 self.fields = fields 

1046 

1047 def clean(self, value): 

1048 """ 

1049 Validate the given value against all of self.fields, which is a 

1050 list of Field instances. 

1051 """ 

1052 super().clean(value) 

1053 for field in self.fields: 

1054 value = field.clean(value) 

1055 return value 

1056 

1057 

1058class MultiValueField(Field): 

1059 """ 

1060 Aggregate the logic of multiple Fields. 

1061 

1062 Its clean() method takes a "decompressed" list of values, which are then 

1063 cleaned into a single value according to self.fields. Each value in 

1064 this list is cleaned by the corresponding field -- the first value is 

1065 cleaned by the first field, the second value is cleaned by the second 

1066 field, etc. Once all fields are cleaned, the list of clean values is 

1067 "compressed" into a single value. 

1068 

1069 Subclasses should not have to implement clean(). Instead, they must 

1070 implement compress(), which takes a list of valid values and returns a 

1071 "compressed" version of those values -- a single value. 

1072 

1073 You'll probably want to use this with MultiWidget. 

1074 """ 

1075 

1076 default_error_messages = { 

1077 "invalid": _("Enter a list of values."), 

1078 "incomplete": _("Enter a complete value."), 

1079 } 

1080 

1081 def __init__(self, fields, *, require_all_fields=True, **kwargs): 

1082 self.require_all_fields = require_all_fields 

1083 super().__init__(**kwargs) 

1084 for f in fields: 

1085 f.error_messages.setdefault("incomplete", self.error_messages["incomplete"]) 

1086 if self.disabled: 

1087 f.disabled = True 

1088 if self.require_all_fields: 

1089 # Set 'required' to False on the individual fields, because the 

1090 # required validation will be handled by MultiValueField, not 

1091 # by those individual fields. 

1092 f.required = False 

1093 self.fields = fields 

1094 

1095 def __deepcopy__(self, memo): 

1096 result = super().__deepcopy__(memo) 

1097 result.fields = tuple(x.__deepcopy__(memo) for x in self.fields) 

1098 return result 

1099 

1100 def validate(self, value): 

1101 pass 

1102 

1103 def clean(self, value): 

1104 """ 

1105 Validate every value in the given list. A value is validated against 

1106 the corresponding Field in self.fields. 

1107 

1108 For example, if this MultiValueField was instantiated with 

1109 fields=(DateField(), TimeField()), clean() would call 

1110 DateField.clean(value[0]) and TimeField.clean(value[1]). 

1111 """ 

1112 clean_data = [] 

1113 errors = [] 

1114 if self.disabled and not isinstance(value, list): 

1115 value = self.widget.decompress(value) 

1116 if not value or isinstance(value, (list, tuple)): 

1117 if not value or not [v for v in value if v not in self.empty_values]: 

1118 if self.required: 

1119 raise ValidationError( 

1120 self.error_messages["required"], code="required" 

1121 ) 

1122 else: 

1123 return self.compress([]) 

1124 else: 

1125 raise ValidationError(self.error_messages["invalid"], code="invalid") 

1126 for i, field in enumerate(self.fields): 

1127 try: 

1128 field_value = value[i] 

1129 except IndexError: 

1130 field_value = None 

1131 if field_value in self.empty_values: 

1132 if self.require_all_fields: 

1133 # Raise a 'required' error if the MultiValueField is 

1134 # required and any field is empty. 

1135 if self.required: 

1136 raise ValidationError( 

1137 self.error_messages["required"], code="required" 

1138 ) 

1139 elif field.required: 

1140 # Otherwise, add an 'incomplete' error to the list of 

1141 # collected errors and skip field cleaning, if a required 

1142 # field is empty. 

1143 if field.error_messages["incomplete"] not in errors: 

1144 errors.append(field.error_messages["incomplete"]) 

1145 continue 

1146 try: 

1147 clean_data.append(field.clean(field_value)) 

1148 except ValidationError as e: 

1149 # Collect all validation errors in a single list, which we'll 

1150 # raise at the end of clean(), rather than raising a single 

1151 # exception for the first error we encounter. Skip duplicates. 

1152 errors.extend(m for m in e.error_list if m not in errors) 

1153 if errors: 

1154 raise ValidationError(errors) 

1155 

1156 out = self.compress(clean_data) 

1157 self.validate(out) 

1158 self.run_validators(out) 

1159 return out 

1160 

1161 def compress(self, data_list): 

1162 """ 

1163 Return a single value for the given list of values. The values can be 

1164 assumed to be valid. 

1165 

1166 For example, if this MultiValueField was instantiated with 

1167 fields=(DateField(), TimeField()), this might return a datetime 

1168 object created by combining the date and time in data_list. 

1169 """ 

1170 raise NotImplementedError("Subclasses must implement this method.") 

1171 

1172 def has_changed(self, initial, data): 

1173 if self.disabled: 

1174 return False 

1175 if initial is None: 

1176 initial = ["" for x in range(0, len(data))] 

1177 else: 

1178 if not isinstance(initial, list): 

1179 initial = self.widget.decompress(initial) 

1180 for field, initial, data in zip(self.fields, initial, data): 

1181 try: 

1182 initial = field.to_python(initial) 

1183 except ValidationError: 

1184 return True 

1185 if field.has_changed(initial, data): 

1186 return True 

1187 return False 

1188 

1189 

1190class FilePathField(ChoiceField): 

1191 def __init__( 

1192 self, 

1193 path, 

1194 *, 

1195 match=None, 

1196 recursive=False, 

1197 allow_files=True, 

1198 allow_folders=False, 

1199 **kwargs, 

1200 ): 

1201 self.path, self.match, self.recursive = path, match, recursive 

1202 self.allow_files, self.allow_folders = allow_files, allow_folders 

1203 super().__init__(choices=(), **kwargs) 

1204 

1205 if self.required: 

1206 self.choices = [] 

1207 else: 

1208 self.choices = [("", "---------")] 

1209 

1210 if self.match is not None: 

1211 self.match_re = re.compile(self.match) 

1212 

1213 if recursive: 

1214 for root, dirs, files in sorted(os.walk(self.path)): 

1215 if self.allow_files: 

1216 for f in sorted(files): 

1217 if self.match is None or self.match_re.search(f): 

1218 f = os.path.join(root, f) 

1219 self.choices.append((f, f.replace(path, "", 1))) 

1220 if self.allow_folders: 

1221 for f in sorted(dirs): 

1222 if f == "__pycache__": 

1223 continue 

1224 if self.match is None or self.match_re.search(f): 

1225 f = os.path.join(root, f) 

1226 self.choices.append((f, f.replace(path, "", 1))) 

1227 else: 

1228 choices = [] 

1229 with os.scandir(self.path) as entries: 

1230 for f in entries: 

1231 if f.name == "__pycache__": 

1232 continue 

1233 if ( 

1234 (self.allow_files and f.is_file()) 

1235 or (self.allow_folders and f.is_dir()) 

1236 ) and (self.match is None or self.match_re.search(f.name)): 

1237 choices.append((f.path, f.name)) 

1238 choices.sort(key=operator.itemgetter(1)) 

1239 self.choices.extend(choices) 

1240 

1241 self.widget.choices = self.choices 

1242 

1243 

1244class SplitDateTimeField(MultiValueField): 

1245 widget = SplitDateTimeWidget 

1246 hidden_widget = SplitHiddenDateTimeWidget 

1247 default_error_messages = { 

1248 "invalid_date": _("Enter a valid date."), 

1249 "invalid_time": _("Enter a valid time."), 

1250 } 

1251 

1252 def __init__(self, *, input_date_formats=None, input_time_formats=None, **kwargs): 

1253 errors = self.default_error_messages.copy() 

1254 if "error_messages" in kwargs: 

1255 errors.update(kwargs["error_messages"]) 

1256 localize = kwargs.get("localize", False) 

1257 fields = ( 

1258 DateField( 

1259 input_formats=input_date_formats, 

1260 error_messages={"invalid": errors["invalid_date"]}, 

1261 localize=localize, 

1262 ), 

1263 TimeField( 

1264 input_formats=input_time_formats, 

1265 error_messages={"invalid": errors["invalid_time"]}, 

1266 localize=localize, 

1267 ), 

1268 ) 

1269 super().__init__(fields, **kwargs) 

1270 

1271 def compress(self, data_list): 

1272 if data_list: 

1273 # Raise a validation error if time or date is empty 

1274 # (possible if SplitDateTimeField has required=False). 

1275 if data_list[0] in self.empty_values: 

1276 raise ValidationError( 

1277 self.error_messages["invalid_date"], code="invalid_date" 

1278 ) 

1279 if data_list[1] in self.empty_values: 

1280 raise ValidationError( 

1281 self.error_messages["invalid_time"], code="invalid_time" 

1282 ) 

1283 result = datetime.datetime.combine(*data_list) 

1284 return from_current_timezone(result) 

1285 return None 

1286 

1287 

1288class GenericIPAddressField(CharField): 

1289 def __init__(self, *, protocol="both", unpack_ipv4=False, **kwargs): 

1290 self.unpack_ipv4 = unpack_ipv4 

1291 self.default_validators = validators.ip_address_validators( 

1292 protocol, unpack_ipv4 

1293 ) 

1294 kwargs.setdefault("max_length", MAX_IPV6_ADDRESS_LENGTH) 

1295 super().__init__(**kwargs) 

1296 

1297 def to_python(self, value): 

1298 if value in self.empty_values: 

1299 return "" 

1300 value = value.strip() 

1301 if value and ":" in value: 

1302 return clean_ipv6_address( 

1303 value, self.unpack_ipv4, max_length=self.max_length 

1304 ) 

1305 return value 

1306 

1307 

1308class SlugField(CharField): 

1309 default_validators = [validators.validate_slug] 

1310 

1311 def __init__(self, *, allow_unicode=False, **kwargs): 

1312 self.allow_unicode = allow_unicode 

1313 if self.allow_unicode: 

1314 self.default_validators = [validators.validate_unicode_slug] 

1315 super().__init__(**kwargs) 

1316 

1317 

1318class UUIDField(CharField): 

1319 default_error_messages = { 

1320 "invalid": _("Enter a valid UUID."), 

1321 } 

1322 

1323 def prepare_value(self, value): 

1324 if isinstance(value, uuid.UUID): 

1325 return str(value) 

1326 return value 

1327 

1328 def to_python(self, value): 

1329 value = super().to_python(value) 

1330 if value in self.empty_values: 

1331 return None 

1332 if not isinstance(value, uuid.UUID): 

1333 try: 

1334 value = uuid.UUID(value) 

1335 except ValueError: 

1336 raise ValidationError(self.error_messages["invalid"], code="invalid") 

1337 return value 

1338 

1339 

1340class InvalidJSONInput(str): 

1341 pass 

1342 

1343 

1344class JSONString(str): 

1345 pass 

1346 

1347 

1348class JSONField(CharField): 

1349 default_error_messages = { 

1350 "invalid": _("Enter a valid JSON."), 

1351 } 

1352 widget = Textarea 

1353 

1354 def __init__(self, encoder=None, decoder=None, **kwargs): 

1355 self.encoder = encoder 

1356 self.decoder = decoder 

1357 super().__init__(**kwargs) 

1358 

1359 def to_python(self, value): 

1360 if self.disabled: 

1361 return value 

1362 if value in self.empty_values: 

1363 return None 

1364 elif isinstance(value, (list, dict, int, float, JSONString)): 

1365 return value 

1366 try: 

1367 converted = json.loads(value, cls=self.decoder) 

1368 except json.JSONDecodeError: 

1369 raise ValidationError( 

1370 self.error_messages["invalid"], 

1371 code="invalid", 

1372 params={"value": value}, 

1373 ) 

1374 if isinstance(converted, str): 

1375 return JSONString(converted) 

1376 else: 

1377 return converted 

1378 

1379 def bound_data(self, data, initial): 

1380 if self.disabled: 

1381 return initial 

1382 if data is None: 

1383 return None 

1384 try: 

1385 return json.loads(data, cls=self.decoder) 

1386 except json.JSONDecodeError: 

1387 return InvalidJSONInput(data) 

1388 

1389 def prepare_value(self, value): 

1390 if isinstance(value, InvalidJSONInput): 

1391 return value 

1392 return json.dumps(value, ensure_ascii=False, cls=self.encoder) 

1393 

1394 def has_changed(self, initial, data): 

1395 if super().has_changed(initial, data): 

1396 return True 

1397 # For purposes of seeing whether something has changed, True isn't the 

1398 # same as 1 and the order of keys doesn't matter. 

1399 return json.dumps(initial, sort_keys=True, cls=self.encoder) != json.dumps( 

1400 self.to_python(data), sort_keys=True, cls=self.encoder 

1401 )