Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/django/forms/models.py: 16%

709 statements  

« prev     ^ index     » next       coverage.py v7.0.5, created at 2023-01-17 06:13 +0000

1""" 

2Helper functions for creating Form classes from Django models 

3and database field objects. 

4""" 

5from itertools import chain 

6 

7from django.core.exceptions import ( 

8 NON_FIELD_ERRORS, 

9 FieldError, 

10 ImproperlyConfigured, 

11 ValidationError, 

12) 

13from django.db.models.utils import AltersData 

14from django.forms.fields import ChoiceField, Field 

15from django.forms.forms import BaseForm, DeclarativeFieldsMetaclass 

16from django.forms.formsets import BaseFormSet, formset_factory 

17from django.forms.utils import ErrorList 

18from django.forms.widgets import ( 

19 HiddenInput, 

20 MultipleHiddenInput, 

21 RadioSelect, 

22 SelectMultiple, 

23) 

24from django.utils.text import capfirst, get_text_list 

25from django.utils.translation import gettext 

26from django.utils.translation import gettext_lazy as _ 

27 

28__all__ = ( 

29 "ModelForm", 

30 "BaseModelForm", 

31 "model_to_dict", 

32 "fields_for_model", 

33 "ModelChoiceField", 

34 "ModelMultipleChoiceField", 

35 "ALL_FIELDS", 

36 "BaseModelFormSet", 

37 "modelformset_factory", 

38 "BaseInlineFormSet", 

39 "inlineformset_factory", 

40 "modelform_factory", 

41) 

42 

43ALL_FIELDS = "__all__" 

44 

45 

46def construct_instance(form, instance, fields=None, exclude=None): 

47 """ 

48 Construct and return a model instance from the bound ``form``'s 

49 ``cleaned_data``, but do not save the returned instance to the database. 

50 """ 

51 from django.db import models 

52 

53 opts = instance._meta 

54 

55 cleaned_data = form.cleaned_data 

56 file_field_list = [] 

57 for f in opts.fields: 

58 if ( 

59 not f.editable 

60 or isinstance(f, models.AutoField) 

61 or f.name not in cleaned_data 

62 ): 

63 continue 

64 if fields is not None and f.name not in fields: 

65 continue 

66 if exclude and f.name in exclude: 

67 continue 

68 # Leave defaults for fields that aren't in POST data, except for 

69 # checkbox inputs because they don't appear in POST data if not checked. 

70 if ( 

71 f.has_default() 

72 and form[f.name].field.widget.value_omitted_from_data( 

73 form.data, form.files, form.add_prefix(f.name) 

74 ) 

75 and cleaned_data.get(f.name) in form[f.name].field.empty_values 

76 ): 

77 continue 

78 # Defer saving file-type fields until after the other fields, so a 

79 # callable upload_to can use the values from other fields. 

80 if isinstance(f, models.FileField): 

81 file_field_list.append(f) 

82 else: 

83 f.save_form_data(instance, cleaned_data[f.name]) 

84 

85 for f in file_field_list: 

86 f.save_form_data(instance, cleaned_data[f.name]) 

87 

88 return instance 

89 

90 

91# ModelForms ################################################################# 

92 

93 

94def model_to_dict(instance, fields=None, exclude=None): 

95 """ 

96 Return a dict containing the data in ``instance`` suitable for passing as 

97 a Form's ``initial`` keyword argument. 

98 

99 ``fields`` is an optional list of field names. If provided, return only the 

100 named. 

101 

102 ``exclude`` is an optional list of field names. If provided, exclude the 

103 named from the returned dict, even if they are listed in the ``fields`` 

104 argument. 

105 """ 

106 opts = instance._meta 

107 data = {} 

108 for f in chain(opts.concrete_fields, opts.private_fields, opts.many_to_many): 

109 if not getattr(f, "editable", False): 

110 continue 

111 if fields is not None and f.name not in fields: 

112 continue 

113 if exclude and f.name in exclude: 

114 continue 

115 data[f.name] = f.value_from_object(instance) 

116 return data 

117 

118 

119def apply_limit_choices_to_to_formfield(formfield): 

120 """Apply limit_choices_to to the formfield's queryset if needed.""" 

121 from django.db.models import Exists, OuterRef, Q 

122 

123 if hasattr(formfield, "queryset") and hasattr(formfield, "get_limit_choices_to"): 

124 limit_choices_to = formfield.get_limit_choices_to() 

125 if limit_choices_to: 

126 complex_filter = limit_choices_to 

127 if not isinstance(complex_filter, Q): 

128 complex_filter = Q(**limit_choices_to) 

129 complex_filter &= Q(pk=OuterRef("pk")) 

130 # Use Exists() to avoid potential duplicates. 

131 formfield.queryset = formfield.queryset.filter( 

132 Exists(formfield.queryset.model._base_manager.filter(complex_filter)), 

133 ) 

134 

135 

136def fields_for_model( 

137 model, 

138 fields=None, 

139 exclude=None, 

140 widgets=None, 

141 formfield_callback=None, 

142 localized_fields=None, 

143 labels=None, 

144 help_texts=None, 

145 error_messages=None, 

146 field_classes=None, 

147 *, 

148 apply_limit_choices_to=True, 

149): 

150 """ 

151 Return a dictionary containing form fields for the given model. 

152 

153 ``fields`` is an optional list of field names. If provided, return only the 

154 named fields. 

155 

156 ``exclude`` is an optional list of field names. If provided, exclude the 

157 named fields from the returned fields, even if they are listed in the 

158 ``fields`` argument. 

159 

160 ``widgets`` is a dictionary of model field names mapped to a widget. 

161 

162 ``formfield_callback`` is a callable that takes a model field and returns 

163 a form field. 

164 

165 ``localized_fields`` is a list of names of fields which should be localized. 

166 

167 ``labels`` is a dictionary of model field names mapped to a label. 

168 

169 ``help_texts`` is a dictionary of model field names mapped to a help text. 

170 

171 ``error_messages`` is a dictionary of model field names mapped to a 

172 dictionary of error messages. 

173 

174 ``field_classes`` is a dictionary of model field names mapped to a form 

175 field class. 

176 

177 ``apply_limit_choices_to`` is a boolean indicating if limit_choices_to 

178 should be applied to a field's queryset. 

179 """ 

180 field_dict = {} 

181 ignored = [] 

182 opts = model._meta 

183 # Avoid circular import 

184 from django.db.models import Field as ModelField 

185 

186 sortable_private_fields = [ 

187 f for f in opts.private_fields if isinstance(f, ModelField) 

188 ] 

189 for f in sorted( 

190 chain(opts.concrete_fields, sortable_private_fields, opts.many_to_many) 

191 ): 

192 if not getattr(f, "editable", False): 

193 if ( 

194 fields is not None 

195 and f.name in fields 

196 and (exclude is None or f.name not in exclude) 

197 ): 

198 raise FieldError( 

199 "'%s' cannot be specified for %s model form as it is a " 

200 "non-editable field" % (f.name, model.__name__) 

201 ) 

202 continue 

203 if fields is not None and f.name not in fields: 

204 continue 

205 if exclude and f.name in exclude: 

206 continue 

207 

208 kwargs = {} 

209 if widgets and f.name in widgets: 

210 kwargs["widget"] = widgets[f.name] 

211 if localized_fields == ALL_FIELDS or ( 

212 localized_fields and f.name in localized_fields 

213 ): 

