docker setup
This commit is contained in:
		| @ -0,0 +1,11 @@ | ||||
| """ | ||||
| Django validation and HTML form handling. | ||||
| """ | ||||
|  | ||||
| from django.core.exceptions import ValidationError  # NOQA | ||||
| from django.forms.boundfield import *  # NOQA | ||||
| from django.forms.fields import *  # NOQA | ||||
| from django.forms.forms import *  # NOQA | ||||
| from django.forms.formsets import *  # NOQA | ||||
| from django.forms.models import *  # NOQA | ||||
| from django.forms.widgets import *  # NOQA | ||||
| @ -0,0 +1,344 @@ | ||||
| import re | ||||
|  | ||||
| from django.core.exceptions import ValidationError | ||||
| from django.forms.utils import pretty_name | ||||
| from django.forms.widgets import MultiWidget, Textarea, TextInput | ||||
| from django.utils.functional import cached_property | ||||
| from django.utils.html import format_html, html_safe | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
|  | ||||
| __all__ = ("BoundField",) | ||||
|  | ||||
|  | ||||
| @html_safe | ||||
| class BoundField: | ||||
|     "A Field plus data" | ||||
|  | ||||
|     def __init__(self, form, field, name): | ||||
|         self.form = form | ||||
|         self.field = field | ||||
|         self.name = name | ||||
|         self.html_name = form.add_prefix(name) | ||||
|         self.html_initial_name = form.add_initial_prefix(name) | ||||
|         self.html_initial_id = form.add_initial_prefix(self.auto_id) | ||||
|         if self.field.label is None: | ||||
|             self.label = pretty_name(name) | ||||
|         else: | ||||
|             self.label = self.field.label | ||||
|         self.help_text = field.help_text or "" | ||||
|  | ||||
|     def __str__(self): | ||||
|         """Render this field as an HTML widget.""" | ||||
|         if self.field.show_hidden_initial: | ||||
|             return self.as_widget() + self.as_hidden(only_initial=True) | ||||
|         return self.as_widget() | ||||
|  | ||||
|     @cached_property | ||||
|     def subwidgets(self): | ||||
|         """ | ||||
|         Most widgets yield a single subwidget, but others like RadioSelect and | ||||
|         CheckboxSelectMultiple produce one subwidget for each choice. | ||||
|  | ||||
|         This property is cached so that only one database query occurs when | ||||
|         rendering ModelChoiceFields. | ||||
|         """ | ||||
|         id_ = self.field.widget.attrs.get("id") or self.auto_id | ||||
|         attrs = {"id": id_} if id_ else {} | ||||
|         attrs = self.build_widget_attrs(attrs) | ||||
|         return [ | ||||
|             BoundWidget(self.field.widget, widget, self.form.renderer) | ||||
|             for widget in self.field.widget.subwidgets( | ||||
|                 self.html_name, self.value(), attrs=attrs | ||||
|             ) | ||||
|         ] | ||||
|  | ||||
|     def __bool__(self): | ||||
|         # BoundField evaluates to True even if it doesn't have subwidgets. | ||||
|         return True | ||||
|  | ||||
|     def __iter__(self): | ||||
|         return iter(self.subwidgets) | ||||
|  | ||||
|     def __len__(self): | ||||
|         return len(self.subwidgets) | ||||
|  | ||||
|     def __getitem__(self, idx): | ||||
|         # Prevent unnecessary reevaluation when accessing BoundField's attrs | ||||
|         # from templates. | ||||
|         if not isinstance(idx, (int, slice)): | ||||
|             raise TypeError( | ||||
|                 "BoundField indices must be integers or slices, not %s." | ||||
|                 % type(idx).__name__ | ||||
|             ) | ||||
|         return self.subwidgets[idx] | ||||
|  | ||||
|     @property | ||||
|     def errors(self): | ||||
|         """ | ||||
|         Return an ErrorList (empty if there are no errors) for this field. | ||||
|         """ | ||||
|         return self.form.errors.get( | ||||
|             self.name, self.form.error_class(renderer=self.form.renderer) | ||||
|         ) | ||||
|  | ||||
|     def as_widget(self, widget=None, attrs=None, only_initial=False): | ||||
|         """ | ||||
|         Render the field by rendering the passed widget, adding any HTML | ||||
|         attributes passed as attrs. If a widget isn't specified, use the | ||||
|         field's default widget. | ||||
|         """ | ||||
|         widget = widget or self.field.widget | ||||
|         if self.field.localize: | ||||
|             widget.is_localized = True | ||||
|         attrs = attrs or {} | ||||
|         attrs = self.build_widget_attrs(attrs, widget) | ||||
|         if self.auto_id and "id" not in widget.attrs: | ||||
|             attrs.setdefault( | ||||
|                 "id", self.html_initial_id if only_initial else self.auto_id | ||||
|             ) | ||||
|         if only_initial and self.html_initial_name in self.form.data: | ||||
|             # Propagate the hidden initial value. | ||||
|             value = self.form._widget_data_value( | ||||
|                 self.field.hidden_widget(), | ||||
|                 self.html_initial_name, | ||||
|             ) | ||||
|         else: | ||||
|             value = self.value() | ||||
|         return widget.render( | ||||
|             name=self.html_initial_name if only_initial else self.html_name, | ||||
|             value=value, | ||||
|             attrs=attrs, | ||||
|             renderer=self.form.renderer, | ||||
|         ) | ||||
|  | ||||
|     def as_text(self, attrs=None, **kwargs): | ||||
|         """ | ||||
|         Return a string of HTML for representing this as an <input type="text">. | ||||
|         """ | ||||
|         return self.as_widget(TextInput(), attrs, **kwargs) | ||||
|  | ||||
|     def as_textarea(self, attrs=None, **kwargs): | ||||
|         """Return a string of HTML for representing this as a <textarea>.""" | ||||
|         return self.as_widget(Textarea(), attrs, **kwargs) | ||||
|  | ||||
|     def as_hidden(self, attrs=None, **kwargs): | ||||
|         """ | ||||
|         Return a string of HTML for representing this as an <input type="hidden">. | ||||
|         """ | ||||
|         return self.as_widget(self.field.hidden_widget(), attrs, **kwargs) | ||||
|  | ||||
|     @property | ||||
|     def data(self): | ||||
|         """ | ||||
|         Return the data for this BoundField, or None if it wasn't given. | ||||
|         """ | ||||
|         return self.form._widget_data_value(self.field.widget, self.html_name) | ||||
|  | ||||
|     def value(self): | ||||
|         """ | ||||
|         Return the value for this BoundField, using the initial value if | ||||
|         the form is not bound or the data otherwise. | ||||
|         """ | ||||
|         data = self.initial | ||||
|         if self.form.is_bound: | ||||
|             data = self.field.bound_data(self.data, data) | ||||
|         return self.field.prepare_value(data) | ||||
|  | ||||
|     def _has_changed(self): | ||||
|         field = self.field | ||||
|         if field.show_hidden_initial: | ||||
|             hidden_widget = field.hidden_widget() | ||||
|             initial_value = self.form._widget_data_value( | ||||
|                 hidden_widget, | ||||
|                 self.html_initial_name, | ||||
|             ) | ||||
|             try: | ||||
|                 initial_value = field.to_python(initial_value) | ||||
|             except ValidationError: | ||||
|                 # Always assume data has changed if validation fails. | ||||
|                 return True | ||||
|         else: | ||||
|             initial_value = self.initial | ||||
|         return field.has_changed(initial_value, self.data) | ||||
|  | ||||
|     def label_tag(self, contents=None, attrs=None, label_suffix=None, tag=None): | ||||
|         """ | ||||
|         Wrap the given contents in a <label>, if the field has an ID attribute. | ||||
|         contents should be mark_safe'd to avoid HTML escaping. If contents | ||||
|         aren't given, use the field's HTML-escaped label. | ||||
|  | ||||
|         If attrs are given, use them as HTML attributes on the <label> tag. | ||||
|  | ||||
|         label_suffix overrides the form's label_suffix. | ||||
|         """ | ||||
|         contents = contents or self.label | ||||
|         if label_suffix is None: | ||||
|             label_suffix = ( | ||||
|                 self.field.label_suffix | ||||
|                 if self.field.label_suffix is not None | ||||
|                 else self.form.label_suffix | ||||
|             ) | ||||
|         # Only add the suffix if the label does not end in punctuation. | ||||
|         # Translators: If found as last label character, these punctuation | ||||
|         # characters will prevent the default label_suffix to be appended to the label | ||||
|         if label_suffix and contents and contents[-1] not in _(":?.!"): | ||||
|             contents = format_html("{}{}", contents, label_suffix) | ||||
|         widget = self.field.widget | ||||
|         id_ = widget.attrs.get("id") or self.auto_id | ||||
|         if id_: | ||||
|             id_for_label = widget.id_for_label(id_) | ||||
|             if id_for_label: | ||||
|                 attrs = {**(attrs or {}), "for": id_for_label} | ||||
|             if self.field.required and hasattr(self.form, "required_css_class"): | ||||
|                 attrs = attrs or {} | ||||
|                 if "class" in attrs: | ||||
|                     attrs["class"] += " " + self.form.required_css_class | ||||
|                 else: | ||||
|                     attrs["class"] = self.form.required_css_class | ||||
|         context = { | ||||
|             "field": self, | ||||
|             "label": contents, | ||||
|             "attrs": attrs, | ||||
|             "use_tag": bool(id_), | ||||
|             "tag": tag or "label", | ||||
|         } | ||||
|         return self.form.render(self.form.template_name_label, context) | ||||
|  | ||||
|     def legend_tag(self, contents=None, attrs=None, label_suffix=None): | ||||
|         """ | ||||
|         Wrap the given contents in a <legend>, if the field has an ID | ||||
|         attribute. Contents should be mark_safe'd to avoid HTML escaping. If | ||||
|         contents aren't given, use the field's HTML-escaped label. | ||||
|  | ||||
|         If attrs are given, use them as HTML attributes on the <legend> tag. | ||||
|  | ||||
|         label_suffix overrides the form's label_suffix. | ||||
|         """ | ||||
|         return self.label_tag(contents, attrs, label_suffix, tag="legend") | ||||
|  | ||||
|     def css_classes(self, extra_classes=None): | ||||
|         """ | ||||
|         Return a string of space-separated CSS classes for this field. | ||||
|         """ | ||||
|         if hasattr(extra_classes, "split"): | ||||
|             extra_classes = extra_classes.split() | ||||
|         extra_classes = set(extra_classes or []) | ||||
|         if self.errors and hasattr(self.form, "error_css_class"): | ||||
|             extra_classes.add(self.form.error_css_class) | ||||
|         if self.field.required and hasattr(self.form, "required_css_class"): | ||||
|             extra_classes.add(self.form.required_css_class) | ||||
|         return " ".join(extra_classes) | ||||
|  | ||||
|     @property | ||||
|     def is_hidden(self): | ||||
|         """Return True if this BoundField's widget is hidden.""" | ||||
|         return self.field.widget.is_hidden | ||||
|  | ||||
|     @property | ||||
|     def auto_id(self): | ||||
|         """ | ||||
|         Calculate and return the ID attribute for this BoundField, if the | ||||
|         associated Form has specified auto_id. Return an empty string otherwise. | ||||
|         """ | ||||
|         auto_id = self.form.auto_id  # Boolean or string | ||||
|         if auto_id and "%s" in str(auto_id): | ||||
|             return auto_id % self.html_name | ||||
|         elif auto_id: | ||||
|             return self.html_name | ||||
|         return "" | ||||
|  | ||||
|     @property | ||||
|     def id_for_label(self): | ||||
|         """ | ||||
|         Wrapper around the field widget's `id_for_label` method. | ||||
|         Useful, for example, for focusing on this field regardless of whether | ||||
|         it has a single widget or a MultiWidget. | ||||
|         """ | ||||
|         widget = self.field.widget | ||||
|         id_ = widget.attrs.get("id") or self.auto_id | ||||
|         return widget.id_for_label(id_) | ||||
|  | ||||
|     @cached_property | ||||
|     def initial(self): | ||||
|         return self.form.get_initial_for_field(self.field, self.name) | ||||
|  | ||||
|     def build_widget_attrs(self, attrs, widget=None): | ||||
|         widget = widget or self.field.widget | ||||
|         attrs = dict(attrs)  # Copy attrs to avoid modifying the argument. | ||||
|         if ( | ||||
|             widget.use_required_attribute(self.initial) | ||||
|             and self.field.required | ||||
|             and self.form.use_required_attribute | ||||
|         ): | ||||
|             # MultiValueField has require_all_fields: if False, fall back | ||||
|             # on subfields. | ||||
|             if ( | ||||
|                 hasattr(self.field, "require_all_fields") | ||||
|                 and not self.field.require_all_fields | ||||
|                 and isinstance(self.field.widget, MultiWidget) | ||||
|             ): | ||||
|                 for subfield, subwidget in zip(self.field.fields, widget.widgets): | ||||
|                     subwidget.attrs["required"] = ( | ||||
|                         subwidget.use_required_attribute(self.initial) | ||||
|                         and subfield.required | ||||
|                     ) | ||||
|             else: | ||||
|                 attrs["required"] = True | ||||
|         if self.field.disabled: | ||||
|             attrs["disabled"] = True | ||||
|         return attrs | ||||
|  | ||||
|     @property | ||||
|     def widget_type(self): | ||||
|         return re.sub( | ||||
|             r"widget$|input$", "", self.field.widget.__class__.__name__.lower() | ||||
|         ) | ||||
|  | ||||
|     @property | ||||
|     def use_fieldset(self): | ||||
|         """ | ||||
|         Return the value of this BoundField widget's use_fieldset attribute. | ||||
|         """ | ||||
|         return self.field.widget.use_fieldset | ||||
|  | ||||
|  | ||||
| @html_safe | ||||
| class BoundWidget: | ||||
|     """ | ||||
|     A container class used for iterating over widgets. This is useful for | ||||
|     widgets that have choices. For example, the following can be used in a | ||||
|     template: | ||||
|  | ||||
|     {% for radio in myform.beatles %} | ||||
|       <label for="{{ radio.id_for_label }}"> | ||||
|         {{ radio.choice_label }} | ||||
|         <span class="radio">{{ radio.tag }}</span> | ||||
|       </label> | ||||
|     {% endfor %} | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, parent_widget, data, renderer): | ||||
|         self.parent_widget = parent_widget | ||||
|         self.data = data | ||||
|         self.renderer = renderer | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.tag(wrap_label=True) | ||||
|  | ||||
|     def tag(self, wrap_label=False): | ||||
|         context = {"widget": {**self.data, "wrap_label": wrap_label}} | ||||
|         return self.parent_widget._render(self.template_name, context, self.renderer) | ||||
|  | ||||
|     @property | ||||
|     def template_name(self): | ||||
|         if "template_name" in self.data: | ||||
|             return self.data["template_name"] | ||||
|         return self.parent_widget.template_name | ||||
|  | ||||
|     @property | ||||
|     def id_for_label(self): | ||||
|         return self.data["attrs"].get("id") | ||||
|  | ||||
|     @property | ||||
|     def choice_label(self): | ||||
|         return self.data["label"] | ||||
							
								
								
									
										1391
									
								
								srcs/.venv/lib/python3.11/site-packages/django/forms/fields.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1391
									
								
								srcs/.venv/lib/python3.11/site-packages/django/forms/fields.py
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										539
									
								
								srcs/.venv/lib/python3.11/site-packages/django/forms/forms.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										539
									
								
								srcs/.venv/lib/python3.11/site-packages/django/forms/forms.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,539 @@ | ||||
| """ | ||||
| Form classes | ||||
| """ | ||||
|  | ||||
| import copy | ||||
| import datetime | ||||
| import warnings | ||||
|  | ||||
| from django.core.exceptions import NON_FIELD_ERRORS, ValidationError | ||||
| from django.forms.fields import Field, FileField | ||||
| from django.forms.utils import ErrorDict, ErrorList, RenderableFormMixin | ||||
| from django.forms.widgets import Media, MediaDefiningClass | ||||
| from django.utils.datastructures import MultiValueDict | ||||
| from django.utils.deprecation import RemovedInDjango50Warning | ||||
| from django.utils.functional import cached_property | ||||
| from django.utils.html import conditional_escape | ||||
| from django.utils.safestring import SafeString, mark_safe | ||||
| from django.utils.translation import gettext as _ | ||||
|  | ||||
| from .renderers import get_default_renderer | ||||
|  | ||||
| __all__ = ("BaseForm", "Form") | ||||
|  | ||||
|  | ||||
| class DeclarativeFieldsMetaclass(MediaDefiningClass): | ||||
|     """Collect Fields declared on the base classes.""" | ||||
|  | ||||
|     def __new__(mcs, name, bases, attrs): | ||||
|         # Collect fields from current class and remove them from attrs. | ||||
|         attrs["declared_fields"] = { | ||||
|             key: attrs.pop(key) | ||||
|             for key, value in list(attrs.items()) | ||||
|             if isinstance(value, Field) | ||||
|         } | ||||
|  | ||||
|         new_class = super().__new__(mcs, name, bases, attrs) | ||||
|  | ||||
|         # Walk through the MRO. | ||||
|         declared_fields = {} | ||||
|         for base in reversed(new_class.__mro__): | ||||
|             # Collect fields from base class. | ||||
|             if hasattr(base, "declared_fields"): | ||||
|                 declared_fields.update(base.declared_fields) | ||||
|  | ||||
|             # Field shadowing. | ||||
|             for attr, value in base.__dict__.items(): | ||||
|                 if value is None and attr in declared_fields: | ||||
|                     declared_fields.pop(attr) | ||||
|  | ||||
|         new_class.base_fields = declared_fields | ||||
|         new_class.declared_fields = declared_fields | ||||
|  | ||||
|         return new_class | ||||
|  | ||||
|  | ||||
| class BaseForm(RenderableFormMixin): | ||||
|     """ | ||||
|     The main implementation of all the Form logic. Note that this class is | ||||
|     different than Form. See the comments by the Form class for more info. Any | ||||
|     improvements to the form API should be made to this class, not to the Form | ||||
|     class. | ||||
|     """ | ||||
|  | ||||
|     default_renderer = None | ||||
|     field_order = None | ||||
|     prefix = None | ||||
|     use_required_attribute = True | ||||
|  | ||||
|     template_name_div = "django/forms/div.html" | ||||
|     template_name_p = "django/forms/p.html" | ||||
|     template_name_table = "django/forms/table.html" | ||||
|     template_name_ul = "django/forms/ul.html" | ||||
|     template_name_label = "django/forms/label.html" | ||||
|  | ||||
|     def __init__( | ||||
|         self, | ||||
|         data=None, | ||||
|         files=None, | ||||
|         auto_id="id_%s", | ||||
|         prefix=None, | ||||
|         initial=None, | ||||
|         error_class=ErrorList, | ||||
|         label_suffix=None, | ||||
|         empty_permitted=False, | ||||
|         field_order=None, | ||||
|         use_required_attribute=None, | ||||
|         renderer=None, | ||||
|     ): | ||||
|         self.is_bound = data is not None or files is not None | ||||
|         self.data = MultiValueDict() if data is None else data | ||||
|         self.files = MultiValueDict() if files is None else files | ||||
|         self.auto_id = auto_id | ||||
|         if prefix is not None: | ||||
|             self.prefix = prefix | ||||
|         self.initial = initial or {} | ||||
|         self.error_class = error_class | ||||
|         # Translators: This is the default suffix added to form field labels | ||||
|         self.label_suffix = label_suffix if label_suffix is not None else _(":") | ||||
|         self.empty_permitted = empty_permitted | ||||
|         self._errors = None  # Stores the errors after clean() has been called. | ||||
|  | ||||
|         # The base_fields class attribute is the *class-wide* definition of | ||||
|         # fields. Because a particular *instance* of the class might want to | ||||
|         # alter self.fields, we create self.fields here by copying base_fields. | ||||
|         # Instances should always modify self.fields; they should not modify | ||||
|         # self.base_fields. | ||||
|         self.fields = copy.deepcopy(self.base_fields) | ||||
|         self._bound_fields_cache = {} | ||||
|         self.order_fields(self.field_order if field_order is None else field_order) | ||||
|  | ||||
|         if use_required_attribute is not None: | ||||
|             self.use_required_attribute = use_required_attribute | ||||
|  | ||||
|         if self.empty_permitted and self.use_required_attribute: | ||||
|             raise ValueError( | ||||
|                 "The empty_permitted and use_required_attribute arguments may " | ||||
|                 "not both be True." | ||||
|             ) | ||||
|  | ||||
|         # Initialize form renderer. Use a global default if not specified | ||||
|         # either as an argument or as self.default_renderer. | ||||
|         if renderer is None: | ||||
|             if self.default_renderer is None: | ||||
|                 renderer = get_default_renderer() | ||||
|             else: | ||||
|                 renderer = self.default_renderer | ||||
|                 if isinstance(self.default_renderer, type): | ||||
|                     renderer = renderer() | ||||
|         self.renderer = renderer | ||||
|  | ||||
|     def order_fields(self, field_order): | ||||
|         """ | ||||
|         Rearrange the fields according to field_order. | ||||
|  | ||||
|         field_order is a list of field names specifying the order. Append fields | ||||
|         not included in the list in the default order for backward compatibility | ||||
|         with subclasses not overriding field_order. If field_order is None, | ||||
|         keep all fields in the order defined in the class. Ignore unknown | ||||
|         fields in field_order to allow disabling fields in form subclasses | ||||
|         without redefining ordering. | ||||
|         """ | ||||
|         if field_order is None: | ||||
|             return | ||||
|         fields = {} | ||||
|         for key in field_order: | ||||
|             try: | ||||
|                 fields[key] = self.fields.pop(key) | ||||
|             except KeyError:  # ignore unknown fields | ||||
|                 pass | ||||
|         fields.update(self.fields)  # add remaining fields in original order | ||||
|         self.fields = fields | ||||
|  | ||||
|     def __repr__(self): | ||||
|         if self._errors is None: | ||||
|             is_valid = "Unknown" | ||||
|         else: | ||||
|             is_valid = self.is_bound and not self._errors | ||||
|         return "<%(cls)s bound=%(bound)s, valid=%(valid)s, fields=(%(fields)s)>" % { | ||||
|             "cls": self.__class__.__name__, | ||||
|             "bound": self.is_bound, | ||||
|             "valid": is_valid, | ||||
|             "fields": ";".join(self.fields), | ||||
|         } | ||||
|  | ||||
|     def _bound_items(self): | ||||
|         """Yield (name, bf) pairs, where bf is a BoundField object.""" | ||||
|         for name in self.fields: | ||||
|             yield name, self[name] | ||||
|  | ||||
|     def __iter__(self): | ||||
|         """Yield the form's fields as BoundField objects.""" | ||||
|         for name in self.fields: | ||||
|             yield self[name] | ||||
|  | ||||
|     def __getitem__(self, name): | ||||
|         """Return a BoundField with the given name.""" | ||||
|         try: | ||||
|             field = self.fields[name] | ||||
|         except KeyError: | ||||
|             raise KeyError( | ||||
|                 "Key '%s' not found in '%s'. Choices are: %s." | ||||
|                 % ( | ||||
|                     name, | ||||
|                     self.__class__.__name__, | ||||
|                     ", ".join(sorted(self.fields)), | ||||
|                 ) | ||||
|             ) | ||||
|         if name not in self._bound_fields_cache: | ||||
|             self._bound_fields_cache[name] = field.get_bound_field(self, name) | ||||
|         return self._bound_fields_cache[name] | ||||
|  | ||||
|     @property | ||||
|     def errors(self): | ||||
|         """Return an ErrorDict for the data provided for the form.""" | ||||
|         if self._errors is None: | ||||
|             self.full_clean() | ||||
|         return self._errors | ||||
|  | ||||
|     def is_valid(self): | ||||
|         """Return True if the form has no errors, or False otherwise.""" | ||||
|         return self.is_bound and not self.errors | ||||
|  | ||||
|     def add_prefix(self, field_name): | ||||
|         """ | ||||
|         Return the field name with a prefix appended, if this Form has a | ||||
|         prefix set. | ||||
|  | ||||
|         Subclasses may wish to override. | ||||
|         """ | ||||
|         return "%s-%s" % (self.prefix, field_name) if self.prefix else field_name | ||||
|  | ||||
|     def add_initial_prefix(self, field_name): | ||||
|         """Add an 'initial' prefix for checking dynamic initial values.""" | ||||
|         return "initial-%s" % self.add_prefix(field_name) | ||||
|  | ||||
|     def _widget_data_value(self, widget, html_name): | ||||
|         # value_from_datadict() gets the data from the data dictionaries. | ||||
|         # Each widget type knows how to retrieve its own data, because some | ||||
|         # widgets split data over several HTML fields. | ||||
|         return widget.value_from_datadict(self.data, self.files, html_name) | ||||
|  | ||||
|     def _html_output( | ||||
|         self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row | ||||
|     ): | ||||
|         "Output HTML. Used by as_table(), as_ul(), as_p()." | ||||
|         warnings.warn( | ||||
|             "django.forms.BaseForm._html_output() is deprecated. " | ||||
|             "Please use .render() and .get_context() instead.", | ||||
|             RemovedInDjango50Warning, | ||||
|             stacklevel=2, | ||||
|         ) | ||||
|         # Errors that should be displayed above all fields. | ||||
|         top_errors = self.non_field_errors().copy() | ||||
|         output, hidden_fields = [], [] | ||||
|  | ||||
|         for name, bf in self._bound_items(): | ||||
|             field = bf.field | ||||
|             html_class_attr = "" | ||||
|             bf_errors = self.error_class(bf.errors) | ||||
|             if bf.is_hidden: | ||||
|                 if bf_errors: | ||||
|                     top_errors.extend( | ||||
|                         [ | ||||
|                             _("(Hidden field %(name)s) %(error)s") | ||||
|                             % {"name": name, "error": str(e)} | ||||
|                             for e in bf_errors | ||||
|                         ] | ||||
|                     ) | ||||
|                 hidden_fields.append(str(bf)) | ||||
|             else: | ||||
|                 # Create a 'class="..."' attribute if the row should have any | ||||
|                 # CSS classes applied. | ||||
|                 css_classes = bf.css_classes() | ||||
|                 if css_classes: | ||||
|                     html_class_attr = ' class="%s"' % css_classes | ||||
|  | ||||
|                 if errors_on_separate_row and bf_errors: | ||||
|                     output.append(error_row % str(bf_errors)) | ||||
|  | ||||
|                 if bf.label: | ||||
|                     label = conditional_escape(bf.label) | ||||
|                     label = bf.label_tag(label) or "" | ||||
|                 else: | ||||
|                     label = "" | ||||
|  | ||||
|                 if field.help_text: | ||||
|                     help_text = help_text_html % field.help_text | ||||
|                 else: | ||||
|                     help_text = "" | ||||
|  | ||||
|                 output.append( | ||||
|                     normal_row | ||||
|                     % { | ||||
|                         "errors": bf_errors, | ||||
|                         "label": label, | ||||
|                         "field": bf, | ||||
|                         "help_text": help_text, | ||||
|                         "html_class_attr": html_class_attr, | ||||
|                         "css_classes": css_classes, | ||||
|                         "field_name": bf.html_name, | ||||
|                     } | ||||
|                 ) | ||||
|  | ||||
|         if top_errors: | ||||
|             output.insert(0, error_row % top_errors) | ||||
|  | ||||
|         if hidden_fields:  # Insert any hidden fields in the last row. | ||||
|             str_hidden = "".join(hidden_fields) | ||||
|             if output: | ||||
|                 last_row = output[-1] | ||||
|                 # Chop off the trailing row_ender (e.g. '</td></tr>') and | ||||
|                 # insert the hidden fields. | ||||
|                 if not last_row.endswith(row_ender): | ||||
|                     # This can happen in the as_p() case (and possibly others | ||||
|                     # that users write): if there are only top errors, we may | ||||
|                     # not be able to conscript the last row for our purposes, | ||||
|                     # so insert a new, empty row. | ||||
|                     last_row = normal_row % { | ||||
|                         "errors": "", | ||||
|                         "label": "", | ||||
|                         "field": "", | ||||
|                         "help_text": "", | ||||
|                         "html_class_attr": html_class_attr, | ||||
|                         "css_classes": "", | ||||
|                         "field_name": "", | ||||
|                     } | ||||
|                     output.append(last_row) | ||||
|                 output[-1] = last_row[: -len(row_ender)] + str_hidden + row_ender | ||||
|             else: | ||||
|                 # If there aren't any rows in the output, just append the | ||||
|                 # hidden fields. | ||||
|                 output.append(str_hidden) | ||||
|         return mark_safe("\n".join(output)) | ||||
|  | ||||
|     @property | ||||
|     def template_name(self): | ||||
|         return self.renderer.form_template_name | ||||
|  | ||||
|     def get_context(self): | ||||
|         fields = [] | ||||
|         hidden_fields = [] | ||||
|         top_errors = self.non_field_errors().copy() | ||||
|         for name, bf in self._bound_items(): | ||||
|             bf_errors = self.error_class(bf.errors, renderer=self.renderer) | ||||
|             if bf.is_hidden: | ||||
|                 if bf_errors: | ||||
|                     top_errors += [ | ||||
|                         _("(Hidden field %(name)s) %(error)s") | ||||
|                         % {"name": name, "error": str(e)} | ||||
|                         for e in bf_errors | ||||
|                     ] | ||||
|                 hidden_fields.append(bf) | ||||
|             else: | ||||
|                 errors_str = str(bf_errors) | ||||
|                 # RemovedInDjango50Warning. | ||||
|                 if not isinstance(errors_str, SafeString): | ||||
|                     warnings.warn( | ||||
|                         f"Returning a plain string from " | ||||
|                         f"{self.error_class.__name__} is deprecated. Please " | ||||
|                         f"customize via the template system instead.", | ||||
|                         RemovedInDjango50Warning, | ||||
|                     ) | ||||
|                     errors_str = mark_safe(errors_str) | ||||
|                 fields.append((bf, errors_str)) | ||||
|         return { | ||||
|             "form": self, | ||||
|             "fields": fields, | ||||
|             "hidden_fields": hidden_fields, | ||||
|             "errors": top_errors, | ||||
|         } | ||||
|  | ||||
|     def non_field_errors(self): | ||||
|         """ | ||||
|         Return an ErrorList of errors that aren't associated with a particular | ||||
|         field -- i.e., from Form.clean(). Return an empty ErrorList if there | ||||
|         are none. | ||||
|         """ | ||||
|         return self.errors.get( | ||||
|             NON_FIELD_ERRORS, | ||||
|             self.error_class(error_class="nonfield", renderer=self.renderer), | ||||
|         ) | ||||
|  | ||||
|     def add_error(self, field, error): | ||||
|         """ | ||||
|         Update the content of `self._errors`. | ||||
|  | ||||
|         The `field` argument is the name of the field to which the errors | ||||
|         should be added. If it's None, treat the errors as NON_FIELD_ERRORS. | ||||
|  | ||||
|         The `error` argument can be a single error, a list of errors, or a | ||||
|         dictionary that maps field names to lists of errors. An "error" can be | ||||
|         either a simple string or an instance of ValidationError with its | ||||
|         message attribute set and a "list or dictionary" can be an actual | ||||
|         `list` or `dict` or an instance of ValidationError with its | ||||
|         `error_list` or `error_dict` attribute set. | ||||
|  | ||||
|         If `error` is a dictionary, the `field` argument *must* be None and | ||||
|         errors will be added to the fields that correspond to the keys of the | ||||
|         dictionary. | ||||
|         """ | ||||
|         if not isinstance(error, ValidationError): | ||||
|             # Normalize to ValidationError and let its constructor | ||||
|             # do the hard work of making sense of the input. | ||||
|             error = ValidationError(error) | ||||
|  | ||||
|         if hasattr(error, "error_dict"): | ||||
|             if field is not None: | ||||
|                 raise TypeError( | ||||
|                     "The argument `field` must be `None` when the `error` " | ||||
|                     "argument contains errors for multiple fields." | ||||
|                 ) | ||||
|             else: | ||||
|                 error = error.error_dict | ||||
|         else: | ||||
|             error = {field or NON_FIELD_ERRORS: error.error_list} | ||||
|  | ||||
|         for field, error_list in error.items(): | ||||
|             if field not in self.errors: | ||||
|                 if field != NON_FIELD_ERRORS and field not in self.fields: | ||||
|                     raise ValueError( | ||||
|                         "'%s' has no field named '%s'." | ||||
|                         % (self.__class__.__name__, field) | ||||
|                     ) | ||||
|                 if field == NON_FIELD_ERRORS: | ||||
|                     self._errors[field] = self.error_class( | ||||
|                         error_class="nonfield", renderer=self.renderer | ||||
|                     ) | ||||
|                 else: | ||||
|                     self._errors[field] = self.error_class(renderer=self.renderer) | ||||
|             self._errors[field].extend(error_list) | ||||
|             if field in self.cleaned_data: | ||||
|                 del self.cleaned_data[field] | ||||
|  | ||||
|     def has_error(self, field, code=None): | ||||
|         return field in self.errors and ( | ||||
|             code is None | ||||
|             or any(error.code == code for error in self.errors.as_data()[field]) | ||||
|         ) | ||||
|  | ||||
|     def full_clean(self): | ||||
|         """ | ||||
|         Clean all of self.data and populate self._errors and self.cleaned_data. | ||||
|         """ | ||||
|         self._errors = ErrorDict() | ||||
|         if not self.is_bound:  # Stop further processing. | ||||
|             return | ||||
|         self.cleaned_data = {} | ||||
|         # If the form is permitted to be empty, and none of the form data has | ||||
|         # changed from the initial data, short circuit any validation. | ||||
|         if self.empty_permitted and not self.has_changed(): | ||||
|             return | ||||
|  | ||||
|         self._clean_fields() | ||||
|         self._clean_form() | ||||
|         self._post_clean() | ||||
|  | ||||
|     def _clean_fields(self): | ||||
|         for name, bf in self._bound_items(): | ||||
|             field = bf.field | ||||
|             value = bf.initial if field.disabled else bf.data | ||||
|             try: | ||||
|                 if isinstance(field, FileField): | ||||
|                     value = field.clean(value, bf.initial) | ||||
|                 else: | ||||
|                     value = field.clean(value) | ||||
|                 self.cleaned_data[name] = value | ||||
|                 if hasattr(self, "clean_%s" % name): | ||||
|                     value = getattr(self, "clean_%s" % name)() | ||||
|                     self.cleaned_data[name] = value | ||||
|             except ValidationError as e: | ||||
|                 self.add_error(name, e) | ||||
|  | ||||
|     def _clean_form(self): | ||||
|         try: | ||||
|             cleaned_data = self.clean() | ||||
|         except ValidationError as e: | ||||
|             self.add_error(None, e) | ||||
|         else: | ||||
|             if cleaned_data is not None: | ||||
|                 self.cleaned_data = cleaned_data | ||||
|  | ||||
|     def _post_clean(self): | ||||
|         """ | ||||
|         An internal hook for performing additional cleaning after form cleaning | ||||
|         is complete. Used for model validation in model forms. | ||||
|         """ | ||||
|         pass | ||||
|  | ||||
|     def clean(self): | ||||
|         """ | ||||
|         Hook for doing any extra form-wide cleaning after Field.clean() has been | ||||
|         called on every field. Any ValidationError raised by this method will | ||||
|         not be associated with a particular field; it will have a special-case | ||||
|         association with the field named '__all__'. | ||||
|         """ | ||||
|         return self.cleaned_data | ||||
|  | ||||
|     def has_changed(self): | ||||
|         """Return True if data differs from initial.""" | ||||
|         return bool(self.changed_data) | ||||
|  | ||||
|     @cached_property | ||||
|     def changed_data(self): | ||||
|         return [name for name, bf in self._bound_items() if bf._has_changed()] | ||||
|  | ||||
|     @property | ||||
|     def media(self): | ||||
|         """Return all media required to render the widgets on this form.""" | ||||
|         media = Media() | ||||
|         for field in self.fields.values(): | ||||
|             media += field.widget.media | ||||
|         return media | ||||
|  | ||||
|     def is_multipart(self): | ||||
|         """ | ||||
|         Return True if the form needs to be multipart-encoded, i.e. it has | ||||
|         FileInput, or False otherwise. | ||||
|         """ | ||||
|         return any(field.widget.needs_multipart_form for field in self.fields.values()) | ||||
|  | ||||
|     def hidden_fields(self): | ||||
|         """ | ||||
|         Return a list of all the BoundField objects that are hidden fields. | ||||
|         Useful for manual form layout in templates. | ||||
|         """ | ||||
|         return [field for field in self if field.is_hidden] | ||||
|  | ||||
|     def visible_fields(self): | ||||
|         """ | ||||
|         Return a list of BoundField objects that aren't hidden fields. | ||||
|         The opposite of the hidden_fields() method. | ||||
|         """ | ||||
|         return [field for field in self if not field.is_hidden] | ||||
|  | ||||
|     def get_initial_for_field(self, field, field_name): | ||||
|         """ | ||||
|         Return initial data for field on form. Use initial data from the form | ||||
|         or the field, in that order. Evaluate callable values. | ||||
|         """ | ||||
|         value = self.initial.get(field_name, field.initial) | ||||
|         if callable(value): | ||||
|             value = value() | ||||
|         # If this is an auto-generated default date, nix the microseconds | ||||
|         # for standardized handling. See #22502. | ||||
|         if ( | ||||
|             isinstance(value, (datetime.datetime, datetime.time)) | ||||
|             and not field.widget.supports_microseconds | ||||
|         ): | ||||
|             value = value.replace(microsecond=0) | ||||
|         return value | ||||
|  | ||||
|  | ||||
| class Form(BaseForm, metaclass=DeclarativeFieldsMetaclass): | ||||
|     "A collection of Fields, plus their associated data." | ||||
|     # This is a separate class from BaseForm in order to abstract the way | ||||
|     # self.fields is specified. This class (Form) is the one that does the | ||||
|     # fancy metaclass stuff purely for the semantic sugar -- it allows one | ||||
|     # to define a form using declarative syntax. | ||||
|     # BaseForm itself has no way of designating self.fields. | ||||
							
								
								
									
										579
									
								
								srcs/.venv/lib/python3.11/site-packages/django/forms/formsets.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										579
									
								
								srcs/.venv/lib/python3.11/site-packages/django/forms/formsets.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,579 @@ | ||||
