Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/contrib/admin/helpers.py: 24%
259 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1import json
3from django import forms
4from django.contrib.admin.utils import (
5 display_for_field,
6 flatten_fieldsets,
7 help_text_for_field,
8 label_for_field,
9 lookup_field,
10 quote,
11)
12from django.core.exceptions import ObjectDoesNotExist
13from django.db.models.fields.related import (
14 ForeignObjectRel,
15 ManyToManyRel,
16 OneToOneField,
17)
18from django.forms.utils import flatatt
19from django.template.defaultfilters import capfirst, linebreaksbr
20from django.urls import NoReverseMatch, reverse
21from django.utils.html import conditional_escape, format_html
22from django.utils.safestring import mark_safe
23from django.utils.translation import gettext
24from django.utils.translation import gettext_lazy as _
26ACTION_CHECKBOX_NAME = "_selected_action"
29class ActionForm(forms.Form):
30 action = forms.ChoiceField(label=_("Action:"))
31 select_across = forms.BooleanField(
32 label="",
33 required=False,
34 initial=0,
35 widget=forms.HiddenInput({"class": "select-across"}),
36 )
39checkbox = forms.CheckboxInput({"class": "action-select"}, lambda value: False) 39 ↛ exitline 39 didn't run the lambda on line 39
42class AdminForm:
43 def __init__(
44 self,
45 form,
46 fieldsets,
47 prepopulated_fields,
48 readonly_fields=None,
49 model_admin=None,
50 ):
51 self.form, self.fieldsets = form, fieldsets
52 self.prepopulated_fields = [
53 {"field": form[field_name], "dependencies": [form[f] for f in dependencies]}
54 for field_name, dependencies in prepopulated_fields.items()
55 ]
56 self.model_admin = model_admin
57 if readonly_fields is None:
58 readonly_fields = ()
59 self.readonly_fields = readonly_fields
61 def __repr__(self):
62 return (
63 f"<{self.__class__.__qualname__}: "
64 f"form={self.form.__class__.__qualname__} "
65 f"fieldsets={self.fieldsets!r}>"
66 )
68 def __iter__(self):
69 for name, options in self.fieldsets:
70 yield Fieldset(
71 self.form,
72 name,
73 readonly_fields=self.readonly_fields,
74 model_admin=self.model_admin,
75 **options,
76 )
78 @property
79 def errors(self):
80 return self.form.errors
82 @property
83 def non_field_errors(self):
84 return self.form.non_field_errors
86 @property
87 def media(self):
88 media = self.form.media
89 for fs in self:
90 media = media + fs.media
91 return media
94class Fieldset:
95 def __init__(
96 self,
97 form,
98 name=None,
99 readonly_fields=(),
100 fields=(),
101 classes=(),
102 description=None,
103 model_admin=None,
104 ):
105 self.form = form
106 self.name, self.fields = name, fields
107 self.classes = " ".join(classes)
108 self.description = description
109 self.model_admin = model_admin
110 self.readonly_fields = readonly_fields
112 @property
113 def media(self):
114 if "collapse" in self.classes:
115 return forms.Media(js=["admin/js/collapse.js"])
116 return forms.Media()
118 def __iter__(self):
119 for field in self.fields:
120 yield Fieldline(
121 self.form, field, self.readonly_fields, model_admin=self.model_admin
122 )
125class Fieldline:
126 def __init__(self, form, field, readonly_fields=None, model_admin=None):
127 self.form = form # A django.forms.Form instance
128 if not hasattr(field, "__iter__") or isinstance(field, str):
129 self.fields = [field]
130 else:
131 self.fields = field
132 self.has_visible_field = not all(
133 field in self.form.fields and self.form.fields[field].widget.is_hidden
134 for field in self.fields
135 )
136 self.model_admin = model_admin
137 if readonly_fields is None:
138 readonly_fields = ()
139 self.readonly_fields = readonly_fields
141 def __iter__(self):
142 for i, field in enumerate(self.fields):
143 if field in self.readonly_fields:
144 yield AdminReadonlyField(
145 self.form, field, is_first=(i == 0), model_admin=self.model_admin
146 )
147 else:
148 yield AdminField(self.form, field, is_first=(i == 0))
150 def errors(self):
151 return mark_safe(
152 "\n".join(
153 self.form[f].errors.as_ul()
154 for f in self.fields
155 if f not in self.readonly_fields
156 ).strip("\n")
157 )
160class AdminField:
161 def __init__(self, form, field, is_first):
162 self.field = form[field] # A django.forms.BoundField instance
163 self.is_first = is_first # Whether this field is first on the line
164 self.is_checkbox = isinstance(self.field.field.widget, forms.CheckboxInput)
165 self.is_readonly = False
167 def label_tag(self):
168 classes = []
169 contents = conditional_escape(self.field.label)
170 if self.is_checkbox:
171 classes.append("vCheckboxLabel")
173 if self.field.field.required:
174 classes.append("required")
175 if not self.is_first:
176 classes.append("inline")
177 attrs = {"class": " ".join(classes)} if classes else {}
178 # checkboxes should not have a label suffix as the checkbox appears
179 # to the left of the label.
180 return self.field.label_tag(
181 contents=mark_safe(contents),
182 attrs=attrs,
183 label_suffix="" if self.is_checkbox else None,
184 )
186 def errors(self):
187 return mark_safe(self.field.errors.as_ul())
190class AdminReadonlyField:
191 def __init__(self, form, field, is_first, model_admin=None):
192 # Make self.field look a little bit like a field. This means that
193 # {{ field.name }} must be a useful class name to identify the field.
194 # For convenience, store other field-related data here too.
195 if callable(field):
196 class_name = field.__name__ if field.__name__ != "<lambda>" else ""
197 else:
198 class_name = field
200 if form._meta.labels and class_name in form._meta.labels:
201 label = form._meta.labels[class_name]
202 else:
203 label = label_for_field(field, form._meta.model, model_admin, form=form)
205 if form._meta.help_texts and class_name in form._meta.help_texts:
206 help_text = form._meta.help_texts[class_name]
207 else:
208 help_text = help_text_for_field(class_name, form._meta.model)
210 if field in form.fields:
211 is_hidden = form.fields[field].widget.is_hidden
212 else:
213 is_hidden = False
215 self.field = {
216 "name": class_name,
217 "label": label,
218 "help_text": help_text,
219 "field": field,
220 "is_hidden": is_hidden,
221 }
222 self.form = form
223 self.model_admin = model_admin
224 self.is_first = is_first
225 self.is_checkbox = False
226 self.is_readonly = True
227 self.empty_value_display = model_admin.get_empty_value_display()
229 def label_tag(self):
230 attrs = {}
231 if not self.is_first:
232 attrs["class"] = "inline"
233 label = self.field["label"]
234 return format_html(
235 "<label{}>{}{}</label>",
236 flatatt(attrs),
237 capfirst(label),
238 self.form.label_suffix,
239 )
241 def get_admin_url(self, remote_field, remote_obj):
242 url_name = "admin:%s_%s_change" % (
243 remote_field.model._meta.app_label,
244 remote_field.model._meta.model_name,
245 )
246 try:
247 url = reverse(
248 url_name,
249 args=[quote(remote_obj.pk)],
250 current_app=self.model_admin.admin_site.name,
251 )
252 return format_html('<a href="{}">{}</a>', url, remote_obj)
253 except NoReverseMatch:
254 return str(remote_obj)
256 def contents(self):
257 from django.contrib.admin.templatetags.admin_list import _boolean_icon
259 field, obj, model_admin = (
260 self.field["field"],
261 self.form.instance,
262 self.model_admin,
263 )
264 try:
265 f, attr, value = lookup_field(field, obj, model_admin)
266 except (AttributeError, ValueError, ObjectDoesNotExist):
267 result_repr = self.empty_value_display
268 else:
269 if field in self.form.fields:
270 widget = self.form[field].field.widget
271 # This isn't elegant but suffices for contrib.auth's
272 # ReadOnlyPasswordHashWidget.
273 if getattr(widget, "read_only", False):
274 return widget.render(field, value)
275 if f is None:
276 if getattr(attr, "boolean", False):
277 result_repr = _boolean_icon(value)
278 else:
279 if hasattr(value, "__html__"):
280 result_repr = value
281 else:
282 result_repr = linebreaksbr(value)
283 else:
284 if isinstance(f.remote_field, ManyToManyRel) and value is not None:
285 result_repr = ", ".join(map(str, value.all()))
286 elif (
287 isinstance(f.remote_field, (ForeignObjectRel, OneToOneField))
288 and value is not None
289 ):
290 result_repr = self.get_admin_url(f.remote_field, value)
291 else:
292 result_repr = display_for_field(value, f, self.empty_value_display)
293 result_repr = linebreaksbr(result_repr)
294 return conditional_escape(result_repr)
297class InlineAdminFormSet:
298 """
299 A wrapper around an inline formset for use in the admin system.
300 """
302 def __init__(
303 self,
304 inline,
305 formset,
306 fieldsets,
307 prepopulated_fields=None,
308 readonly_fields=None,
309 model_admin=None,
310 has_add_permission=True,
311 has_change_permission=True,
312 has_delete_permission=True,
313 has_view_permission=True,
314 ):
315 self.opts = inline
316 self.formset = formset
317 self.fieldsets = fieldsets
318 self.model_admin = model_admin
319 if readonly_fields is None:
320 readonly_fields = ()
321 self.readonly_fields = readonly_fields
322 if prepopulated_fields is None:
323 prepopulated_fields = {}
324 self.prepopulated_fields = prepopulated_fields
325 self.classes = " ".join(inline.classes) if inline.classes else ""
326 self.has_add_permission = has_add_permission
327 self.has_change_permission = has_change_permission
328 self.has_delete_permission = has_delete_permission
329 self.has_view_permission = has_view_permission
331 def __iter__(self):
332 if self.has_change_permission:
333 readonly_fields_for_editing = self.readonly_fields
334 else:
335 readonly_fields_for_editing = self.readonly_fields + flatten_fieldsets(
336 self.fieldsets
337 )
339 for form, original in zip(
340 self.formset.initial_forms, self.formset.get_queryset()
341 ):
342 view_on_site_url = self.opts.get_view_on_site_url(original)
343 yield InlineAdminForm(
344 self.formset,
345 form,
346 self.fieldsets,
347 self.prepopulated_fields,
348 original,
349 readonly_fields_for_editing,
350 model_admin=self.opts,
351 view_on_site_url=view_on_site_url,
352 )
353 for form in self.formset.extra_forms:
354 yield InlineAdminForm(
355 self.formset,
356 form,
357 self.fieldsets,
358 self.prepopulated_fields,
359 None,
360 self.readonly_fields,
361 model_admin=self.opts,
362 )
363 if self.has_add_permission:
364 yield InlineAdminForm(
365 self.formset,
366 self.formset.empty_form,
367 self.fieldsets,
368 self.prepopulated_fields,
369 None,
370 self.readonly_fields,
371 model_admin=self.opts,
372 )
374 def fields(self):
375 fk = getattr(self.formset, "fk", None)
376 empty_form = self.formset.empty_form
377 meta_labels = empty_form._meta.labels or {}
378 meta_help_texts = empty_form._meta.help_texts or {}
379 for i, field_name in enumerate(flatten_fieldsets(self.fieldsets)):
380 if fk and fk.name == field_name:
381 continue
382 if not self.has_change_permission or field_name in self.readonly_fields:
383 form_field = empty_form.fields.get(field_name)
384 widget_is_hidden = False
385 if form_field is not None:
386 widget_is_hidden = form_field.widget.is_hidden
387 yield {
388 "name": field_name,
389 "label": meta_labels.get(field_name)
390 or label_for_field(
391 field_name,
392 self.opts.model,
393 self.opts,
394 form=empty_form,
395 ),
396 "widget": {"is_hidden": widget_is_hidden},
397 "required": False,
398 "help_text": meta_help_texts.get(field_name)
399 or help_text_for_field(field_name, self.opts.model),
400 }
401 else:
402 form_field = empty_form.fields[field_name]
403 label = form_field.label
404 if label is None:
405 label = label_for_field(
406 field_name, self.opts.model, self.opts, form=empty_form
407 )
408 yield {
409 "name": field_name,
410 "label": label,
411 "widget": form_field.widget,
412 "required": form_field.required,
413 "help_text": form_field.help_text,
414 }
416 def inline_formset_data(self):
417 verbose_name = self.opts.verbose_name
418 return json.dumps(
419 {
420 "name": "#%s" % self.formset.prefix,
421 "options": {
422 "prefix": self.formset.prefix,
423 "addText": gettext("Add another %(verbose_name)s")
424 % {
425 "verbose_name": capfirst(verbose_name),
426 },
427 "deleteText": gettext("Remove"),
428 },
429 }
430 )
432 @property
433 def forms(self):
434 return self.formset.forms
436 @property
437 def non_form_errors(self):
438 return self.formset.non_form_errors
440 @property
441 def media(self):
442 media = self.opts.media + self.formset.media
443 for fs in self:
444 media = media + fs.media
445 return media
448class InlineAdminForm(AdminForm):
449 """
450 A wrapper around an inline form for use in the admin system.
451 """
453 def __init__(
454 self,
455 formset,
456 form,
457 fieldsets,
458 prepopulated_fields,
459 original,
460 readonly_fields=None,
461 model_admin=None,
462 view_on_site_url=None,
463 ):
464 self.formset = formset
465 self.model_admin = model_admin
466 self.original = original
467 self.show_url = original and view_on_site_url is not None
468 self.absolute_url = view_on_site_url
469 super().__init__(
470 form, fieldsets, prepopulated_fields, readonly_fields, model_admin
471 )
473 def __iter__(self):
474 for name, options in self.fieldsets:
475 yield InlineFieldset(
476 self.formset,
477 self.form,
478 name,
479 self.readonly_fields,
480 model_admin=self.model_admin,
481 **options,
482 )
484 def needs_explicit_pk_field(self):
485 return (
486 # Auto fields are editable, so check for auto or non-editable pk.
487 self.form._meta.model._meta.auto_field
488 or not self.form._meta.model._meta.pk.editable
489 or
490 # Also search any parents for an auto field. (The pk info is
491 # propagated to child models so that does not need to be checked
492 # in parents.)
493 any(
494 parent._meta.auto_field or not parent._meta.model._meta.pk.editable
495 for parent in self.form._meta.model._meta.get_parent_list()
496 )
497 )
499 def pk_field(self):
500 return AdminField(self.form, self.formset._pk_field.name, False)
502 def fk_field(self):
503 fk = getattr(self.formset, "fk", None)
504 if fk:
505 return AdminField(self.form, fk.name, False)
506 else:
507 return ""
509 def deletion_field(self):
510 from django.forms.formsets import DELETION_FIELD_NAME
512 return AdminField(self.form, DELETION_FIELD_NAME, False)
514 def ordering_field(self):
515 from django.forms.formsets import ORDERING_FIELD_NAME
517 return AdminField(self.form, ORDERING_FIELD_NAME, False)
520class InlineFieldset(Fieldset):
521 def __init__(self, formset, *args, **kwargs):
522 self.formset = formset
523 super().__init__(*args, **kwargs)
525 def __iter__(self):
526 fk = getattr(self.formset, "fk", None)
527 for field in self.fields:
528 if not fk or fk.name != field:
529 yield Fieldline(
530 self.form, field, self.readonly_fields, model_admin=self.model_admin
531 )
534class AdminErrorList(forms.utils.ErrorList):
535 """Store errors for the form/formsets in an add/change view."""
537 def __init__(self, form, inline_formsets):
538 super().__init__()
540 if form.is_bound:
541 self.extend(form.errors.values())
542 for inline_formset in inline_formsets:
543 self.extend(inline_formset.non_form_errors())
544 for errors_in_inline_form in inline_formset.errors:
545 self.extend(errors_in_inline_form.values())