214 kwargs["localize"] = True 

215 if labels and f.name in labels: 

216 kwargs["label"] = labels[f.name] 

217 if help_texts and f.name in help_texts: 

218 kwargs["help_text"] = help_texts[f.name] 

219 if error_messages and f.name in error_messages: 

220 kwargs["error_messages"] = error_messages[f.name] 

221 if field_classes and f.name in field_classes: 

222 kwargs["form_class"] = field_classes[f.name] 

223 

224 if formfield_callback is None: 

225 formfield = f.formfield(**kwargs) 

226 elif not callable(formfield_callback): 

227 raise TypeError("formfield_callback must be a function or callable") 

228 else: 

229 formfield = formfield_callback(f, **kwargs) 

230 

231 if formfield: 

232 if apply_limit_choices_to: 

233 apply_limit_choices_to_to_formfield(formfield) 

234 field_dict[f.name] = formfield 

235 else: 

236 ignored.append(f.name) 

237 if fields: 

238 field_dict = { 

239 f: field_dict.get(f) 

240 for f in fields 

241 if (not exclude or f not in exclude) and f not in ignored 

242 } 

243 return field_dict 

244 

245 

246class ModelFormOptions: 

247 def __init__(self, options=None): 

248 self.model = getattr(options, "model", None) 

249 self.fields = getattr(options, "fields", None) 

250 self.exclude = getattr(options, "exclude", None) 

251 self.widgets = getattr(options, "widgets", None) 

252 self.localized_fields = getattr(options, "localized_fields", None) 

253 self.labels = getattr(options, "labels", None) 

254 self.help_texts = getattr(options, "help_texts", None) 

255 self.error_messages = getattr(options, "error_messages", None) 

256 self.field_classes = getattr(options, "field_classes", None) 

257 self.formfield_callback = getattr(options, "formfield_callback", None) 

258 

259 

260class ModelFormMetaclass(DeclarativeFieldsMetaclass): 

261 def __new__(mcs, name, bases, attrs): 

262 new_class = super().__new__(mcs, name, bases, attrs) 

263 

264 if bases == (BaseModelForm,): 

265 return new_class 

266 

267 opts = new_class._meta = ModelFormOptions(getattr(new_class, "Meta", None)) 

268 

269 # We check if a string was passed to `fields` or `exclude`, 

270 # which is likely to be a mistake where the user typed ('foo') instead 

271 # of ('foo',) 

272 for opt in ["fields", "exclude", "localized_fields"]: 

273 value = getattr(opts, opt) 

274 if isinstance(value, str) and value != ALL_FIELDS: 

275 msg = ( 

276 "%(model)s.Meta.%(opt)s cannot be a string. " 

277 "Did you mean to type: ('%(value)s',)?" 

278 % { 

279 "model": new_class.__name__, 

280 "opt": opt, 

281 "value": value, 

282 } 

283 ) 

284 raise TypeError(msg) 

285 

286 if opts.model: 

287 # If a model is defined, extract form fields from it. 

288 if opts.fields is None and opts.exclude is None: 

289 raise ImproperlyConfigured( 

290 "Creating a ModelForm without either the 'fields' attribute " 

291 "or the 'exclude' attribute is prohibited; form %s " 

292 "needs updating." % name 

293 ) 

294 

295 if opts.fields == ALL_FIELDS: 

296 # Sentinel for fields_for_model to indicate "get the list of 

297 # fields from the model" 

298 opts.fields = None 

299 

300 fields = fields_for_model( 

301 opts.model, 

302 opts.fields, 

303 opts.exclude, 

304 opts.widgets, 

305 opts.formfield_callback, 

306 opts.localized_fields, 

307 opts.labels, 

308 opts.help_texts, 

309 opts.error_messages, 

310 opts.field_classes, 

311 # limit_choices_to will be applied during ModelForm.__init__(). 

312 apply_limit_choices_to=False, 

313 ) 

314 

315 # make sure opts.fields doesn't specify an invalid field 

316 none_model_fields = {k for k, v in fields.items() if not v} 

317 missing_fields = none_model_fields.difference(new_class.declared_fields) 

318 if missing_fields: 

319 message = "Unknown field(s) (%s) specified for %s" 

320 message %= (", ".join(missing_fields), opts.model.__name__) 

321 raise FieldError(message) 

322 # Override default model fields with any custom declared ones 

323 # (plus, include all the other declared fields). 

324 fields.update(new_class.declared_fields) 

325 else: 

326 fields = new_class.declared_fields 

327 

328 new_class.base_fields = fields 

329 

330 return new_class 

331 

332 

333class BaseModelForm(BaseForm, AltersData): 

334 def __init__( 

335 self, 

336 data=None, 

337 files=None, 

338 auto_id="id_%s", 

339 prefix=None, 

340 initial=None, 

341 error_class=ErrorList, 

342 label_suffix=None, 

343 empty_permitted=False, 

344 instance=None, 

345 use_required_attribute=None, 

346 renderer=None, 

347 ): 

348 opts = self._meta 

349 if opts.model is None: 

350 raise ValueError("ModelForm has no model class specified.") 

351 if instance is None: 

352 # if we didn't get an instance, instantiate a new one 

353 self.instance = opts.model() 

354 object_data = {} 

355 else: 

356 self.instance = instance 

357 object_data = model_to_dict(instance, opts.fields, opts.exclude) 

358 # if initial was provided, it should override the values from instance 

359 if initial is not None: 

360 object_data.update(initial) 

361 # self._validate_unique will be set to True by BaseModelForm.clean(). 

362 # It is False by default so overriding self.clean() and failing to call 

363 # super will stop validate_unique from being called. 

364 self._validate_unique = False 

365 super().__init__( 

366 data, 

367 files, 

368 auto_id, 

369 prefix, 

370 object_data, 

371 error_class, 

372 label_suffix, 

373 empty_permitted, 

374 use_required_attribute=use_required_attribute, 

375 renderer=renderer, 

376 ) 

377 for formfield in self.fields.values(): 

378 apply_limit_choices_to_to_formfield(formfield) 

379 

380 def _get_validation_exclusions(self): 

381 """ 

382 For backwards-compatibility, exclude several types of fields from model 

383 validation. See tickets #12507, #12521, #12553. 

384 """ 

385 exclude = set() 

386 # Build up a list of fields that should be excluded from model field 

387 # validation and unique checks. 

388 for f in self.instance._meta.fields: 

389 field = f.name 

390 # Exclude fields that aren't on the form. The developer may be 

391 # adding these values to the model after form validation. 

392 if field not in self.fields: 

393 exclude.add(f.name) 

394 

395 # Don't perform model validation on fields that were defined 

396 # manually on the form and excluded via the ModelForm's Meta 

397 # class. See #12901. 

398 elif self._meta.fields and field not in self._meta.fields: 

399 exclude.add(f.name) 

400 elif self._meta.exclude and field in self._meta.exclude: 

401 exclude.add(f.name) 

402 

403 # Exclude fields that failed form validation. There's no need for 

404 # the model fields to validate them as well. 

405 elif field in self._errors: 

406 exclude.add(f.name) 

407 

408 # Exclude empty fields that are not required by the form, if the 

409 # underlying model field is required. This keeps the model field 

410 # from raising a required error. Note: don't exclude the field from 

411 # validation if the model field allows blanks. If it does, the blank 

412 # value may be included in a unique check, so cannot be excluded 

