| 635 | |
| 636 | |
| 637 | class FileField(Field): |
| 638 | widget = ClearableFileInput |
| 639 | default_error_messages = { |
| 640 | "invalid": _("No file was submitted. Check the encoding type on the form."), |
| 641 | "missing": _("No file was submitted."), |
| 642 | "empty": _("The submitted file is empty."), |
| 643 | "max_length": ngettext_lazy( |
| 644 | "Ensure this filename has at most %(max)d character (it has %(length)d).", |
| 645 | "Ensure this filename has at most %(max)d characters (it has %(length)d).", |
| 646 | "max", |
| 647 | ), |
| 648 | "contradiction": _( |
| 649 | "Please either submit a file or check the clear checkbox, not both." |
| 650 | ), |
| 651 | } |
| 652 | |
| 653 | def __init__(self, *, max_length=None, allow_empty_file=False, **kwargs): |
| 654 | self.max_length = max_length |
| 655 | self.allow_empty_file = allow_empty_file |
| 656 | super().__init__(**kwargs) |
| 657 | |
| 658 | def to_python(self, data): |
| 659 | if data in self.empty_values: |
| 660 | return None |
| 661 | |
| 662 | # UploadedFile objects should have name and size attributes. |
| 663 | try: |
| 664 | file_name = data.name |
| 665 | file_size = data.size |
| 666 | except AttributeError: |
| 667 | raise ValidationError(self.error_messages["invalid"], code="invalid") |
| 668 | |
| 669 | if self.max_length is not None and len(file_name) > self.max_length: |
| 670 | params = {"max": self.max_length, "length": len(file_name)} |
| 671 | raise ValidationError( |
| 672 | self.error_messages["max_length"], code="max_length", params=params |
| 673 | ) |
| 674 | if not file_name: |
| 675 | raise ValidationError(self.error_messages["invalid"], code="invalid") |
| 676 | if not self.allow_empty_file and not file_size: |
| 677 | raise ValidationError(self.error_messages["empty"], code="empty") |
| 678 | |
| 679 | return data |
| 680 | |
| 681 | def clean(self, data, initial=None): |
| 682 | # If the widget got contradictory inputs, we raise a validation error |
| 683 | if data is FILE_INPUT_CONTRADICTION: |
| 684 | raise ValidationError( |
| 685 | self.error_messages["contradiction"], code="contradiction" |
| 686 | ) |
| 687 | # False means the field value should be cleared; further validation is |
| 688 | # not needed. |
| 689 | if data is False: |
| 690 | if not self.required: |
| 691 | return False |
| 692 | # If the field is required, clearing is not possible (the widget |
| 693 | # shouldn't return False data in that case anyway). False is not |
| 694 | # in self.empty_value; if a False value makes it this far |