| from django.core.exceptions import ValidationError | ||||
| from django.forms import Form | ||||
| from django.forms.fields import BooleanField, IntegerField | ||||
| from django.forms.renderers import get_default_renderer | ||||
| from django.forms.utils import ErrorList, RenderableFormMixin | ||||
| from django.forms.widgets import CheckboxInput, HiddenInput, NumberInput | ||||
| from django.utils.functional import cached_property | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from django.utils.translation import ngettext_lazy | ||||
|  | ||||
| __all__ = ("BaseFormSet", "formset_factory", "all_valid") | ||||
|  | ||||
| # special field names | ||||
| TOTAL_FORM_COUNT = "TOTAL_FORMS" | ||||
| INITIAL_FORM_COUNT = "INITIAL_FORMS" | ||||
| MIN_NUM_FORM_COUNT = "MIN_NUM_FORMS" | ||||
| MAX_NUM_FORM_COUNT = "MAX_NUM_FORMS" | ||||
| ORDERING_FIELD_NAME = "ORDER" | ||||
| DELETION_FIELD_NAME = "DELETE" | ||||
|  | ||||
| # default minimum number of forms in a formset | ||||
| DEFAULT_MIN_NUM = 0 | ||||
|  | ||||
| # default maximum number of forms in a formset, to prevent memory exhaustion | ||||
| DEFAULT_MAX_NUM = 1000 | ||||
|  | ||||
|  | ||||
| class ManagementForm(Form): | ||||
|     """ | ||||
|     Keep track of how many form instances are displayed on the page. If adding | ||||
|     new forms via JavaScript, you should increment the count field of this form | ||||
|     as well. | ||||
|     """ | ||||
|  | ||||
|     template_name = "django/forms/div.html"  # RemovedInDjango50Warning. | ||||
|  | ||||
|     TOTAL_FORMS = IntegerField(widget=HiddenInput) | ||||
|     INITIAL_FORMS = IntegerField(widget=HiddenInput) | ||||
|     # MIN_NUM_FORM_COUNT and MAX_NUM_FORM_COUNT are output with the rest of the | ||||
|     # management form, but only for the convenience of client-side code. The | ||||
|     # POST value of them returned from the client is not checked. | ||||
|     MIN_NUM_FORMS = IntegerField(required=False, widget=HiddenInput) | ||||
|     MAX_NUM_FORMS = IntegerField(required=False, widget=HiddenInput) | ||||
|  | ||||
|     def clean(self): | ||||
|         cleaned_data = super().clean() | ||||
|         # When the management form is invalid, we don't know how many forms | ||||
|         # were submitted. | ||||
|         cleaned_data.setdefault(TOTAL_FORM_COUNT, 0) | ||||
|         cleaned_data.setdefault(INITIAL_FORM_COUNT, 0) | ||||
|         return cleaned_data | ||||
|  | ||||
|  | ||||
| class BaseFormSet(RenderableFormMixin): | ||||
|     """ | ||||
|     A collection of instances of the same Form class. | ||||
|     """ | ||||
|  | ||||
|     deletion_widget = CheckboxInput | ||||
|     ordering_widget = NumberInput | ||||
|     default_error_messages = { | ||||
|         "missing_management_form": _( | ||||
|             "ManagementForm data is missing or has been tampered with. Missing fields: " | ||||
|             "%(field_names)s. You may need to file a bug report if the issue persists." | ||||
|         ), | ||||
|         "too_many_forms": ngettext_lazy( | ||||
|             "Please submit at most %(num)d form.", | ||||
|             "Please submit at most %(num)d forms.", | ||||
|             "num", | ||||
|         ), | ||||
|         "too_few_forms": ngettext_lazy( | ||||
|             "Please submit at least %(num)d form.", | ||||
|             "Please submit at least %(num)d forms.", | ||||
|             "num", | ||||
|         ), | ||||
|     } | ||||
|  | ||||
|     template_name_div = "django/forms/formsets/div.html" | ||||
|     template_name_p = "django/forms/formsets/p.html" | ||||
|     template_name_table = "django/forms/formsets/table.html" | ||||
|     template_name_ul = "django/forms/formsets/ul.html" | ||||
|  | ||||
|     def __init__( | ||||
|         self, | ||||
|         data=None, | ||||
|         files=None, | ||||
|         auto_id="id_%s", | ||||
|         prefix=None, | ||||
|         initial=None, | ||||
|         error_class=ErrorList, | ||||
|         form_kwargs=None, | ||||
|         error_messages=None, | ||||
|     ): | ||||
|         self.is_bound = data is not None or files is not None | ||||
|         self.prefix = prefix or self.get_default_prefix() | ||||
|         self.auto_id = auto_id | ||||
|         self.data = data or {} | ||||
|         self.files = files or {} | ||||
|         self.initial = initial | ||||
|         self.form_kwargs = form_kwargs or {} | ||||
|         self.error_class = error_class | ||||
|         self._errors = None | ||||
|         self._non_form_errors = None | ||||
|  | ||||
|         messages = {} | ||||
|         for cls in reversed(type(self).__mro__): | ||||
|             messages.update(getattr(cls, "default_error_messages", {})) | ||||
|         if error_messages is not None: | ||||
|             messages.update(error_messages) | ||||
|         self.error_messages = messages | ||||
|  | ||||
|     def __iter__(self): | ||||
|         """Yield the forms in the order they should be rendered.""" | ||||
|         return iter(self.forms) | ||||
|  | ||||
|     def __getitem__(self, index): | ||||
|         """Return the form at the given index, based on the rendering order.""" | ||||
|         return self.forms[index] | ||||
|  | ||||
|     def __len__(self): | ||||
|         return len(self.forms) | ||||
|  | ||||
|     def __bool__(self): | ||||
|         """ | ||||
|         Return True since all formsets have a management form which is not | ||||
|         included in the length. | ||||
|         """ | ||||
|         return True | ||||
|  | ||||
|     def __repr__(self): | ||||
|         if self._errors is None: | ||||
|             is_valid = "Unknown" | ||||
|         else: | ||||
|             is_valid = ( | ||||
|                 self.is_bound | ||||
|                 and not self._non_form_errors | ||||
|                 and not any(form_errors for form_errors in self._errors) | ||||
|             ) | ||||
|         return "<%s: bound=%s valid=%s total_forms=%s>" % ( | ||||
|             self.__class__.__qualname__, | ||||
|             self.is_bound, | ||||
|             is_valid, | ||||
|             self.total_form_count(), | ||||
|         ) | ||||
|  | ||||
|     @cached_property | ||||
|     def management_form(self): | ||||
|         """Return the ManagementForm instance for this FormSet.""" | ||||
|         if self.is_bound: | ||||
|             form = ManagementForm( | ||||
|                 self.data, | ||||
|                 auto_id=self.auto_id, | ||||
|                 prefix=self.prefix, | ||||
|                 renderer=self.renderer, | ||||
|             ) | ||||
|             form.full_clean() | ||||
|         else: | ||||
|             form = ManagementForm( | ||||
|                 auto_id=self.auto_id, | ||||
|                 prefix=self.prefix, | ||||
|                 initial={ | ||||
|                     TOTAL_FORM_COUNT: self.total_form_count(), | ||||
|                     INITIAL_FORM_COUNT: self.initial_form_count(), | ||||
|                     MIN_NUM_FORM_COUNT: self.min_num, | ||||
|                     MAX_NUM_FORM_COUNT: self.max_num, | ||||
|                 }, | ||||
|                 renderer=self.renderer, | ||||
|             ) | ||||
|         return form | ||||
|  | ||||
|     def total_form_count(self): | ||||
|         """Return the total number of forms in this FormSet.""" | ||||
|         if self.is_bound: | ||||
|             # return absolute_max if it is lower than the actual total form | ||||
|             # count in the data; this is DoS protection to prevent clients | ||||
|             # from forcing the server to instantiate arbitrary numbers of | ||||
|             # forms | ||||
|             return min( | ||||
|                 self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max | ||||
|             ) | ||||
|         else: | ||||
|             initial_forms = self.initial_form_count() | ||||
|             total_forms = max(initial_forms, self.min_num) + self.extra | ||||
|             # Allow all existing related objects/inlines to be displayed, | ||||
|             # but don't allow extra beyond max_num. | ||||
|             if initial_forms > self.max_num >= 0: | ||||
|                 total_forms = initial_forms | ||||
|             elif total_forms > self.max_num >= 0: | ||||
|                 total_forms = self.max_num | ||||
|         return total_forms | ||||
|  | ||||
|     def initial_form_count(self): | ||||
|         """Return the number of forms that are required in this FormSet.""" | ||||
|         if self.is_bound: | ||||
|             return self.management_form.cleaned_data[INITIAL_FORM_COUNT] | ||||
|         else: | ||||
|             # Use the length of the initial data if it's there, 0 otherwise. | ||||
|             initial_forms = len(self.initial) if self.initial else 0 | ||||
|         return initial_forms | ||||
|  | ||||
|     @cached_property | ||||
|     def forms(self): | ||||
|         """Instantiate forms at first property access.""" | ||||
|         # DoS protection is included in total_form_count() | ||||
|         return [ | ||||
|             self._construct_form(i, **self.get_form_kwargs(i)) | ||||
|             for i in range(self.total_form_count()) | ||||
|         ] | ||||
|  | ||||
|     def get_form_kwargs(self, index): | ||||
|         """ | ||||
|         Return additional keyword arguments for each individual formset form. | ||||
|  | ||||
|         index will be None if the form being constructed is a new empty | ||||
|         form. | ||||
|         """ | ||||
|         return self.form_kwargs.copy() | ||||
|  | ||||
|     def _construct_form(self, i, **kwargs): | ||||
|         """Instantiate and return the i-th form instance in a formset.""" | ||||
|         defaults = { | ||||
|             "auto_id": self.auto_id, | ||||
|             "prefix": self.add_prefix(i), | ||||
|             "error_class": self.error_class, | ||||
|             # Don't render the HTML 'required' attribute as it may cause | ||||
|             # incorrect validation for extra, optional, and deleted | ||||
|             # forms in the formset. | ||||
|             "use_required_attribute": False, | ||||
|             "renderer": self.renderer, | ||||
|         } | ||||
|         if self.is_bound: | ||||
|             defaults["data"] = self.data | ||||
|             defaults["files"] = self.files | ||||
|         if self.initial and "initial" not in kwargs: | ||||
|             try: | ||||
|                 defaults["initial"] = self.initial[i] | ||||
|             except IndexError: | ||||
|                 pass | ||||
|         # Allow extra forms to be empty, unless they're part of | ||||
|         # the minimum forms. | ||||
|         if i >= self.initial_form_count() and i >= self.min_num: | ||||
|             defaults["empty_permitted"] = True | ||||
|         defaults.update(kwargs) | ||||
|         form = self.form(**defaults) | ||||
|         self.add_fields(form, i) | ||||
|         return form | ||||
|  | ||||
|     @property | ||||
|     def initial_forms(self): | ||||
|         """Return a list of all the initial forms in this formset.""" | ||||
|         return self.forms[: self.initial_form_count()] | ||||
|  | ||||
|     @property | ||||
|     def extra_forms(self): | ||||
|         """Return a list of all the extra forms in this formset.""" | ||||
|         return self.forms[self.initial_form_count() :] | ||||
|  | ||||
|     @property | ||||
|     def empty_form(self): | ||||
|         form_kwargs = { | ||||
|             **self.get_form_kwargs(None), | ||||
|             "auto_id": self.auto_id, | ||||
|             "prefix": self.add_prefix("__prefix__"), | ||||
|             "empty_permitted": True, | ||||
|             "use_required_attribute": False, | ||||
|             "renderer": self.renderer, | ||||
|         } | ||||
|         form = self.form(**form_kwargs) | ||||
|         self.add_fields(form, None) | ||||
|         return form | ||||
|  | ||||
|     @property | ||||
|     def cleaned_data(self): | ||||
|         """ | ||||
|         Return a list of form.cleaned_data dicts for every form in self.forms. | ||||
|         """ | ||||
|         if not self.is_valid(): | ||||
|             raise AttributeError( | ||||
|                 "'%s' object has no attribute 'cleaned_data'" % self.__class__.__name__ | ||||
|             ) | ||||
|         return [form.cleaned_data for form in self.forms] | ||||
|  | ||||
|     @property | ||||
|     def deleted_forms(self): | ||||
|         """Return a list of forms that have been marked for deletion.""" | ||||
|         if not self.is_valid() or not self.can_delete: | ||||
|             return [] | ||||
|         # construct _deleted_form_indexes which is just a list of form indexes | ||||
|         # that have had their deletion widget set to True | ||||
|         if not hasattr(self, "_deleted_form_indexes"): | ||||
|             self._deleted_form_indexes = [] | ||||
|             for i, form in enumerate(self.forms): | ||||
|                 # if this is an extra form and hasn't changed, don't consider it | ||||
|                 if i >= self.initial_form_count() and not form.has_changed(): | ||||
|                     continue | ||||
|                 if self._should_delete_form(form): | ||||
|                     self._deleted_form_indexes.append(i) | ||||
|         return [self.forms[i] for i in self._deleted_form_indexes] | ||||
|  | ||||
|     @property | ||||
|     def ordered_forms(self): | ||||
|         """ | ||||
|         Return a list of form in the order specified by the incoming data. | ||||
|         Raise an AttributeError if ordering is not allowed. | ||||
|         """ | ||||
|         if not self.is_valid() or not self.can_order: | ||||
|             raise AttributeError( | ||||
|                 "'%s' object has no attribute 'ordered_forms'" % self.__class__.__name__ | ||||
|             ) | ||||
|         # Construct _ordering, which is a list of (form_index, order_field_value) | ||||
|         # tuples. After constructing this list, we'll sort it by order_field_value | ||||
|         # so we have a way to get to the form indexes in the order specified | ||||
|         # by the form data. | ||||
|         if not hasattr(self, "_ordering"): | ||||
|             self._ordering = [] | ||||
|             for i, form in enumerate(self.forms): | ||||
|                 # if this is an extra form and hasn't changed, don't consider it | ||||
|                 if i >= self.initial_form_count() and not form.has_changed(): | ||||
|                     continue | ||||
|                 # don't add data marked for deletion to self.ordered_data | ||||
|                 if self.can_delete and self._should_delete_form(form): | ||||
|                     continue | ||||
|                 self._ordering.append((i, form.cleaned_data[ORDERING_FIELD_NAME])) | ||||
|             # After we're done populating self._ordering, sort it. | ||||
|             # A sort function to order things numerically ascending, but | ||||
|             # None should be sorted below anything else. Allowing None as | ||||
|             # a comparison value makes it so we can leave ordering fields | ||||
|             # blank. | ||||
|  | ||||
|             def compare_ordering_key(k): | ||||
|                 if k[1] is None: | ||||
|                     return (1, 0)  # +infinity, larger than any number | ||||
|                 return (0, k[1]) | ||||
|  | ||||
|             self._ordering.sort(key=compare_ordering_key) | ||||
|         # Return a list of form.cleaned_data dicts in the order specified by | ||||
|         # the form data. | ||||
|         return [self.forms[i[0]] for i in self._ordering] | ||||
|  | ||||
|     @classmethod | ||||
|     def get_default_prefix(cls): | ||||
|         return "form" | ||||
|  | ||||
|     @classmethod | ||||
|     def get_deletion_widget(cls): | ||||
|         return cls.deletion_widget | ||||
|  | ||||
|     @classmethod | ||||
|     def get_ordering_widget(cls): | ||||
|         return cls.ordering_widget | ||||
|  | ||||
|     def non_form_errors(self): | ||||
|         """ | ||||
|         Return an ErrorList of errors that aren't associated with a particular | ||||
|         form -- i.e., from formset.clean(). Return an empty ErrorList if there | ||||
|         are none. | ||||
|         """ | ||||
|         if self._non_form_errors is None: | ||||
|             self.full_clean() | ||||
|         return self._non_form_errors | ||||
|  | ||||
|     @property | ||||
|     def errors(self): | ||||
|         """Return a list of form.errors for every form in self.forms.""" | ||||
|         if self._errors is None: | ||||
|             self.full_clean() | ||||
|         return self._errors | ||||
|  | ||||
|     def total_error_count(self): | ||||
|         """Return the number of errors across all forms in the formset.""" | ||||
|         return len(self.non_form_errors()) + sum( | ||||
|             len(form_errors) for form_errors in self.errors | ||||
|         ) | ||||
|  | ||||
|     def _should_delete_form(self, form): | ||||
|         """Return whether or not the form was marked for deletion.""" | ||||
|         return form.cleaned_data.get(DELETION_FIELD_NAME, False) | ||||
|  | ||||
|     def is_valid(self): | ||||
|         """Return True if every form in self.forms is valid.""" | ||||
|         if not self.is_bound: | ||||
|             return False | ||||
|         # Accessing errors triggers a full clean the first time only. | ||||
|         self.errors | ||||
|         # List comprehension ensures is_valid() is called for all forms. | ||||
|         # Forms due to be deleted shouldn't cause the formset to be invalid. | ||||
|         forms_valid = all( | ||||
|             [ | ||||
|                 form.is_valid() | ||||
|                 for form in self.forms | ||||
|                 if not (self.can_delete and self._should_delete_form(form)) | ||||
|             ] | ||||
|         ) | ||||
|         return forms_valid and not self.non_form_errors() | ||||
|  | ||||
|     def full_clean(self): | ||||
|         """ | ||||
|         Clean all of self.data and populate self._errors and | ||||
|         self._non_form_errors. | ||||
|         """ | ||||
|         self._errors = [] | ||||
|         self._non_form_errors = self.error_class( | ||||
|             error_class="nonform", renderer=self.renderer | ||||
|         ) | ||||
|         empty_forms_count = 0 | ||||
|  | ||||
|         if not self.is_bound:  # Stop further processing. | ||||
|             return | ||||
|  | ||||
|         if not self.management_form.is_valid(): | ||||
|             error = ValidationError( | ||||
|                 self.error_messages["missing_management_form"], | ||||
|                 params={ | ||||
|                     "field_names": ", ".join( | ||||
|                         self.management_form.add_prefix(field_name) | ||||
|                         for field_name in self.management_form.errors | ||||
|                     ), | ||||
|                 }, | ||||
|                 code="missing_management_form", | ||||
|             ) | ||||
|             self._non_form_errors.append(error) | ||||
|  | ||||
|         for i, form in enumerate(self.forms): | ||||
|             # Empty forms are unchanged forms beyond those with initial data. | ||||
|             if not form.has_changed() and i >= self.initial_form_count(): | ||||
|                 empty_forms_count += 1 | ||||
|             # Accessing errors calls full_clean() if necessary. | ||||
|             # _should_delete_form() requires cleaned_data. | ||||
|             form_errors = form.errors | ||||
|             if self.can_delete and self._should_delete_form(form): | ||||
|                 continue | ||||
|             self._errors.append(form_errors) | ||||
|         try: | ||||
|             if ( | ||||
|                 self.validate_max | ||||
|                 and self.total_form_count() - len(self.deleted_forms) > self.max_num | ||||
|             ) or self.management_form.cleaned_data[ | ||||
|                 TOTAL_FORM_COUNT | ||||
|             ] > self.absolute_max: | ||||
|                 raise ValidationError( | ||||
|                     self.error_messages["too_many_forms"] % {"num": self.max_num}, | ||||
|                     code="too_many_forms", | ||||
|                 ) | ||||
|             if ( | ||||
|                 self.validate_min | ||||
|                 and self.total_form_count() | ||||
|                 - len(self.deleted_forms) | ||||
|                 - empty_forms_count | ||||
|                 < self.min_num | ||||
|             ): | ||||
|                 raise ValidationError( | ||||
|                     self.error_messages["too_few_forms"] % {"num": self.min_num}, | ||||
|                     code="too_few_forms", | ||||
|                 ) | ||||
|             # Give self.clean() a chance to do cross-form validation. | ||||
|             self.clean() | ||||
|         except ValidationError as e: | ||||
|             self._non_form_errors = self.error_class( | ||||
|                 e.error_list, | ||||
|                 error_class="nonform", | ||||
|                 renderer=self.renderer, | ||||
|             ) | ||||
|  | ||||
|     def clean(self): | ||||
|         """ | ||||
|         Hook for doing any extra formset-wide cleaning after Form.clean() has | ||||
|         been called on every form. Any ValidationError raised by this method | ||||
|         will not be associated with a particular form; it will be accessible | ||||
|         via formset.non_form_errors() | ||||
|         """ | ||||
|         pass | ||||
|  | ||||
|     def has_changed(self): | ||||
|         """Return True if data in any form differs from initial.""" | ||||
|         return any(form.has_changed() for form in self) | ||||
|  | ||||
|     def add_fields(self, form, index): | ||||
|         """A hook for adding extra fields on to each form instance.""" | ||||
|         initial_form_count = self.initial_form_count() | ||||
|         if self.can_order: | ||||
|             # Only pre-fill the ordering field for initial forms. | ||||
|             if index is not None and index < initial_form_count: | ||||
|                 form.fields[ORDERING_FIELD_NAME] = IntegerField( | ||||
|                     label=_("Order"), | ||||
|                     initial=index + 1, | ||||
|                     required=False, | ||||
|                     widget=self.get_ordering_widget(), | ||||
|                 ) | ||||
|             else: | ||||
|                 form.fields[ORDERING_FIELD_NAME] = IntegerField( | ||||
|                     label=_("Order"), | ||||
|                     required=False, | ||||
|                     widget=self.get_ordering_widget(), | ||||
|                 ) | ||||
|         if self.can_delete and ( | ||||
|             self.can_delete_extra or (index is not None and index < initial_form_count) | ||||
|         ): | ||||
|             form.fields[DELETION_FIELD_NAME] = BooleanField( | ||||
|                 label=_("Delete"), | ||||
|                 required=False, | ||||
|                 widget=self.get_deletion_widget(), | ||||
|             ) | ||||
|  | ||||
|     def add_prefix(self, index): | ||||
|         return "%s-%s" % (self.prefix, index) | ||||
|  | ||||
|     def is_multipart(self): | ||||
|         """ | ||||
|         Return True if the formset needs to be multipart, i.e. it | ||||
|         has FileInput, or False otherwise. | ||||
|         """ | ||||
|         if self.forms: | ||||
|             return self.forms[0].is_multipart() | ||||
|         else: | ||||
|             return self.empty_form.is_multipart() | ||||
|  | ||||
|     @property | ||||
|     def media(self): | ||||
|         # All the forms on a FormSet are the same, so you only need to | ||||
|         # interrogate the first form for media. | ||||
|         if self.forms: | ||||
|             return self.forms[0].media | ||||
|         else: | ||||
|             return self.empty_form.media | ||||
|  | ||||
|     @property | ||||
|     def template_name(self): | ||||
|         return self.renderer.formset_template_name | ||||
|  | ||||
|     def get_context(self): | ||||
|         return {"formset": self} | ||||
|  | ||||
|  | ||||
| def formset_factory( | ||||
|     form, | ||||
|     formset=BaseFormSet, | ||||
|     extra=1, | ||||
|     can_order=False, | ||||
|     can_delete=False, | ||||
|     max_num=None, | ||||
|     validate_max=False, | ||||
|     min_num=None, | ||||
|     validate_min=False, | ||||
|     absolute_max=None, | ||||
|     can_delete_extra=True, | ||||
|     renderer=None, | ||||
| ): | ||||
|     """Return a FormSet for the given form class.""" | ||||
|     if min_num is None: | ||||
|         min_num = DEFAULT_MIN_NUM | ||||
|     if max_num is None: | ||||
|         max_num = DEFAULT_MAX_NUM | ||||
|     # absolute_max is a hard limit on forms instantiated, to prevent | ||||
|     # memory-exhaustion attacks. Default to max_num + DEFAULT_MAX_NUM | ||||
|     # (which is 2 * DEFAULT_MAX_NUM if max_num is None in the first place). | ||||
|     if absolute_max is None: | ||||
|         absolute_max = max_num + DEFAULT_MAX_NUM | ||||
|     if max_num > absolute_max: | ||||
|         raise ValueError("'absolute_max' must be greater or equal to 'max_num'.") | ||||
|     attrs = { | ||||
|         "form": form, | ||||
|         "extra": extra, | ||||
|         "can_order": can_order, | ||||
|         "can_delete": can_delete, | ||||
|         "can_delete_extra": can_delete_extra, | ||||
|         "min_num": min_num, | ||||
|         "max_num": max_num, | ||||
|         "absolute_max": absolute_max, | ||||
|         "validate_min": validate_min, | ||||
|         "validate_max": validate_max, | ||||
|         "renderer": renderer or get_default_renderer(), | ||||
|     } | ||||
|     return type(form.__name__ + "FormSet", (formset,), attrs) | ||||
|  | ||||
|  | ||||
| def all_valid(formsets): | ||||
|     """Validate every formset and return True if all are valid.""" | ||||
|     # List comprehension ensures is_valid() is called for all formsets. | ||||
|     return all([formset.is_valid() for formset in formsets]) | ||||
| @ -0,0 +1 @@ | ||||
| {% for name, value in attrs.items() %}{% if value is not sameas False %} {{ name }}{% if value is not sameas True %}="{{ value }}"{% endif %}{% endif %}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/table.html" %} | ||||
| @ -0,0 +1,24 @@ | ||||
| {{ errors }} | ||||
| {% if errors and not fields %} | ||||
|   <div>{% for field in hidden_fields %}{{ field }}{% endfor %}</div> | ||||
| {% endif %} | ||||
| {% for field, errors in fields %} | ||||
|   <div{% set classes = field.css_classes() %}{% if classes %} class="{{ classes }}"{% endif %}> | ||||
|     {% if field.use_fieldset %} | ||||
|       <fieldset> | ||||
|       {% if field.label %}{{ field.legend_tag() }}{% endif %} | ||||
|     {% else %} | ||||
|       {% if field.label %}{{ field.label_tag() }}{% endif %} | ||||
|     {% endif %} | ||||
|     {% if field.help_text %}<div class="helptext">{{ field.help_text|safe }}</div>{% endif %} | ||||
|     {{ errors }} | ||||
|     {{ field }} | ||||
|     {% if field.use_fieldset %}</fieldset>{% endif %} | ||||
|     {% if loop.last %} | ||||
|       {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|     {% endif %} | ||||
| </div> | ||||
| {% endfor %} | ||||
| {% if not fields and not errors %} | ||||
|   {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
| {% endif %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/errors/dict/ul.html" %} | ||||
| @ -0,0 +1,3 @@ | ||||
| {% for field, errors in errors %}* {{ field }} | ||||
| {% for error in errors %}  * {{ error }} | ||||
| {% endfor %}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% if errors %}<ul class="{{ error_class }}">{% for field, error in errors %}<li>{{ field }}{{ error }}</li>{% endfor %}</ul>{% endif %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/errors/list/ul.html" %} | ||||
| @ -0,0 +1,2 @@ | ||||
| {% for error in errors %}* {{ error }} | ||||
| {% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% if errors %}<ul class="{{ error_class }}">{% for error in errors %}<li>{{ error }}</li>{% endfor %}</ul>{% endif %} | ||||
| @ -0,0 +1 @@ | ||||
| {{ formset.management_form }}{% for form in formset %}{{ form }}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {{ formset.management_form }}{% for form in formset %}{{ form.as_div() }}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {{ formset.management_form }}{% for form in formset %}{{ form.as_p() }}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {{ formset.management_form }}{% for form in formset %}{{ form.as_table() }}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {{ formset.management_form }}{% for form in formset %}{{ form.as_ul() }}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% if use_tag %}<{{ tag }}{% if attrs %}{% include 'django/forms/attrs.html' %}{% endif %}>{{ label }}</{{ tag }}>{% else %}{{ label }}{% endif %} | ||||
| @ -0,0 +1,20 @@ | ||||
| {{ errors }} | ||||
| {% if errors and not fields %} | ||||
|   <p>{% for field in hidden_fields %}{{ field }}{% endfor %}</p> | ||||
| {% endif %} | ||||
| {% for field, errors in fields %} | ||||
|   {{ errors }} | ||||
|   <p{% set classes = field.css_classes() %}{% if classes %} class="{{ classes }}"{% endif %}> | ||||
|     {% if field.label %}{{ field.label_tag() }}{% endif %} | ||||
|     {{ field }} | ||||
|     {% if field.help_text %} | ||||
|       <span class="helptext">{{ field.help_text|safe }}</span> | ||||
|     {% endif %} | ||||
|     {% if loop.last %} | ||||
|       {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|     {% endif %} | ||||
|   </p> | ||||
| {% endfor %} | ||||
| {% if not fields and not errors %} | ||||
|   {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
| {% endif %} | ||||
| @ -0,0 +1,29 @@ | ||||
| {% if errors %} | ||||
|   <tr> | ||||
|     <td colspan="2"> | ||||
|       {{ errors }} | ||||
|       {% if not fields %} | ||||
|         {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|       {% endif %} | ||||
|     </td> | ||||
|   </tr> | ||||
| {% endif %} | ||||
| {% for field, errors in fields %} | ||||
|   <tr{% set classes = field.css_classes() %}{% if classes %} class="{{ classes }}"{% endif %}> | ||||
|     <th>{% if field.label %}{{ field.label_tag() }}{% endif %}</th> | ||||
|     <td> | ||||
|       {{ errors }} | ||||
|       {{ field }} | ||||
|       {% if field.help_text %} | ||||
|         <br> | ||||
|         <span class="helptext">{{ field.help_text|safe }}</span> | ||||
|       {% endif %} | ||||
|       {% if loop.last %} | ||||
|         {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|       {% endif %} | ||||
|     </td> | ||||
|   </tr> | ||||
| {% endfor %} | ||||
| {% if not fields and not errors %} | ||||
|   {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
| {% endif %} | ||||
| @ -0,0 +1,24 @@ | ||||
| {% if errors %} | ||||
|   <li> | ||||
|     {{ errors }} | ||||
|   {% if not fields %} | ||||
|     {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|   {% endif %} | ||||
|   </li> | ||||
| {% endif %} | ||||
| {% for field, errors in fields %} | ||||
|   <li{% set classes = field.css_classes() %}{% if classes %} class="{{ classes }}"{% endif %}> | ||||
|     {{ errors }} | ||||
|     {% if field.label %}{{ field.label_tag() }}{% endif %} | ||||
|     {{ field }} | ||||
|     {% if field.help_text %} | ||||
|       <span class="helptext">{{ field.help_text|safe }}</span> | ||||
|     {% endif %} | ||||
|     {% if loop.last %} | ||||
|       {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|     {% endif %} | ||||
|   </li> | ||||
| {% endfor %} | ||||
| {% if not fields and not errors %} | ||||
|   {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
| {% endif %} | ||||
| @ -0,0 +1 @@ | ||||
| {% for name, value in widget.attrs.items() %}{% if value is not sameas False %} {{ name }}{% if value is not sameas True %}="{{ value }}"{% endif %}{% endif %}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input_option.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/multiple_input.html" %} | ||||
| @ -0,0 +1,5 @@ | ||||
| {% if widget.is_initial %}{{ widget.initial_text }}: <a href="{{ widget.value.url }}">{{ widget.value }}</a>{% if not widget.required %} | ||||
| <input type="checkbox" name="{{ widget.checkbox_name }}" id="{{ widget.checkbox_id }}"{% if widget.attrs.disabled %} disabled{% endif %}> | ||||
| <label for="{{ widget.checkbox_id }}">{{ widget.clear_checkbox_label }}</label>{% endif %}<br> | ||||
| {{ widget.input_text }}:{% endif %} | ||||
| <input type="{{ widget.type }}" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}> | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| <input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}> | ||||
| @ -0,0 +1 @@ | ||||
| {% if widget.wrap_label %}<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.wrap_label %} {{ widget.label }}</label>{% endif %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/multiwidget.html" %} | ||||
| @ -0,0 +1,5 @@ | ||||
| {% set id = widget.attrs.id %}<div{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>{% for group, options, index in widget.optgroups %}{% if group %} | ||||
|   <div><label>{{ group }}</label>{% endif %}{% for widget in options %}<div> | ||||
|     {% include widget.template_name %}</div>{% endfor %}{% if group %} | ||||
|   </div>{% endif %}{% endfor %} | ||||
| </div> | ||||
| @ -0,0 +1 @@ | ||||
| {% for widget in widget.subwidgets -%}{% include widget.template_name %}{%- endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/multiple_input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input_option.html" %} | ||||
| @ -0,0 +1,5 @@ | ||||
| <select name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>{% for group_name, group_choices, group_index in widget.optgroups %}{% if group_name %} | ||||
|   <optgroup label="{{ group_name }}">{% endif %}{% for widget in group_choices %} | ||||
|   {% include widget.template_name %}{% endfor %}{% if group_name %} | ||||
|   </optgroup>{% endif %}{% endfor %} | ||||
| </select> | ||||
| @ -0,0 +1 @@ | ||||
| {% include 'django/forms/widgets/multiwidget.html' %} | ||||
| @ -0,0 +1 @@ | ||||
| <option value="{{ widget.value }}"{% include "django/forms/widgets/attrs.html" %}>{{ widget.label }}</option> | ||||
| @ -0,0 +1 @@ | ||||
| {% include 'django/forms/widgets/multiwidget.html' %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include 'django/forms/widgets/multiwidget.html' %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1,2 @@ | ||||
| <textarea name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}> | ||||
| {% if widget.value %}{{ widget.value }}{% endif %}</textarea> | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
							
								
								
									
										1660
									
								
								srcs/.venv/lib/python3.11/site-packages/django/forms/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1660
									
								
								srcs/.venv/lib/python3.11/site-packages/django/forms/models.py
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -0,0 +1,102 @@ | ||||
| import functools | ||||
| from pathlib import Path | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.template.backends.django import DjangoTemplates | ||||
| from django.template.loader import get_template | ||||
| from django.utils.functional import cached_property | ||||
| from django.utils.module_loading import import_string | ||||
|  | ||||
|  | ||||
| @functools.lru_cache | ||||
| def get_default_renderer(): | ||||
|     renderer_class = import_string(settings.FORM_RENDERER) | ||||
|     return renderer_class() | ||||
|  | ||||
|  | ||||
| class BaseRenderer: | ||||
|     # RemovedInDjango50Warning: When the deprecation ends, replace with | ||||
|     # form_template_name = "django/forms/div.html" | ||||
|     # formset_template_name = "django/forms/formsets/div.html" | ||||
|     form_template_name = "django/forms/default.html" | ||||
|     formset_template_name = "django/forms/formsets/default.html" | ||||
|  | ||||
|     def get_template(self, template_name): | ||||
|         raise NotImplementedError("subclasses must implement get_template()") | ||||
|  | ||||
|     def render(self, template_name, context, request=None): | ||||
|         template = self.get_template(template_name) | ||||
|         return template.render(context, request=request).strip() | ||||
|  | ||||
|  | ||||
| class EngineMixin: | ||||
|     def get_template(self, template_name): | ||||
|         return self.engine.get_template(template_name) | ||||
|  | ||||
|     @cached_property | ||||
|     def engine(self): | ||||
|         return self.backend( | ||||
|             { | ||||
|                 "APP_DIRS": True, | ||||
|                 "DIRS": [Path(__file__).parent / self.backend.app_dirname], | ||||
|                 "NAME": "djangoforms", | ||||
|                 "OPTIONS": {}, | ||||
|             } | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class DjangoTemplates(EngineMixin, BaseRenderer): | ||||
|     """ | ||||
|     Load Django templates from the built-in widget templates in | ||||
|     django/forms/templates and from apps' 'templates' directory. | ||||
|     """ | ||||
|  | ||||
|     backend = DjangoTemplates | ||||
|  | ||||
|  | ||||
| class Jinja2(EngineMixin, BaseRenderer): | ||||
|     """ | ||||
|     Load Jinja2 templates from the built-in widget templates in | ||||
|     django/forms/jinja2 and from apps' 'jinja2' directory. | ||||
|     """ | ||||
|  | ||||
|     @cached_property | ||||
|     def backend(self): | ||||
|         from django.template.backends.jinja2 import Jinja2 | ||||
|  | ||||
|         return Jinja2 | ||||
|  | ||||
|  | ||||
| class DjangoDivFormRenderer(DjangoTemplates): | ||||
|     """ | ||||
|     Load Django templates from django/forms/templates and from apps' | ||||
|     'templates' directory and use the 'div.html' template to render forms and | ||||
|     formsets. | ||||
|     """ | ||||
|  | ||||
|     # RemovedInDjango50Warning Deprecate this class in 5.0 and remove in 6.0. | ||||
|  | ||||
|     form_template_name = "django/forms/div.html" | ||||
|     formset_template_name = "django/forms/formsets/div.html" | ||||
|  | ||||
|  | ||||
| class Jinja2DivFormRenderer(Jinja2): | ||||
|     """ | ||||
|     Load Jinja2 templates from the built-in widget templates in | ||||
|     django/forms/jinja2 and from apps' 'jinja2' directory. | ||||
|     """ | ||||
|  | ||||
|     # RemovedInDjango50Warning Deprecate this class in 5.0 and remove in 6.0. | ||||
|  | ||||
|     form_template_name = "django/forms/div.html" | ||||
|     formset_template_name = "django/forms/formsets/div.html" | ||||
|  | ||||
|  | ||||
| class TemplatesSetting(BaseRenderer): | ||||
|     """ | ||||
|     Load templates using template.loader.get_template() which is configured | ||||
|     based on settings.TEMPLATES. | ||||
|     """ | ||||
|  | ||||
|     def get_template(self, template_name): | ||||
|         return get_template(template_name) | ||||
| @ -0,0 +1 @@ | ||||
| {% for name, value in attrs.items %}{% if value is not False %} {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/table.html" %} | ||||
| @ -0,0 +1,24 @@ | ||||
| {{ errors }} | ||||
| {% if errors and not fields %} | ||||
|   <div>{% for field in hidden_fields %}{{ field }}{% endfor %}</div> | ||||
| {% endif %} | ||||
| {% for field, errors in fields %} | ||||
|   <div{% with classes=field.css_classes %}{% if classes %} class="{{ classes }}"{% endif %}{% endwith %}> | ||||
|     {% if field.use_fieldset %} | ||||
|       <fieldset> | ||||
|       {% if field.label %}{{ field.legend_tag }}{% endif %} | ||||
|     {% else %} | ||||
|       {% if field.label %}{{ field.label_tag }}{% endif %} | ||||
|     {% endif %} | ||||
|     {% if field.help_text %}<div class="helptext">{{ field.help_text|safe }}</div>{% endif %} | ||||
|     {{ errors }} | ||||
|     {{ field }} | ||||
|     {% if field.use_fieldset %}</fieldset>{% endif %} | ||||
|     {% if forloop.last %} | ||||
|       {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|     {% endif %} | ||||
| </div> | ||||
| {% endfor %} | ||||
| {% if not fields and not errors %} | ||||
|   {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
| {% endif %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/errors/dict/ul.html" %} | ||||
| @ -0,0 +1,3 @@ | ||||
| {% for field, errors in errors %}* {{ field }} | ||||
| {% for error in errors %}  * {{ error }} | ||||
| {% endfor %}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% if errors %}<ul class="{{ error_class }}">{% for field, error in errors %}<li>{{ field }}{{ error }}</li>{% endfor %}</ul>{% endif %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/errors/list/ul.html" %} | ||||
| @ -0,0 +1,2 @@ | ||||
| {% for error in errors %}* {{ error }} | ||||
| {% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% if errors %}<ul class="{{ error_class }}">{% for error in errors %}<li>{{ error }}</li>{% endfor %}</ul>{% endif %} | ||||
| @ -0,0 +1 @@ | ||||
| {{ formset.management_form }}{% for form in formset %}{{ form }}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {{ formset.management_form }}{% for form in formset %}{{ form.as_div }}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {{ formset.management_form }}{% for form in formset %}{{ form.as_p }}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {{ formset.management_form }}{% for form in formset %}{{ form.as_table }}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {{ formset.management_form }}{% for form in formset %}{{ form.as_ul }}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% if use_tag %}<{{ tag }}{% include 'django/forms/attrs.html' %}>{{ label }}</{{ tag }}>{% else %}{{ label }}{% endif %} | ||||
| @ -0,0 +1,20 @@ | ||||
| {{ errors }} | ||||
| {% if errors and not fields %} | ||||
|   <p>{% for field in hidden_fields %}{{ field }}{% endfor %}</p> | ||||
| {% endif %} | ||||
| {% for field, errors in fields %} | ||||
|   {{ errors }} | ||||
|   <p{% with classes=field.css_classes %}{% if classes %} class="{{ classes }}"{% endif %}{% endwith %}> | ||||
|     {% if field.label %}{{ field.label_tag }}{% endif %} | ||||
|     {{ field }} | ||||
|     {% if field.help_text %} | ||||
|       <span class="helptext">{{ field.help_text|safe }}</span> | ||||
|     {% endif %} | ||||
|     {% if forloop.last %} | ||||
|       {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|     {% endif %} | ||||
|   </p> | ||||
| {% endfor %} | ||||
| {% if not fields and not errors %} | ||||
|   {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
| {% endif %} | ||||
| @ -0,0 +1,29 @@ | ||||
| {% if errors %} | ||||
|   <tr> | ||||
|     <td colspan="2"> | ||||
|       {{ errors }} | ||||
|       {% if not fields %} | ||||
|         {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|       {% endif %} | ||||
|     </td> | ||||
|   </tr> | ||||
| {% endif %} | ||||
| {% for field, errors in fields %} | ||||
|   <tr{% with classes=field.css_classes %}{% if classes %} class="{{ classes }}"{% endif %}{% endwith %}> | ||||
|     <th>{% if field.label %}{{ field.label_tag }}{% endif %}</th> | ||||
|     <td> | ||||
|       {{ errors }} | ||||
|       {{ field }} | ||||
|       {% if field.help_text %} | ||||
|         <br> | ||||
|         <span class="helptext">{{ field.help_text|safe }}</span> | ||||
|       {% endif %} | ||||
|       {% if forloop.last %} | ||||
|         {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|       {% endif %} | ||||
|     </td> | ||||
|   </tr> | ||||
| {% endfor %} | ||||
| {% if not fields and not errors %} | ||||
|   {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
| {% endif %} | ||||
| @ -0,0 +1,24 @@ | ||||
| {% if errors %} | ||||
|   <li> | ||||
|     {{ errors }} | ||||
|   {% if not fields %} | ||||
|     {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|   {% endif %} | ||||
|   </li> | ||||
| {% endif %} | ||||
| {% for field, errors in fields %} | ||||
|   <li{% with classes=field.css_classes %}{% if classes %} class="{{ classes }}"{% endif %}{% endwith %}> | ||||
|     {{ errors }} | ||||
|     {% if field.label %}{{ field.label_tag }}{% endif %} | ||||
|     {{ field }} | ||||
|     {% if field.help_text %} | ||||
|       <span class="helptext">{{ field.help_text|safe }}</span> | ||||
|     {% endif %} | ||||
|     {% if forloop.last %} | ||||
|       {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
|     {% endif %} | ||||
|   </li> | ||||
| {% endfor %} | ||||
| {% if not fields and not errors %} | ||||
|   {% for field in hidden_fields %}{{ field }}{% endfor %} | ||||
| {% endif %} | ||||
| @ -0,0 +1 @@ | ||||
| {% for name, value in widget.attrs.items %}{% if value is not False %} {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input_option.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/multiple_input.html" %} | ||||
| @ -0,0 +1,5 @@ | ||||
| {% if widget.is_initial %}{{ widget.initial_text }}: <a href="{{ widget.value.url }}">{{ widget.value }}</a>{% if not widget.required %} | ||||
| <input type="checkbox" name="{{ widget.checkbox_name }}" id="{{ widget.checkbox_id }}"{% if widget.attrs.disabled %} disabled{% endif %}> | ||||
| <label for="{{ widget.checkbox_id }}">{{ widget.clear_checkbox_label }}</label>{% endif %}<br> | ||||
| {{ widget.input_text }}:{% endif %} | ||||
| <input type="{{ widget.type }}" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}> | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| <input type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}> | ||||
| @ -0,0 +1 @@ | ||||
| {% if widget.wrap_label %}<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.wrap_label %} {{ widget.label }}</label>{% endif %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/multiwidget.html" %} | ||||
| @ -0,0 +1,5 @@ | ||||
| {% with id=widget.attrs.id %}<div{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>{% for group, options, index in widget.optgroups %}{% if group %} | ||||
|   <div><label>{{ group }}</label>{% endif %}{% for option in options %}<div> | ||||
|     {% include option.template_name with widget=option %}</div>{% endfor %}{% if group %} | ||||
|   </div>{% endif %}{% endfor %} | ||||
| </div>{% endwith %} | ||||
| @ -0,0 +1 @@ | ||||
| {% spaceless %}{% for widget in widget.subwidgets %}{% include widget.template_name %}{% endfor %}{% endspaceless %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/multiple_input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input_option.html" %} | ||||
| @ -0,0 +1,5 @@ | ||||
| <select name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>{% for group_name, group_choices, group_index in widget.optgroups %}{% if group_name %} | ||||
|   <optgroup label="{{ group_name }}">{% endif %}{% for option in group_choices %} | ||||
|   {% include option.template_name with widget=option %}{% endfor %}{% if group_name %} | ||||
|   </optgroup>{% endif %}{% endfor %} | ||||
| </select> | ||||
| @ -0,0 +1 @@ | ||||
| {% include 'django/forms/widgets/multiwidget.html' %} | ||||
| @ -0,0 +1 @@ | ||||
| <option value="{{ widget.value|stringformat:'s' }}"{% include "django/forms/widgets/attrs.html" %}>{{ widget.label }}</option> | ||||
| @ -0,0 +1 @@ | ||||
| {% include 'django/forms/widgets/multiwidget.html' %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include 'django/forms/widgets/multiwidget.html' %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1,2 @@ | ||||
| <textarea name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}> | ||||
| {% if widget.value %}{{ widget.value }}{% endif %}</textarea> | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
| @ -0,0 +1 @@ | ||||
| {% include "django/forms/widgets/input.html" %} | ||||
							
								
								
									
										243
									
								
								srcs/.venv/lib/python3.11/site-packages/django/forms/utils.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								srcs/.venv/lib/python3.11/site-packages/django/forms/utils.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,243 @@ | ||||
| import json | ||||
| import warnings | ||||
| from collections import UserList | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.core.exceptions import ValidationError | ||||
| from django.forms.renderers import get_default_renderer | ||||
| from django.utils import timezone | ||||
| from django.utils.deprecation import RemovedInDjango50Warning | ||||
| from django.utils.html import escape, format_html_join | ||||
| from django.utils.safestring import mark_safe | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| from django.utils.version import get_docs_version | ||||
|  | ||||
|  | ||||
| def pretty_name(name): | ||||
|     """Convert 'first_name' to 'First name'.""" | ||||
|     if not name: | ||||
|         return "" | ||||
|     return name.replace("_", " ").capitalize() | ||||
|  | ||||
|  | ||||
| def flatatt(attrs): | ||||
|     """ | ||||
|     Convert a dictionary of attributes to a single string. | ||||
|     The returned string will contain a leading space followed by key="value", | ||||
|     XML-style pairs. In the case of a boolean value, the key will appear | ||||
|     without a value. It is assumed that the keys do not need to be | ||||
|     XML-escaped. If the passed dictionary is empty, then return an empty | ||||
|     string. | ||||
|  | ||||
|     The result is passed through 'mark_safe' (by way of 'format_html_join'). | ||||
|     """ | ||||
|     key_value_attrs = [] | ||||
|     boolean_attrs = [] | ||||
|     for attr, value in attrs.items(): | ||||
|         if isinstance(value, bool): | ||||
|             if value: | ||||
|                 boolean_attrs.append((attr,)) | ||||
|         elif value is not None: | ||||
|             key_value_attrs.append((attr, value)) | ||||
|  | ||||
|     return format_html_join("", ' {}="{}"', sorted(key_value_attrs)) + format_html_join( | ||||
|         "", " {}", sorted(boolean_attrs) | ||||
|     ) | ||||
|  | ||||
|  | ||||
| DEFAULT_TEMPLATE_DEPRECATION_MSG = ( | ||||
|     'The "default.html" templates for forms and formsets will be removed. These were ' | ||||
|     'proxies to the equivalent "table.html" templates, but the new "div.html" ' | ||||
|     "templates will be the default from Django 5.0. Transitional renderers are " | ||||
|     "provided to allow you to opt-in to the new output style now. See " | ||||
|     "https://docs.djangoproject.com/en/%s/releases/4.1/ for more details" | ||||
|     % get_docs_version() | ||||
| ) | ||||
|  | ||||
|  | ||||
| class RenderableMixin: | ||||
|     def get_context(self): | ||||
|         raise NotImplementedError( | ||||
|             "Subclasses of RenderableMixin must provide a get_context() method." | ||||
|         ) | ||||
|  | ||||
|     def render(self, template_name=None, context=None, renderer=None): | ||||
|         renderer = renderer or self.renderer | ||||
|         template = template_name or self.template_name | ||||
|         context = context or self.get_context() | ||||
|         if ( | ||||
|             template == "django/forms/default.html" | ||||
|             or template == "django/forms/formsets/default.html" | ||||
|         ): | ||||
|             warnings.warn( | ||||
|                 DEFAULT_TEMPLATE_DEPRECATION_MSG, RemovedInDjango50Warning, stacklevel=2 | ||||
|             ) | ||||
|         return mark_safe(renderer.render(template, context)) | ||||
|  | ||||
|     __str__ = render | ||||
|     __html__ = render | ||||
|  | ||||
|  | ||||
| class RenderableFormMixin(RenderableMixin): | ||||
|     def as_p(self): | ||||
|         """Render as <p> elements.""" | ||||
|         return self.render(self.template_name_p) | ||||
|  | ||||
|     def as_table(self): | ||||
|         """Render as <tr> elements excluding the surrounding <table> tag.""" | ||||
|         return self.render(self.template_name_table) | ||||
|  | ||||
|     def as_ul(self): | ||||
|         """Render as <li> elements excluding the surrounding <ul> tag.""" | ||||
|         return self.render(self.template_name_ul) | ||||
|  | ||||
|     def as_div(self): | ||||
|         """Render as <div> elements.""" | ||||
|         return self.render(self.template_name_div) | ||||
|  | ||||
|  | ||||
| class RenderableErrorMixin(RenderableMixin): | ||||
|     def as_json(self, escape_html=False): | ||||
|         return json.dumps(self.get_json_data(escape_html)) | ||||
|  | ||||
|     def as_text(self): | ||||
|         return self.render(self.template_name_text) | ||||
|  | ||||
|     def as_ul(self): | ||||
|         return self.render(self.template_name_ul) | ||||
|  | ||||
|  | ||||
| class ErrorDict(dict, RenderableErrorMixin): | ||||
|     """ | ||||
|     A collection of errors that knows how to display itself in various formats. | ||||
|  | ||||
|     The dictionary keys are the field names, and the values are the errors. | ||||
|     """ | ||||
|  | ||||
|     template_name = "django/forms/errors/dict/default.html" | ||||
|     template_name_text = "django/forms/errors/dict/text.txt" | ||||
|     template_name_ul = "django/forms/errors/dict/ul.html" | ||||
|  | ||||
|     def __init__(self, *args, renderer=None, **kwargs): | ||||
|         super().__init__(*args, **kwargs) | ||||
|         self.renderer = renderer or get_default_renderer() | ||||
|  | ||||
|     def as_data(self): | ||||
|         return {f: e.as_data() for f, e in self.items()} | ||||
|  | ||||
|     def get_json_data(self, escape_html=False): | ||||
|         return {f: e.get_json_data(escape_html) for f, e in self.items()} | ||||
|  | ||||
|     def get_context(self): | ||||
|         return { | ||||
|             "errors": self.items(), | ||||
|             "error_class": "errorlist", | ||||
|         } | ||||
|  | ||||
|  | ||||
| class ErrorList(UserList, list, RenderableErrorMixin): | ||||
|     """ | ||||
|     A collection of errors that knows how to display itself in various formats. | ||||
|     """ | ||||
|  | ||||
|     template_name = "django/forms/errors/list/default.html" | ||||
|     template_name_text = "django/forms/errors/list/text.txt" | ||||
|     template_name_ul = "django/forms/errors/list/ul.html" | ||||
|  | ||||
|     def __init__(self, initlist=None, error_class=None, renderer=None): | ||||
|         super().__init__(initlist) | ||||
|  | ||||
|         if error_class is None: | ||||
|             self.error_class = "errorlist" | ||||
|         else: | ||||
|             self.error_class = "errorlist {}".format(error_class) | ||||
|         self.renderer = renderer or get_default_renderer() | ||||
|  | ||||
|     def as_data(self): | ||||
|         return ValidationError(self.data).error_list | ||||
|  | ||||
|     def copy(self): | ||||
|         copy = super().copy() | ||||
|         copy.error_class = self.error_class | ||||
|         return copy | ||||
|  | ||||
|     def get_json_data(self, escape_html=False): | ||||
|         errors = [] | ||||
|         for error in self.as_data(): | ||||
|             message = next(iter(error)) | ||||
|             errors.append( | ||||
|                 { | ||||
|                     "message": escape(message) if escape_html else message, | ||||
|                     "code": error.code or "", | ||||
|                 } | ||||
|             ) | ||||
|         return errors | ||||
|  | ||||
|     def get_context(self): | ||||
|         return { | ||||
|             "errors": self, | ||||
|             "error_class": self.error_class, | ||||
|         } | ||||
|  | ||||
|     def __repr__(self): | ||||
|         return repr(list(self)) | ||||
|  | ||||
|     def __contains__(self, item): | ||||
|         return item in list(self) | ||||
|  | ||||
|     def __eq__(self, other): | ||||
|         return list(self) == other | ||||
|  | ||||
|     def __getitem__(self, i): | ||||
|         error = self.data[i] | ||||
|         if isinstance(error, ValidationError): | ||||
|             return next(iter(error)) | ||||
|         return error | ||||
|  | ||||
|     def __reduce_ex__(self, *args, **kwargs): | ||||
|         # The `list` reduce function returns an iterator as the fourth element | ||||
|         # that is normally used for repopulating. Since we only inherit from | ||||
|         # `list` for `isinstance` backward compatibility (Refs #17413) we | ||||
|         # nullify this iterator as it would otherwise result in duplicate | ||||
|         # entries. (Refs #23594) | ||||
|         info = super(UserList, self).__reduce_ex__(*args, **kwargs) | ||||
|         return info[:3] + (None, None) | ||||
|  | ||||
|  | ||||
| # Utilities for time zone support in DateTimeField et al. | ||||
|  | ||||
|  | ||||
| def from_current_timezone(value): | ||||
|     """ | ||||
|     When time zone support is enabled, convert naive datetimes | ||||
|     entered in the current time zone to aware datetimes. | ||||
|     """ | ||||
|     if settings.USE_TZ and value is not None and timezone.is_naive(value): | ||||
|         current_timezone = timezone.get_current_timezone() | ||||
|         try: | ||||
|             if not timezone._is_pytz_zone( | ||||
|                 current_timezone | ||||
|             ) and timezone._datetime_ambiguous_or_imaginary(value, current_timezone): | ||||
|                 raise ValueError("Ambiguous or non-existent time.") | ||||
|             return timezone.make_aware(value, current_timezone) | ||||
|         except Exception as exc: | ||||
|             raise ValidationError( | ||||
|                 _( | ||||
|                     "%(datetime)s couldn’t be interpreted " | ||||
|                     "in time zone %(current_timezone)s; it " | ||||
|                     "may be ambiguous or it may not exist." | ||||
|                 ), | ||||
|                 code="ambiguous_timezone", | ||||
|                 params={"datetime": value, "current_timezone": current_timezone}, | ||||
|             ) from exc | ||||
|     return value | ||||
|  | ||||
|  | ||||
| def to_current_timezone(value): | ||||
|     """ | ||||
|     When time zone support is enabled, convert aware datetimes | ||||
|     to naive datetimes in the current time zone for display. | ||||
|     """ | ||||
|     if settings.USE_TZ and value is not None and timezone.is_aware(value): | ||||
|         return timezone.make_naive(value) | ||||
|     return value | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user