413 # from validation. 

414 else: 

415 form_field = self.fields[field] 

416 field_value = self.cleaned_data.get(field) 

417 if ( 

418 not f.blank 

419 and not form_field.required 

420 and field_value in form_field.empty_values 

421 ): 

422 exclude.add(f.name) 

423 return exclude 

424 

425 def clean(self): 

426 self._validate_unique = True 

427 return self.cleaned_data 

428 

429 def _update_errors(self, errors): 

430 # Override any validation error messages defined at the model level 

431 # with those defined at the form level. 

432 opts = self._meta 

433 

434 # Allow the model generated by construct_instance() to raise 

435 # ValidationError and have them handled in the same way as others. 

436 if hasattr(errors, "error_dict"): 

437 error_dict = errors.error_dict 

438 else: 

439 error_dict = {NON_FIELD_ERRORS: errors} 

440 

441 for field, messages in error_dict.items(): 

442 if ( 

443 field == NON_FIELD_ERRORS 

444 and opts.error_messages 

445 and NON_FIELD_ERRORS in opts.error_messages 

446 ): 

447 error_messages = opts.error_messages[NON_FIELD_ERRORS] 

448 elif field in self.fields: 

449 error_messages = self.fields[field].error_messages 

450 else: 

451 continue 

452 

453 for message in messages: 

454 if ( 

455 isinstance(message, ValidationError) 

456 and message.code in error_messages 

457 ): 

458 message.message = error_messages[message.code] 

459 

460 self.add_error(None, errors) 

461 

462 def _post_clean(self): 

463 opts = self._meta 

464 

465 exclude = self._get_validation_exclusions() 

466 

467 # Foreign Keys being used to represent inline relationships 

468 # are excluded from basic field value validation. This is for two 

469 # reasons: firstly, the value may not be supplied (#12507; the 

470 # case of providing new values to the admin); secondly the 

471 # object being referred to may not yet fully exist (#12749). 

472 # However, these fields *must* be included in uniqueness checks, 

473 # so this can't be part of _get_validation_exclusions(). 

474 for name, field in self.fields.items(): 

475 if isinstance(field, InlineForeignKeyField): 

476 exclude.add(name) 

477 

478 try: 

479 self.instance = construct_instance( 

480 self, self.instance, opts.fields, opts.exclude 

481 ) 

482 except ValidationError as e: 

483 self._update_errors(e) 

484 

485 try: 

486 self.instance.full_clean(exclude=exclude, validate_unique=False) 

487 except ValidationError as e: 

488 self._update_errors(e) 

489 

490 # Validate uniqueness if needed. 

491 if self._validate_unique: 

492 self.validate_unique() 

493 

494 def validate_unique(self): 

495 """ 

496 Call the instance's validate_unique() method and update the form's 

497 validation errors if any were raised. 

498 """ 

499 exclude = self._get_validation_exclusions() 

500 try: 

501 self.instance.validate_unique(exclude=exclude) 

502 except ValidationError as e: 

503 self._update_errors(e) 

504 

505 def _save_m2m(self): 

506 """ 

507 Save the many-to-many fields and generic relations for this form. 

508 """ 

509 cleaned_data = self.cleaned_data 

510 exclude = self._meta.exclude 

511 fields = self._meta.fields 

512 opts = self.instance._meta 

513 # Note that for historical reasons we want to include also 

514 # private_fields here. (GenericRelation was previously a fake 

515 # m2m field). 

516 for f in chain(opts.many_to_many, opts.private_fields): 

517 if not hasattr(f, "save_form_data"): 

518 continue 

519 if fields and f.name not in fields: 

520 continue 

521 if exclude and f.name in exclude: 

522 continue 

523 if f.name in cleaned_data: 

524 f.save_form_data(self.instance, cleaned_data[f.name]) 

525 

526 def save(self, commit=True): 

527 """ 

528 Save this form's self.instance object if commit=True. Otherwise, add 

529 a save_m2m() method to the form which can be called after the instance 

530 is saved manually at a later time. Return the model instance. 

531 """ 

532 if self.errors: 

533 raise ValueError( 

534 "The %s could not be %s because the data didn't validate." 

535 % ( 

536 self.instance._meta.object_name, 

537 "created" if self.instance._state.adding else "changed", 

538 ) 

539 ) 

540 if commit: 

541 # If committing, save the instance and the m2m data immediately. 

542 self.instance.save() 

543 self._save_m2m() 

544 else: 

545 # If not committing, add a method to the form to allow deferred 

546 # saving of m2m data. 

547 self.save_m2m = self._save_m2m 

548 return self.instance 

549 

550 save.alters_data = True 

551 

552 

553class ModelForm(BaseModelForm, metaclass=ModelFormMetaclass): 

554 pass 

555 

556 

557def modelform_factory( 

558 model, 

559 form=ModelForm, 

560 fields=None, 

561 exclude=None, 

562 formfield_callback=None, 

563 widgets=None, 

564 localized_fields=None, 

565 labels=None, 

566 help_texts=None, 

567 error_messages=None, 

568 field_classes=None, 

569): 

570 """ 

571 Return a ModelForm containing form fields for the given model. You can 

572 optionally pass a `form` argument to use as a starting point for 

573 constructing the ModelForm. 

574 

575 ``fields`` is an optional list of field names. If provided, include only 

576 the named fields in the returned fields. If omitted or '__all__', use all 

577 fields. 

578 

579 ``exclude`` is an optional list of field names. If provided, exclude the 

580 named fields from the returned fields, even if they are listed in the 

581 ``fields`` argument. 

582 

583 ``widgets`` is a dictionary of model field names mapped to a widget. 

584 

585 ``localized_fields`` is a list of names of fields which should be localized. 

586 

587 ``formfield_callback`` is a callable that takes a model field and returns 

588 a form field. 

589 

590 ``labels`` is a dictionary of model field names mapped to a label. 

591 

592 ``help_texts`` is a dictionary of model field names mapped to a help text. 

593 

594 ``error_messages`` is a dictionary of model field names mapped to a 

595 dictionary of error messages. 

596 

597 ``field_classes`` is a dictionary of model field names mapped to a form 

598 field class. 

599 """ 

600 # Create the inner Meta class. FIXME: ideally, we should be able to 

601 # construct a ModelForm without creating and passing in a temporary 

602 # inner class. 

603 

604 # Build up a list of attributes that the Meta object will have. 

605 attrs = {"model": model} 

606 if fields is not None: 

607 attrs["fields"] = fields 

608 if exclude is not None: 

609 attrs["exclude"] = exclude 

610 if widgets is not None: 

611 attrs["widgets"] = widgets 

612 if localized_fields is not None: 

613 attrs["localized_fields"] = localized_fields 

614 if labels is not None: 

615 attrs["labels"] = labels 

616 if help_texts is not None: 

617 attrs["help_texts"] = help_texts 

618 if error_messages is not None: 

619 attrs["error_messages"] = error_messages 

620 if field_classes is not None: 

621 attrs["field_classes"] = field_classes 

622 

623 # If parent form class already has an inner Meta, the Meta we're 

624 # creating needs to inherit from the parent's inner meta. 

625 bases = (form.Meta,) if hasattr(form, "Meta") else () 

626 Meta = type("Meta", bases, attrs) 

627 if formfield_callback: 

628 Meta.formfield_callback = staticmethod(formfield_callback) 

629 # Give this new form class a reasonable name. 

