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

1import json 

2 

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 _ 

25 

26ACTION_CHECKBOX_NAME = "_selected_action" 

27 

28 

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 ) 

37 

38 

39checkbox = forms.CheckboxInput({"class": "action-select"}, lambda value: False) 39 ↛ exitline 39 didn't run the lambda on line 39

40 

41 

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 

60 

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 ) 

67 

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 ) 

77 

78 @property 

79 def errors(self): 

80 return self.form.errors 

81 

82 @property 

83 def non_field_errors(self): 

84 return self.form.non_field_errors 

85 

86 @property 

87 def media(self): 

88 media = self.form.media 

89 for fs in self: 

90 media = media + fs.media 

91 return media 

92 

93 

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 

111 

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() 

117 

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 ) 

123 

124 

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 

140 

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)) 

149 

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 ) 

158 

159 

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 

166 

167 def label_tag(self): 

168 classes = [] 

169 contents = conditional_escape(self.field.label) 

170 if self.is_checkbox: 

171 classes.append("vCheckboxLabel") 

172 

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 ) 

185 

186 def errors(self): 

187 return mark_safe(self.field.errors.as_ul()) 

188 

189 

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 

199 

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) 

204 

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) 

209 

210 if field in form.fields: 

211 is_hidden = form.fields[field].widget.is_hidden 

212 else: 

213 is_hidden = False 

214 

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() 

228 

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 ) 

240 

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) 

255 

256 def contents(self): 

257 from django.contrib.admin.templatetags.admin_list import _boolean_icon 

258 

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) 

295 

296 

297class InlineAdminFormSet: 

298 """ 

299 A wrapper around an inline formset for use in the admin system. 

300 """ 

301 

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 

330 

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 ) 

338 

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 ) 

373 

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 } 

415 

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 ) 

431 

432 @property 

433 def forms(self): 

434 return self.formset.forms 

435 

436 @property 

437 def non_form_errors(self): 

438 return self.formset.non_form_errors 

439 

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 

446 

447 

448class InlineAdminForm(AdminForm): 

449 """ 

450 A wrapper around an inline form for use in the admin system. 

451 """ 

452 

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 ) 

472 

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 ) 

483 

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 ) 

498 

499 def pk_field(self): 

500 return AdminField(self.form, self.formset._pk_field.name, False) 

501 

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 "" 

508 

509 def deletion_field(self): 

510 from django.forms.formsets import DELETION_FIELD_NAME 

511 

512 return AdminField(self.form, DELETION_FIELD_NAME, False) 

513 

514 def ordering_field(self): 

515 from django.forms.formsets import ORDERING_FIELD_NAME 

516 

517 return AdminField(self.form, ORDERING_FIELD_NAME, False) 

518 

519 

520class InlineFieldset(Fieldset): 

521 def __init__(self, formset, *args, **kwargs): 

522 self.formset = formset 

523 super().__init__(*args, **kwargs) 

524 

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 ) 

532 

533 

534class AdminErrorList(forms.utils.ErrorList): 

535 """Store errors for the form/formsets in an add/change view.""" 

536 

537 def __init__(self, form, inline_formsets): 

538 super().__init__() 

539 

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())