630 class_name = model.__name__ + "Form" 

631 

632 # Class attributes for the new form class. 

633 form_class_attrs = {"Meta": Meta} 

634 

635 if getattr(Meta, "fields", None) is None and getattr(Meta, "exclude", None) is None: 

636 raise ImproperlyConfigured( 

637 "Calling modelform_factory without defining 'fields' or " 

638 "'exclude' explicitly is prohibited." 

639 ) 

640 

641 # Instantiate type(form) in order to use the same metaclass as form. 

642 return type(form)(class_name, (form,), form_class_attrs) 

643 

644 

645# ModelFormSets ############################################################## 

646 

647 

648class BaseModelFormSet(BaseFormSet, AltersData): 

649 """ 

650 A ``FormSet`` for editing a queryset and/or adding new objects to it. 

651 """ 

652 

653 model = None 

654 edit_only = False 

655 

656 # Set of fields that must be unique among forms of this set. 

657 unique_fields = set() 

658 

659 def __init__( 

660 self, 

661 data=None, 

662 files=None, 

663 auto_id="id_%s", 

664 prefix=None, 

665 queryset=None, 

666 *, 

667 initial=None, 

668 **kwargs, 

669 ): 

670 self.queryset = queryset 

671 self.initial_extra = initial 

672 super().__init__( 

673 **{ 

674 "data": data, 

675 "files": files, 

676 "auto_id": auto_id, 

677 "prefix": prefix, 

678 **kwargs, 

679 } 

680 ) 

681 

682 def initial_form_count(self): 

683 """Return the number of forms that are required in this FormSet.""" 

684 if not self.is_bound: 

685 return len(self.get_queryset()) 

686 return super().initial_form_count() 

687 

688 def _existing_object(self, pk): 

689 if not hasattr(self, "_object_dict"): 

690 self._object_dict = {o.pk: o for o in self.get_queryset()} 

691 return self._object_dict.get(pk) 

692 

693 def _get_to_python(self, field): 

694 """ 

695 If the field is a related field, fetch the concrete field's (that 

696 is, the ultimate pointed-to field's) to_python. 

697 """ 

698 while field.remote_field is not None: 

699 field = field.remote_field.get_related_field() 

700 return field.to_python 

701 

702 def _construct_form(self, i, **kwargs): 

703 pk_required = i < self.initial_form_count() 

704 if pk_required: 

705 if self.is_bound: 

706 pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name) 

707 try: 

708 pk = self.data[pk_key] 

709 except KeyError: 

710 # The primary key is missing. The user may have tampered 

711 # with POST data. 

712 pass 

713 else: 

714 to_python = self._get_to_python(self.model._meta.pk) 

715 try: 

716 pk = to_python(pk) 

717 except ValidationError: 

718 # The primary key exists but is an invalid value. The 

719 # user may have tampered with POST data. 

720 pass 

721 else: 

722 kwargs["instance"] = self._existing_object(pk) 

723 else: 

724 kwargs["instance"] = self.get_queryset()[i] 

725 elif self.initial_extra: 

726 # Set initial values for extra forms 

727 try: 

728 kwargs["initial"] = self.initial_extra[i - self.initial_form_count()] 

729 except IndexError: 

730 pass 

731 form = super()._construct_form(i, **kwargs) 

732 if pk_required: 

733 form.fields[self.model._meta.pk.name].required = True 

734 return form 

735 

736 def get_queryset(self): 

737 if not hasattr(self, "_queryset"): 

738 if self.queryset is not None: 

739 qs = self.queryset 

740 else: 

741 qs = self.model._default_manager.get_queryset() 

742 

743 # If the queryset isn't already ordered we need to add an 

744 # artificial ordering here to make sure that all formsets 

745 # constructed from this queryset have the same form order. 

746 if not qs.ordered: 

747 qs = qs.order_by(self.model._meta.pk.name) 

748 

749 # Removed queryset limiting here. As per discussion re: #13023 

750 # on django-dev, max_num should not prevent existing 

751 # related objects/inlines from being displayed. 

752 self._queryset = qs 

753 return self._queryset 

754 

755 def save_new(self, form, commit=True): 

756 """Save and return a new model instance for the given form.""" 

757 return form.save(commit=commit) 

758 

759 def save_existing(self, form, instance, commit=True): 

760 """Save and return an existing model instance for the given form.""" 

761 return form.save(commit=commit) 

762 

763 def delete_existing(self, obj, commit=True): 

764 """Deletes an existing model instance.""" 

765 if commit: 

766 obj.delete() 

767 

768 def save(self, commit=True): 

769 """ 

770 Save model instances for every form, adding and changing instances 

771 as necessary, and return the list of instances. 

772 """ 

773 if not commit: 

774 self.saved_forms = [] 

775 

776 def save_m2m(): 

777 for form in self.saved_forms: 

778 form.save_m2m() 

779 

780 self.save_m2m = save_m2m 

781 if self.edit_only: 

782 return self.save_existing_objects(commit) 

783 else: 

784 return self.save_existing_objects(commit) + self.save_new_objects(commit) 

785 

786 save.alters_data = True 

787 

788 def clean(self): 

789 self.validate_unique() 

790 

791 def validate_unique(self): 

792 # Collect unique_checks and date_checks to run from all the forms. 

793 all_unique_checks = set() 

794 all_date_checks = set() 

795 forms_to_delete = self.deleted_forms 

796 valid_forms = [ 

797 form 

798 for form in self.forms 

799 if form.is_valid() and form not in forms_to_delete 

800 ] 

801 for form in valid_forms: 

802 exclude = form._get_validation_exclusions() 

803 unique_checks, date_checks = form.instance._get_unique_checks( 

804 exclude=exclude, 

805 include_meta_constraints=True, 

806 ) 

807 all_unique_checks.update(unique_checks) 

808 all_date_checks.update(date_checks) 

809 

810 errors = [] 

811 # Do each of the unique checks (unique and unique_together) 

812 for uclass, unique_check in all_unique_checks: 

813 seen_data = set() 

814 for form in valid_forms: 

815 # Get the data for the set of fields that must be unique among 

816 # the forms. 

817 row_data = ( 

818 field if field in self.unique_fields else form.cleaned_data[field] 

819 for field in unique_check 

820 if field in form.cleaned_data 

821 ) 

822 # Reduce Model instances to their primary key values 

823 row_data = tuple( 

824 d._get_pk_val() if hasattr(d, "_get_pk_val") 

825 # Prevent "unhashable type: list" errors later on. 

826 else tuple(d) if isinstance(d, list) else d 

827 for d in row_data 

828 ) 

829 if row_data and None not in row_data: 

830 # if we've already seen it then we have a uniqueness failure 

831 if row_data in seen_data: 

832 # poke error messages into the right places and mark 

833 # the form as invalid 

834 errors.append(self.get_unique_error_message(unique_check)) 

835 form._errors[NON_FIELD_ERRORS] = self.error_class( 

836 [self.get_form_error()], 

837 renderer=self.renderer, 

838 ) 

839 # Remove the data from the cleaned_data dict since it 

840 # was invalid. 

841 for field in unique_check: 

842 if field in form.cleaned_data: 

843 del form.cleaned_data[field] 

844 # mark the data as seen 

845 seen_data.add(row_data) 

846 # iterate over each of the date checks now 

847 for date_check in all_date_checks: 

848 seen_data = set() 

849 uclass, lookup, field, unique_for = date_check 

850 for form in valid_forms: 

851 # see if we have data for both fields 

852 if ( 

853 form.cleaned_data 

854 and form.cleaned_data[field] is not None 

855 and form.cleaned_data[unique_for] is not None 

856 ): 

857 # if it's a date lookup we need to get the data for all the fields 

858 if lookup == "date": 

859 date = form.cleaned_data[unique_for] 

860 date_data = (date.year, date.month, date.day) 

861 # otherwise it's just the attribute on the date/datetime 

862 # object 

863 else: 

864 date_data = (getattr(form.cleaned_data[unique_for], lookup),) 

865 data = (form.cleaned_data[field],) + date_data 

866 # if we've already seen it then we have a uniqueness failure 

867 if data in seen_data: 

868 # poke error messages into the right places and mark 

869 # the form as invalid 

870 errors.append(self.get_date_error_message(date_check)) 

871 form._errors[NON_FIELD_ERRORS] = self.error_class( 

872 [self.get_form_error()], 

873 renderer=self.renderer, 

874 ) 

875 # Remove the data from the cleaned_data dict since it 

876 # was invalid. 

877 del form.cleaned_data[field] 

878 # mark the data as seen 

879 seen_data.add(data) 

880 

881 if errors: 

882 raise ValidationError(errors) 

883 

884 def get_unique_error_message(self, unique_check): 

885 if len(unique_check) == 1: 

886 return gettext("Please correct the duplicate data for %(field)s.") % { 

887 "field": unique_check[0], 

888 } 

889 else: 

890 return gettext( 

891 "Please correct the duplicate data for %(field)s, which must be unique." 

892 ) % { 

893 "field": get_text_list(unique_check, _("and")), 

894 } 

895 

896 def get_date_error_message(self, date_check): 

897 return gettext( 

898 "Please correct the duplicate data for %(field_name)s " 

899 "which must be unique for the %(lookup)s in %(date_field)s." 

900 ) % { 

901 "field_name": date_check[2], 

902 "date_field": date_check[3], 

903 "lookup": str(date_check[1]), 

904 } 

905 

906 def get_form_error(self): 

907 return gettext("Please correct the duplicate values below.") 

908 

909 def save_existing_objects(self, commit=True): 

910 self.changed_objects = [] 

911 self.deleted_objects = [] 

912 if not self.initial_forms: 

913 return [] 

914 

915 saved_instances = [] 

916 forms_to_delete = self.deleted_forms 

917 for form in self.initial_forms: 

918 obj = form.instance 

919 # If the pk is None, it means either: 

920 # 1. The object is an unexpected empty model, created by invalid 

921 # POST data such as an object outside the formset's queryset. 

922 # 2. The object was already deleted from the database. 

923 if obj.pk is None: 

924 continue 

925 if form in forms_to_delete: 

926 self.deleted_objects.append(obj) 

927 self.delete_existing(obj, commit=commit) 

928 elif form.has_changed(): 

929 self.changed_objects.append((obj, form.changed_data)) 

930 saved_instances.append(self.save_existing(form, obj, commit=commit)) 

931 if not commit: 

932 self.saved_forms.append(form) 

933 return saved_instances 

934 

935 def save_new_objects(self, commit=True): 

936 self.new_objects = [] 

937 for form in self.extra_forms: 

938 if not form.has_changed(): 

939 continue 

940 # If someone has marked an add form for deletion, don't save the 

941 # object. 

942 if self.can_delete and self._should_delete_form(form): 

943 continue 

944 self.new_objects.append(self.save_new(form, commit=commit)) 

945 if not commit: 

946 self.saved_forms.append(form) 

947 return self.new_objects 

948 

949 def add_fields(self, form, index): 

950 """Add a hidden field for the object's primary key.""" 

951 from django.db.models import AutoField, ForeignKey, OneToOneField 

952 

953 self._pk_field = pk = self.model._meta.pk 

954 # If a pk isn't editable, then it won't be on the form, so we need to 

955 # add it here so we can tell which object is which when we get the 

956 # data back. Generally, pk.editable should be false, but for some 

957 # reason, auto_created pk fields and AutoField's editable attribute is 

958 # True, so check for that as well. 

959 

960 def pk_is_not_editable(pk): 

961 return ( 

962 (not pk.editable) 

963 or (pk.auto_created or isinstance(pk, AutoField)) 

964 or ( 

965 pk.remote_field 

966 and pk.remote_field.parent_link 

967 and pk_is_not_editable(pk.remote_field.model._meta.pk) 

968 ) 

969 ) 

970 

971 if pk_is_not_editable(pk) or pk.name not in form.fields: 

972 if form.is_bound: 

973 # If we're adding the related instance, ignore its primary key 

974 # as it could be an auto-generated default which isn't actually 

975 # in the database. 

976 pk_value = None if form.instance._state.adding else form.instance.pk 

977 else: 

978 try: 

979 if index is not None: 

980 pk_value = self.get_queryset()[index].pk 

981 else: 

982 pk_value = None 

983 except IndexError: 

984 pk_value = None 

985 if isinstance(pk, (ForeignKey, OneToOneField)): 

986 qs = pk.remote_field.model._default_manager.get_queryset() 

987 else: 

988 qs = self.model._default_manager.get_queryset() 

989 qs = qs.using(form.instance._state.db) 

990 if form._meta.widgets: 

991 widget = form._meta.widgets.get(self._pk_field.name, HiddenInput) 

992 else: 

993 widget = HiddenInput 

994 form.fields[self._pk_field.name] = ModelChoiceField( 

995 qs, initial=pk_value, required=False, widget=widget 

996 ) 

997 super().add_fields(form, index) 

998 

999 

1000def modelformset_factory( 

1001 model, 

1002 form=ModelForm, 

1003 formfield_callback=None, 

1004 formset=BaseModelFormSet, 

1005 extra=1, 

1006 can_delete=False, 

1007 can_order=False, 

1008 max_num=None, 

1009 fields=None, 

1010 exclude=None, 

1011 widgets=None, 

1012 validate_max=False, 

1013 localized_fields=None, 

1014 labels=None, 

1015 help_texts=None, 

1016 error_messages=None, 

1017 min_num=None, 

1018 validate_min=False, 

1019 field_classes=None, 

1020 absolute_max=None, 

1021 can_delete_extra=True, 

1022 renderer=None, 

1023 edit_only=False, 

1024): 

1025 """Return a FormSet class for the given Django model class.""" 

1026 meta = getattr(form, "Meta", None) 

1027 if ( 

1028 getattr(meta, "fields", fields) is None 

1029 and getattr(meta, "exclude", exclude) is None 

1030 ): 

1031 raise ImproperlyConfigured( 

1032 "Calling modelformset_factory without defining 'fields' or " 

1033 "'exclude' explicitly is prohibited." 

1034 ) 

1035 

1036 form = modelform_factory( 

1037 model, 

1038 form=form, 

1039 fields=fields, 

1040 exclude=exclude, 

1041 formfield_callback=formfield_callback, 

1042 widgets=widgets, 

1043 localized_fields=localized_fields, 

1044 labels=labels, 

1045 help_texts=help_texts, 

1046 error_messages=error_messages, 

1047 field_classes=field_classes, 

1048 ) 

1049 FormSet = formset_factory( 

1050 form, 

1051 formset, 

1052 extra=extra, 

1053 min_num=min_num, 

1054 max_num=max_num, 

1055 can_order=can_order, 

1056 can_delete=can_delete, 

1057 validate_min=validate_min, 

1058 validate_max=validate_max, 

1059 absolute_max=absolute_max, 

1060 can_delete_extra=can_delete_extra, 

1061 renderer=renderer, 

1062 ) 

1063 FormSet.model = model 

1064 FormSet.edit_only = edit_only 

1065 return FormSet 

1066 

1067 

1068# InlineFormSets ############################################################# 

1069 

1070 

1071class BaseInlineFormSet(BaseModelFormSet): 

1072 """A formset for child objects related to a parent.""" 

1073 

1074 def __init__( 

1075 self, 

1076 data=None, 

1077 files=None, 

1078 instance=None, 

1079 save_as_new=False, 

1080 prefix=None, 

1081 queryset=None, 

1082 **kwargs, 

1083 ): 

1084 if instance is None: 

1085 self.instance = self.fk.remote_field.model() 

1086 else: 

1087 self.instance = instance 

1088 self.save_as_new = save_as_new 

1089 if queryset is None: 

1090 queryset = self.model._default_manager 

1091 if self.instance.pk is not None: 

1092 qs = queryset.filter(**{self.fk.name: self.instance}) 

1093 else: 

1094 qs = queryset.none() 

1095 self.unique_fields = {self.fk.name} 

1096 super().__init__(data, files, prefix=prefix, queryset=qs, **kwargs) 

1097 

1098 # Add the generated field to form._meta.fields if it's defined to make 

1099 # sure validation isn't skipped on that field. 

1100 if self.form._meta.fields and self.fk.name not in self.form._meta.fields: 

1101 if isinstance(self.form._meta.fields, tuple): 

1102 self.form._meta.fields = list(self.form._meta.fields) 

1103 self.form._meta.fields.append(self.fk.name) 

1104 

1105 def initial_form_count(self): 

1106 if self.save_as_new: 

1107 return 0 

1108 return super().initial_form_count() 

1109 

1110 def _construct_form(self, i, **kwargs): 

1111 form = super()._construct_form(i, **kwargs) 

1112 if self.save_as_new: 

1113 mutable = getattr(form.data, "_mutable", None) 

1114 # Allow modifying an immutable QueryDict. 

1115 if mutable is not None: 

1116 form.data._mutable = True 

1117 # Remove the primary key from the form's data, we are only 

1118 # creating new instances 

1119 form.data[form.add_prefix(self._pk_field.name)] = None 

1120 # Remove the foreign key from the form's data 

1121 form.data[form.add_prefix(self.fk.name)] = None 

1122 if mutable is not None: 

1123 form.data._mutable = mutable 

1124 

1125 # Set the fk value here so that the form can do its validation. 

1126 fk_value = self.instance.pk 

1127 if self.fk.remote_field.field_name != self.fk.remote_field.model._meta.pk.name: 

1128 fk_value = getattr(self.instance, self.fk.remote_field.field_name) 

1129 fk_value = getattr(fk_value, "pk", fk_value) 

1130 setattr(form.instance, self.fk.get_attname(), fk_value) 

1131 return form 

1132 

1133 @classmethod 

1134 def get_default_prefix(cls): 

1135 return cls.fk.remote_field.get_accessor_name(model=cls.model).replace("+", "") 

1136 

1137 def save_new(self, form, commit=True): 

1138 # Ensure the latest copy of the related instance is present on each 

1139 # form (it may have been saved after the formset was originally 

1140 # instantiated). 

1141 setattr(form.instance, self.fk.name, self.instance) 

1142 return super().save_new(form, commit=commit) 

1143 

1144 def add_fields(self, form, index): 

1145 super().add_fields(form, index) 

1146 if self._pk_field == self.fk: 

1147 name = self._pk_field.name 

1148 kwargs = {"pk_field": True} 

1149 else: 

1150 # The foreign key field might not be on the form, so we poke at the 

1151 # Model field to get the label, since we need that for error messages. 

1152 name = self.fk.name 

1153 kwargs = { 

1154 "label": getattr( 

1155 form.fields.get(name), "label", capfirst(self.fk.verbose_name) 

1156 ) 

1157 } 

1158 

1159 # The InlineForeignKeyField assumes that the foreign key relation is 

1160 # based on the parent model's pk. If this isn't the case, set to_field 

1161 # to correctly resolve the initial form value. 

1162 if self.fk.remote_field.field_name != self.fk.remote_field.model._meta.pk.name: 

1163 kwargs["to_field"] = self.fk.remote_field.field_name 

1164 

1165 # If we're adding a new object, ignore a parent's auto-generated key 

1166 # as it will be regenerated on the save request. 

1167 if self.instance._state.adding: 

1168 if kwargs.get("to_field") is not None: 

1169 to_field = self.instance._meta.get_field(kwargs["to_field"]) 

1170 else: 

1171 to_field = self.instance._meta.pk 

1172 if to_field.has_default(): 

1173 setattr(self.instance, to_field.attname, None) 

1174 

1175 form.fields[name] = InlineForeignKeyField(self.instance, **kwargs) 

1176 

1177 def get_unique_error_message(self, unique_check): 

1178 unique_check = [field for field in unique_check if field != self.fk.name] 

1179 return super().get_unique_error_message(unique_check) 

1180 

1181 

1182def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False): 

1183 """ 

1184 Find and return the ForeignKey from model to parent if there is one 

1185 (return None if can_fail is True and no such field exists). If fk_name is 

1186 provided, assume it is the name of the ForeignKey field. Unless can_fail is 

1187 True, raise an exception if there isn't a ForeignKey from model to 

1188 parent_model. 

1189 """ 

1190 # avoid circular import 

1191 from django.db.models import ForeignKey 

1192 

1193 opts = model._meta 

1194 if fk_name: 

1195 fks_to_parent = [f for f in opts.fields if f.name == fk_name] 

1196 if len(fks_to_parent) == 1: 

1197 fk = fks_to_parent[0] 

1198 parent_list = parent_model._meta.get_parent_list() 

1199 if ( 

1200 not isinstance(fk, ForeignKey) 

1201 or ( 

1202 # ForeignKey to proxy models. 

1203 fk.remote_field.model._meta.proxy 

1204 and fk.remote_field.model._meta.proxy_for_model not in parent_list 

1205 ) 

1206 or ( 

1207 # ForeignKey to concrete models. 

1208 not fk.remote_field.model._meta.proxy 

1209 and fk.remote_field.model != parent_model 

1210 and fk.remote_field.model not in parent_list 

1211 ) 

1212 ): 

1213 raise ValueError( 

1214 "fk_name '%s' is not a ForeignKey to '%s'." 

1215 % (fk_name, parent_model._meta.label) 

1216 ) 

1217 elif not fks_to_parent: 

1218 raise ValueError( 

1219 "'%s' has no field named '%s'." % (model._meta.label, fk_name) 

1220 ) 

1221 else: 

1222 # Try to discover what the ForeignKey from model to parent_model is 

1223 parent_list = parent_model._meta.get_parent_list() 

1224 fks_to_parent = [ 

1225 f 

1226 for f in opts.fields 

1227 if isinstance(f, ForeignKey) 

1228 and ( 

1229 f.remote_field.model == parent_model 

1230 or f.remote_field.model in parent_list 

1231 or ( 

1232 f.remote_field.model._meta.proxy 

1233 and f.remote_field.model._meta.proxy_for_model in parent_list 

1234 ) 

1235 ) 

1236 ] 

1237 if len(fks_to_parent) == 1: 

1238 fk = fks_to_parent[0] 

1239 elif not fks_to_parent: 

1240 if can_fail: 

1241 return 

1242 raise ValueError( 

1243 "'%s' has no ForeignKey to '%s'." 

1244 % ( 

1245 model._meta.label, 

1246 parent_model._meta.label, 

1247 ) 

1248 ) 

1249 else: 

1250 raise ValueError( 

1251 "'%s' has more than one ForeignKey to '%s'. You must specify " 

1252 "a 'fk_name' attribute." 

1253 % ( 

1254 model._meta.label, 

1255 parent_model._meta.label, 

1256 ) 

1257 ) 

1258 return fk 

1259 

1260 

1261def inlineformset_factory( 

1262 parent_model, 

1263 model, 

1264 form=ModelForm, 

1265 formset=BaseInlineFormSet, 

1266 fk_name=None, 

1267 fields=None, 

1268 exclude=None, 

1269 extra=3, 

1270 can_order=False, 

1271 can_delete=True, 

1272 max_num=None, 

1273 formfield_callback=None, 

1274 widgets=None, 

1275 validate_max=False, 

1276 localized_fields=None, 

1277 labels=None, 

1278 help_texts=None, 

1279 error_messages=None, 

1280 min_num=None, 

1281 validate_min=False, 

1282 field_classes=None, 

1283 absolute_max=None, 

1284 can_delete_extra=True, 

1285 renderer=None, 

1286 edit_only=False, 

1287): 

1288 """ 

1289 Return an ``InlineFormSet`` for the given kwargs. 

1290 

1291 ``fk_name`` must be provided if ``model`` has more than one ``ForeignKey`` 

1292 to ``parent_model``. 

1293 """ 

1294 fk = _get_foreign_key(parent_model, model, fk_name=fk_name) 

1295 # enforce a max_num=1 when the foreign key to the parent model is unique. 

1296 if fk.unique: 

1297 max_num = 1 

1298 kwargs = { 

1299 "form": form, 

1300 "formfield_callback": formfield_callback, 

1301 "formset": formset, 

1302 "extra": extra, 

1303 "can_delete": can_delete, 

1304 "can_order": can_order, 

1305 "fields": fields, 

1306 "exclude": exclude, 

1307 "min_num": min_num, 

1308 "max_num": max_num, 

1309 "widgets": widgets, 

1310 "validate_min": validate_min, 

1311 "validate_max": validate_max, 

1312 "localized_fields": localized_fields, 

1313 "labels": labels, 

1314 "help_texts": help_texts, 

1315 "error_messages": error_messages, 

1316 "field_classes": field_classes, 

1317 "absolute_max": absolute_max, 

1318 "can_delete_extra": can_delete_extra, 

1319 "renderer": renderer, 

1320 "edit_only": edit_only, 

1321 } 

1322 FormSet = modelformset_factory(model, **kwargs) 

1323 FormSet.fk = fk 

1324 return FormSet 

1325 

1326 

1327# Fields ##################################################################### 

1328 

1329 

1330class InlineForeignKeyField(Field): 

1331 """ 

1332 A basic integer field that deals with validating the given value to a 

1333 given parent instance in an inline. 

1334 """ 

1335 

1336 widget = HiddenInput 

1337 default_error_messages = { 

1338 "invalid_choice": _("The inline value did not match the parent instance."), 

1339 } 

1340 

1341 def __init__(self, parent_instance, *args, pk_field=False, to_field=None, **kwargs): 

1342 self.parent_instance = parent_instance 

1343 self.pk_field = pk_field 

1344 self.to_field = to_field 

1345 if self.parent_instance is not None: 

1346 if self.to_field: 

1347 kwargs["initial"] = getattr(self.parent_instance, self.to_field) 

1348 else: 

1349 kwargs["initial"] = self.parent_instance.pk 

1350 kwargs["required"] = False 

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

1352 

1353 def clean(self, value): 

1354 if value in self.empty_values: 

1355 if self.pk_field: 

1356 return None 

1357 # if there is no value act as we did before. 

1358 return self.parent_instance 

1359 # ensure the we compare the values as equal types. 

1360 if self.to_field: 

1361 orig = getattr(self.parent_instance, self.to_field) 

1362 else: 

1363 orig = self.parent_instance.pk 

1364 if str(value) != str(orig): 

1365 raise ValidationError( 

1366 self.error_messages["invalid_choice"], code="invalid_choice" 

1367 ) 

1368 return self.parent_instance 

1369 

1370 def has_changed(self, initial, data): 

1371 return False 

1372 

1373 

1374class ModelChoiceIteratorValue: 

1375 def __init__(self, value, instance): 

1376 self.value = value 

1377 self.instance = instance 

1378 

1379 def __str__(self): 

1380 return str(self.value) 

1381 

1382 def __hash__(self): 

1383 return hash(self.value) 

1384 

1385 def __eq__(self, other): 

1386 if isinstance(other, ModelChoiceIteratorValue): 

1387 other = other.value 

1388 return self.value == other 

1389 

1390 

1391class ModelChoiceIterator: 

1392 def __init__(self, field): 

1393 self.field = field 

1394 self.queryset = field.queryset 

1395 

1396 def __iter__(self): 

1397 if self.field.empty_label is not None: 

1398 yield ("", self.field.empty_label) 

1399 queryset = self.queryset 

1400 # Can't use iterator() when queryset uses prefetch_related() 

1401 if not queryset._prefetch_related_lookups: 

1402 queryset = queryset.iterator() 

1403 for obj in queryset: 

1404 yield self.choice(obj) 

1405 

1406 def __len__(self): 

1407 # count() adds a query but uses less memory since the QuerySet results 

1408 # won't be cached. In most cases, the choices will only be iterated on, 

1409 # and __len__() won't be called. 

1410 return self.queryset.count() + (1 if self.field.empty_label is not None else 0) 

1411 

1412 def __bool__(self): 

1413 return self.field.empty_label is not None or self.queryset.exists() 

1414 

1415 def choice(self, obj): 

1416 return ( 

1417 ModelChoiceIteratorValue(self.field.prepare_value(obj), obj), 

1418 self.field.label_from_instance(obj), 

1419 ) 

1420 

1421 

1422class ModelChoiceField(ChoiceField): 

1423 """A ChoiceField whose choices are a model QuerySet.""" 

1424 

1425 # This class is a subclass of ChoiceField for purity, but it doesn't 

1426 # actually use any of ChoiceField's implementation. 

1427 default_error_messages = { 

1428 "invalid_choice": _( 

1429 "Select a valid choice. That choice is not one of the available choices." 

1430 ), 

1431 } 

1432 iterator = ModelChoiceIterator 

1433 

1434 def __init__( 

1435 self, 

1436 queryset, 

1437 *, 

1438 empty_label="---------", 

1439 required=True, 

1440 widget=None, 

1441 label=None, 

1442 initial=None, 

1443 help_text="", 

1444 to_field_name=None, 

1445 limit_choices_to=None, 

1446 blank=False, 

1447 **kwargs, 

1448 ): 

1449 # Call Field instead of ChoiceField __init__() because we don't need 

1450 # ChoiceField.__init__(). 

1451 Field.__init__( 

1452 self, 

1453 required=required, 

1454 widget=widget, 

1455 label=label, 

1456 initial=initial, 

1457 help_text=help_text, 

1458 **kwargs, 

1459 ) 

1460 if (required and initial is not None) or ( 

1461 isinstance(self.widget, RadioSelect) and not blank 

1462 ): 

1463 self.empty_label = None 

1464 else: 

1465 self.empty_label = empty_label 

1466 self.queryset = queryset 

1467 self.limit_choices_to = limit_choices_to # limit the queryset later. 

1468 self.to_field_name = to_field_name 

1469 

1470 def get_limit_choices_to(self): 

1471 """ 

1472 Return ``limit_choices_to`` for this form field. 

1473 

1474 If it is a callable, invoke it and return the result. 

1475 """ 

1476 if callable(self.limit_choices_to): 

1477 return self.limit_choices_to() 

1478 return self.limit_choices_to 

1479 

1480 def __deepcopy__(self, memo): 

1481 result = super(ChoiceField, self).__deepcopy__(memo) 

1482 # Need to force a new ModelChoiceIterator to be created, bug #11183 

1483 if self.queryset is not None: 

1484 result.queryset = self.queryset.all() 

1485 return result 

1486 

1487 def _get_queryset(self): 

1488 return self._queryset 

1489 

1490 def _set_queryset(self, queryset): 

1491 self._queryset = None if queryset is None else queryset.all() 

1492 self.widget.choices = self.choices 

1493 

1494 queryset = property(_get_queryset, _set_queryset) 

1495 

1496 # this method will be used to create object labels by the QuerySetIterator. 

1497 # Override it to customize the label. 

1498 def label_from_instance(self, obj): 

1499 """ 

1500 Convert objects into strings and generate the labels for the choices 

1501 presented by this object. Subclasses can override this method to 

1502 customize the display of the choices. 

1503 """ 

1504 return str(obj) 

1505 

1506 def _get_choices(self): 

1507 # If self._choices is set, then somebody must have manually set 

1508 # the property self.choices. In this case, just return self._choices. 

1509 if hasattr(self, "_choices"): 

1510 return self._choices 

1511 

1512 # Otherwise, execute the QuerySet in self.queryset to determine the 

1513 # choices dynamically. Return a fresh ModelChoiceIterator that has not been 

1514 # consumed. Note that we're instantiating a new ModelChoiceIterator *each* 

1515 # time _get_choices() is called (and, thus, each time self.choices is 

1516 # accessed) so that we can ensure the QuerySet has not been consumed. This 

1517 # construct might look complicated but it allows for lazy evaluation of 

1518 # the queryset. 

1519 return self.iterator(self) 

1520 

1521 choices = property(_get_choices, ChoiceField._set_choices) 

1522 

1523 def prepare_value(self, value): 

1524 if hasattr(value, "_meta"): 

1525 if self.to_field_name: 

1526 return value.serializable_value(self.to_field_name) 

1527 else: 

1528 return value.pk 

1529 return super().prepare_value(value) 

1530 

1531 def to_python(self, value): 

1532 if value in self.empty_values: 

1533 return None 

1534 try: 

1535 key = self.to_field_name or "pk" 

1536 if isinstance(value, self.queryset.model): 

1537 value = getattr(value, key) 

1538 value = self.queryset.get(**{key: value}) 

1539 except (ValueError, TypeError, self.queryset.model.DoesNotExist): 

1540 raise ValidationError( 

1541 self.error_messages["invalid_choice"], 

1542 code="invalid_choice", 

1543 params={"value": value}, 

1544 ) 

1545 return value 

1546 

1547 def validate(self, value): 

1548 return Field.validate(self, value) 

1549 

1550 def has_changed(self, initial, data): 

1551 if self.disabled: 

1552 return False 

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

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

1555 return str(self.prepare_value(initial_value)) != str(data_value) 

1556 

1557 

1558class ModelMultipleChoiceField(ModelChoiceField): 

1559 """A MultipleChoiceField whose choices are a model QuerySet.""" 

1560 

1561 widget = SelectMultiple 

1562 hidden_widget = MultipleHiddenInput 

1563 default_error_messages = { 

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

1565 "invalid_choice": _( 

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

1567 ), 

1568 "invalid_pk_value": _("“%(pk)s” is not a valid value."), 

1569 } 

1570 

1571 def __init__(self, queryset, **kwargs): 

1572 super().__init__(queryset, empty_label=None, **kwargs) 

1573 

1574 def to_python(self, value): 

1575 if not value: 

1576 return [] 

1577 return list(self._check_values(value)) 

1578 

1579 def clean(self, value): 

1580 value = self.prepare_value(value) 

1581 if self.required and not value: 

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

1583 elif not self.required and not value: 

1584 return self.queryset.none() 

1585 if not isinstance(value, (list, tuple)): 

1586 raise ValidationError( 

1587 self.error_messages["invalid_list"], 

1588 code="invalid_list", 

1589 ) 

1590 qs = self._check_values(value) 

1591 # Since this overrides the inherited ModelChoiceField.clean 

1592 # we run custom validators here 

1593 self.run_validators(value) 

1594 return qs 

1595 

1596 def _check_values(self, value): 

1597 """ 

1598 Given a list of possible PK values, return a QuerySet of the 

1599 corresponding objects. Raise a ValidationError if a given value is 

1600 invalid (not a valid PK, not in the queryset, etc.) 

1601 """ 

1602 key = self.to_field_name or "pk" 

1603 # deduplicate given values to avoid creating many querysets or 

1604 # requiring the database backend deduplicate efficiently. 

1605 try: 

1606 value = frozenset(value) 

1607 except TypeError: 

1608 # list of lists isn't hashable, for example 

1609 raise ValidationError( 

1610 self.error_messages["invalid_list"], 

1611 code="invalid_list", 

1612 ) 

1613 for pk in value: 

1614 try: 

1615 self.queryset.filter(**{key: pk}) 

1616 except (ValueError, TypeError): 

1617 raise ValidationError( 

1618 self.error_messages["invalid_pk_value"], 

1619 code="invalid_pk_value", 

1620 params={"pk": pk}, 

1621 ) 

1622 qs = self.queryset.filter(**{"%s__in" % key: value}) 

1623 pks = {str(getattr(o, key)) for o in qs} 

1624 for val in value: 

1625 if str(val) not in pks: 

1626 raise ValidationError( 

1627 self.error_messages["invalid_choice"], 

1628 code="invalid_choice", 

1629 params={"value": val}, 

1630 ) 

1631 return qs 

1632 

1633 def prepare_value(self, value): 

1634 if ( 

1635 hasattr(value, "__iter__") 

1636 and not isinstance(value, str) 

1637 and not hasattr(value, "_meta") 

1638 ): 

1639 prepare_value = super().prepare_value 

1640 return [prepare_value(v) for v in value] 

1641 return super().prepare_value(value) 

1642 

1643 def has_changed(self, initial, data): 

1644 if self.disabled: 

1645 return False 

1646 if initial is None: 

1647 initial = [] 

1648 if data is None: 

1649 data = [] 

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

1651 return True 

1652 initial_set = {str(value) for value in self.prepare_value(initial)} 

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

1654 return data_set != initial_set 

1655 

1656 

1657def modelform_defines_fields(form_class): 

1658 return hasattr(form_class, "_meta") and ( 

1659 form_class._meta.fields is not None or form_class._meta.exclude is not None 

1660 )