Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/django/db/models/fields/related.py: 25%

760 statements  

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

1import functools 

2import inspect 

3from functools import partial 

4 

5from django import forms 

6from django.apps import apps 

7from django.conf import SettingsReference, settings 

8from django.core import checks, exceptions 

9from django.db import connection, router 

10from django.db.backends import utils 

11from django.db.models import Q 

12from django.db.models.constants import LOOKUP_SEP 

13from django.db.models.deletion import CASCADE, SET_DEFAULT, SET_NULL 

14from django.db.models.query_utils import PathInfo 

15from django.db.models.utils import make_model_tuple 

16from django.utils.functional import cached_property 

17from django.utils.translation import gettext_lazy as _ 

18 

19from . import Field 

20from .mixins import FieldCacheMixin 

21from .related_descriptors import ( 

22 ForeignKeyDeferredAttribute, 

23 ForwardManyToOneDescriptor, 

24 ForwardOneToOneDescriptor, 

25 ManyToManyDescriptor, 

26 ReverseManyToOneDescriptor, 

27 ReverseOneToOneDescriptor, 

28) 

29from .related_lookups import ( 

30 RelatedExact, 

31 RelatedGreaterThan, 

32 RelatedGreaterThanOrEqual, 

33 RelatedIn, 

34 RelatedIsNull, 

35 RelatedLessThan, 

36 RelatedLessThanOrEqual, 

37) 

38from .reverse_related import ForeignObjectRel, ManyToManyRel, ManyToOneRel, OneToOneRel 

39 

40RECURSIVE_RELATIONSHIP_CONSTANT = "self" 

41 

42 

43def resolve_relation(scope_model, relation): 

44 """ 

45 Transform relation into a model or fully-qualified model string of the form 

46 "app_label.ModelName", relative to scope_model. 

47 

48 The relation argument can be: 

49 * RECURSIVE_RELATIONSHIP_CONSTANT, i.e. the string "self", in which case 

50 the model argument will be returned. 

51 * A bare model name without an app_label, in which case scope_model's 

52 app_label will be prepended. 

53 * An "app_label.ModelName" string. 

54 * A model class, which will be returned unchanged. 

55 """ 

56 # Check for recursive relations 

57 if relation == RECURSIVE_RELATIONSHIP_CONSTANT: 

58 relation = scope_model 

59 

60 # Look for an "app.Model" relation 

61 if isinstance(relation, str): 

62 if "." not in relation: 

63 relation = "%s.%s" % (scope_model._meta.app_label, relation) 

64 

65 return relation 

66 

67 

68def lazy_related_operation(function, model, *related_models, **kwargs): 

69 """ 

70 Schedule `function` to be called once `model` and all `related_models` 

71 have been imported and registered with the app registry. `function` will 

72 be called with the newly-loaded model classes as its positional arguments, 

73 plus any optional keyword arguments. 

74 

75 The `model` argument must be a model class. Each subsequent positional 

76 argument is another model, or a reference to another model - see 

77 `resolve_relation()` for the various forms these may take. Any relative 

78 references will be resolved relative to `model`. 

79 

80 This is a convenience wrapper for `Apps.lazy_model_operation` - the app 

81 registry model used is the one found in `model._meta.apps`. 

82 """ 

83 models = [model] + [resolve_relation(model, rel) for rel in related_models] 

84 model_keys = (make_model_tuple(m) for m in models) 

85 apps = model._meta.apps 

86 return apps.lazy_model_operation(partial(function, **kwargs), *model_keys) 

87 

88 

89class RelatedField(FieldCacheMixin, Field): 

90 """Base class that all relational fields inherit from.""" 

91 

92 # Field flags 

93 one_to_many = False 

94 one_to_one = False 

95 many_to_many = False 

96 many_to_one = False 

97 

98 def __init__( 

99 self, 

100 related_name=None, 

101 related_query_name=None, 

102 limit_choices_to=None, 

103 **kwargs, 

104 ): 

105 self._related_name = related_name 

106 self._related_query_name = related_query_name 

107 self._limit_choices_to = limit_choices_to 

108 super().__init__(**kwargs) 

109 

110 @cached_property 

111 def related_model(self): 

112 # Can't cache this property until all the models are loaded. 

113 apps.check_models_ready() 

114 return self.remote_field.model 

115 

116 def check(self, **kwargs): 

117 return [ 

118 *super().check(**kwargs), 

119 *self._check_related_name_is_valid(), 

120 *self._check_related_query_name_is_valid(), 

121 *self._check_relation_model_exists(), 

122 *self._check_referencing_to_swapped_model(), 

123 *self._check_clashes(), 

124 ] 

125 

126 def _check_related_name_is_valid(self): 

127 import keyword 

128 

129 related_name = self.remote_field.related_name 

130 if related_name is None: 

131 return [] 

132 is_valid_id = ( 

133 not keyword.iskeyword(related_name) and related_name.isidentifier() 

134 ) 

135 if not (is_valid_id or related_name.endswith("+")): 

136 return [ 

137 checks.Error( 

138 "The name '%s' is invalid related_name for field %s.%s" 

139 % ( 

140 self.remote_field.related_name, 

141 self.model._meta.object_name, 

142 self.name, 

143 ), 

144 hint=( 

145 "Related name must be a valid Python identifier or end with a " 

146 "'+'" 

147 ), 

148 obj=self, 

149 id="fields.E306", 

150 ) 

151 ] 

152 return [] 

153 

154 def _check_related_query_name_is_valid(self): 

155 if self.remote_field.is_hidden(): 

156 return [] 

157 rel_query_name = self.related_query_name() 

158 errors = [] 

159 if rel_query_name.endswith("_"): 

160 errors.append( 

161 checks.Error( 

162 "Reverse query name '%s' must not end with an underscore." 

163 % rel_query_name, 

164 hint=( 

165 "Add or change a related_name or related_query_name " 

166 "argument for this field." 

167 ), 

168 obj=self, 

169 id="fields.E308", 

170 ) 

171 ) 

172 if LOOKUP_SEP in rel_query_name: 

173 errors.append( 

174 checks.Error( 

175 "Reverse query name '%s' must not contain '%s'." 

176 % (rel_query_name, LOOKUP_SEP), 

177 hint=( 

178 "Add or change a related_name or related_query_name " 

179 "argument for this field." 

180 ), 

181 obj=self, 

182 id="fields.E309", 

183 ) 

184 ) 

185 return errors 

186 

187 def _check_relation_model_exists(self): 

188 rel_is_missing = self.remote_field.model not in self.opts.apps.get_models() 

189 rel_is_string = isinstance(self.remote_field.model, str) 

190 model_name = ( 

191 self.remote_field.model 

192 if rel_is_string 

193 else self.remote_field.model._meta.object_name 

194 ) 

195 if rel_is_missing and ( 

196 rel_is_string or not self.remote_field.model._meta.swapped 

197 ): 

198 return [ 

199 checks.Error( 

200 "Field defines a relation with model '%s', which is either " 

201 "not installed, or is abstract." % model_name, 

202 obj=self, 

203 id="fields.E300", 

204 ) 

205 ] 

206 return [] 

207 

208 def _check_referencing_to_swapped_model(self): 

209 if ( 

210 self.remote_field.model not in self.opts.apps.get_models() 

211 and not isinstance(self.remote_field.model, str) 

212 and self.remote_field.model._meta.swapped 

213 ): 

214 return [ 

215 checks.Error( 

216 "Field defines a relation with the model '%s', which has " 

217 "been swapped out." % self.remote_field.model._meta.label, 

218 hint="Update the relation to point at 'settings.%s'." 

219 % self.remote_field.model._meta.swappable, 

220 obj=self, 

221 id="fields.E301", 

222 ) 

223 ] 

224 return [] 

225 

226 def _check_clashes(self): 

227 """Check accessor and reverse query name clashes.""" 

228 from django.db.models.base import ModelBase 

229 

230 errors = [] 

231 opts = self.model._meta 

232 

233 # f.remote_field.model may be a string instead of a model. Skip if 

234 # model name is not resolved. 

235 if not isinstance(self.remote_field.model, ModelBase): 

236 return [] 

237 

238 # Consider that we are checking field `Model.foreign` and the models 

239 # are: 

240 # 

241 # class Target(models.Model): 

242 # model = models.IntegerField() 

243 # model_set = models.IntegerField() 

244 # 

245 # class Model(models.Model): 

246 # foreign = models.ForeignKey(Target) 

247 # m2m = models.ManyToManyField(Target) 

248 

249 # rel_opts.object_name == "Target" 

250 rel_opts = self.remote_field.model._meta 

251 # If the field doesn't install a backward relation on the target model 

252 # (so `is_hidden` returns True), then there are no clashes to check 

253 # and we can skip these fields. 

254 rel_is_hidden = self.remote_field.is_hidden() 

255 rel_name = self.remote_field.get_accessor_name() # i. e. "model_set" 

256 rel_query_name = self.related_query_name() # i. e. "model" 

257 # i.e. "app_label.Model.field". 

258 field_name = "%s.%s" % (opts.label, self.name) 

259 

260 # Check clashes between accessor or reverse query name of `field` 

261 # and any other field name -- i.e. accessor for Model.foreign is 

262 # model_set and it clashes with Target.model_set. 

263 potential_clashes = rel_opts.fields + rel_opts.many_to_many 

264 for clash_field in potential_clashes: 

265 # i.e. "app_label.Target.model_set". 

266 clash_name = "%s.%s" % (rel_opts.label, clash_field.name) 

267 if not rel_is_hidden and clash_field.name == rel_name: 

268 errors.append( 

269 checks.Error( 

270 f"Reverse accessor '{rel_opts.object_name}.{rel_name}' " 

271 f"for '{field_name}' clashes with field name " 

272 f"'{clash_name}'.", 

273 hint=( 

274 "Rename field '%s', or add/change a related_name " 

275 "argument to the definition for field '%s'." 

276 ) 

277 % (clash_name, field_name), 

278 obj=self, 

279 id="fields.E302", 

280 ) 

281 ) 

282 

283 if clash_field.name == rel_query_name: 

284 errors.append( 

285 checks.Error( 

286 "Reverse query name for '%s' clashes with field name '%s'." 

287 % (field_name, clash_name), 

288 hint=( 

289 "Rename field '%s', or add/change a related_name " 

290 "argument to the definition for field '%s'." 

291 ) 

292 % (clash_name, field_name), 

293 obj=self, 

294 id="fields.E303", 

295 ) 

296 ) 

297 

298 # Check clashes between accessors/reverse query names of `field` and 

299 # any other field accessor -- i. e. Model.foreign accessor clashes with 

300 # Model.m2m accessor. 

301 potential_clashes = (r for r in rel_opts.related_objects if r.field is not self) 

302 for clash_field in potential_clashes: 

303 # i.e. "app_label.Model.m2m". 

304 clash_name = "%s.%s" % ( 

305 clash_field.related_model._meta.label, 

306 clash_field.field.name, 

307 ) 

308 if not rel_is_hidden and clash_field.get_accessor_name() == rel_name: 

309 errors.append( 

310 checks.Error( 

311 f"Reverse accessor '{rel_opts.object_name}.{rel_name}' " 

312 f"for '{field_name}' clashes with reverse accessor for " 

313 f"'{clash_name}'.", 

314 hint=( 

315 "Add or change a related_name argument " 

316 "to the definition for '%s' or '%s'." 

317 ) 

318 % (field_name, clash_name), 

319 obj=self, 

320 id="fields.E304", 

321 ) 

322 ) 

323 

324 if clash_field.get_accessor_name() == rel_query_name: 

325 errors.append( 

326 checks.Error( 

327 "Reverse query name for '%s' clashes with reverse query name " 

328 "for '%s'." % (field_name, clash_name), 

329 hint=( 

330 "Add or change a related_name argument " 

331 "to the definition for '%s' or '%s'." 

332 ) 

333 % (field_name, clash_name), 

334 obj=self, 

335 id="fields.E305", 

336 ) 

337 ) 

338 

339 return errors 

340 

341 def db_type(self, connection): 

342 # By default related field will not have a column as it relates to 

343 # columns from another table. 

344 return None 

345 

346 def contribute_to_class(self, cls, name, private_only=False, **kwargs): 

347 

348 super().contribute_to_class(cls, name, private_only=private_only, **kwargs) 

349 

350 self.opts = cls._meta 

351 

352 if not cls._meta.abstract: 

353 if self.remote_field.related_name: 

354 related_name = self.remote_field.related_name 

355 else: 

356 related_name = self.opts.default_related_name 

357 if related_name: 

358 related_name %= { 

359 "class": cls.__name__.lower(), 

360 "model_name": cls._meta.model_name.lower(), 

361 "app_label": cls._meta.app_label.lower(), 

362 } 

363 self.remote_field.related_name = related_name 

364 

365 if self.remote_field.related_query_name: 

366 related_query_name = self.remote_field.related_query_name % { 

367 "class": cls.__name__.lower(), 

368 "app_label": cls._meta.app_label.lower(), 

369 } 

370 self.remote_field.related_query_name = related_query_name 

371 

372 def resolve_related_class(model, related, field): 

373 field.remote_field.model = related 

374 field.do_related_class(related, model) 

375 

376 lazy_related_operation( 

377 resolve_related_class, cls, self.remote_field.model, field=self 

378 ) 

379 

380 def deconstruct(self): 

381 name, path, args, kwargs = super().deconstruct() 

382 if self._limit_choices_to: 

383 kwargs["limit_choices_to"] = self._limit_choices_to 

384 if self._related_name is not None: 

385 kwargs["related_name"] = self._related_name 

386 if self._related_query_name is not None: 

387 kwargs["related_query_name"] = self._related_query_name 

388 return name, path, args, kwargs 

389 

390 def get_forward_related_filter(self, obj): 

391 """ 

392 Return the keyword arguments that when supplied to 

393 self.model.object.filter(), would select all instances related through 

394 this field to the remote obj. This is used to build the querysets 

395 returned by related descriptors. obj is an instance of 

396 self.related_field.model. 

397 """ 

398 return { 

399 "%s__%s" % (self.name, rh_field.name): getattr(obj, rh_field.attname) 

400 for _, rh_field in self.related_fields 

401 } 

402 

403 def get_reverse_related_filter(self, obj): 

404 """ 

405 Complement to get_forward_related_filter(). Return the keyword 

406 arguments that when passed to self.related_field.model.object.filter() 

407 select all instances of self.related_field.model related through 

408 this field to obj. obj is an instance of self.model. 

409 """ 

410 base_q = Q.create( 

411 [ 

412 (rh_field.attname, getattr(obj, lh_field.attname)) 

413 for lh_field, rh_field in self.related_fields 

414 ] 

415 ) 

416 descriptor_filter = self.get_extra_descriptor_filter(obj) 

417 if isinstance(descriptor_filter, dict): 

418 return base_q & Q(**descriptor_filter) 

419 elif descriptor_filter: 

420 return base_q & descriptor_filter 

421 return base_q 

422 

423 @property 

424 def swappable_setting(self): 

425 """ 

426 Get the setting that this is powered from for swapping, or None 

427 if it's not swapped in / marked with swappable=False. 

428 """ 

429 if self.swappable: 

430 # Work out string form of "to" 

431 if isinstance(self.remote_field.model, str): 

432 to_string = self.remote_field.model 

433 else: 

434 to_string = self.remote_field.model._meta.label 

435 return apps.get_swappable_settings_name(to_string) 

436 return None 

437 

438 def set_attributes_from_rel(self): 

439 self.name = self.name or ( 

440 self.remote_field.model._meta.model_name 

441 + "_" 

442 + self.remote_field.model._meta.pk.name 

443 ) 

444 if self.verbose_name is None: 

445 self.verbose_name = self.remote_field.model._meta.verbose_name 

446 self.remote_field.set_field_name() 

447 

448 def do_related_class(self, other, cls): 

449 self.set_attributes_from_rel() 

450 self.contribute_to_related_class(other, self.remote_field) 

451 

452 def get_limit_choices_to(self): 

453 """ 

454 Return ``limit_choices_to`` for this model field. 

455 

456 If it is a callable, it will be invoked and the result will be 

457 returned. 

458 """ 

459 if callable(self.remote_field.limit_choices_to): 

460 return self.remote_field.limit_choices_to() 

461 return self.remote_field.limit_choices_to 

462 

463 def formfield(self, **kwargs): 

464 """ 

465 Pass ``limit_choices_to`` to the field being constructed. 

466 

467 Only passes it if there is a type that supports related fields. 

468 This is a similar strategy used to pass the ``queryset`` to the field 

469 being constructed. 

470 """ 

471 defaults = {} 

472 if hasattr(self.remote_field, "get_related_field"): 

473 # If this is a callable, do not invoke it here. Just pass 

474 # it in the defaults for when the form class will later be 

475 # instantiated. 

476 limit_choices_to = self.remote_field.limit_choices_to 

477 defaults.update( 

478 { 

479 "limit_choices_to": limit_choices_to, 

480 } 

481 ) 

482 defaults.update(kwargs) 

483 return super().formfield(**defaults) 

484 

485 def related_query_name(self): 

486 """ 

487 Define the name that can be used to identify this related object in a 

488 table-spanning query. 

489 """ 

490 return ( 

491 self.remote_field.related_query_name 

492 or self.remote_field.related_name 

493 or self.opts.model_name 

494 ) 

495 

496 @property 

497 def target_field(self): 

498 """ 

499 When filtering against this relation, return the field on the remote 

500 model against which the filtering should happen. 

501 """ 

502 target_fields = self.path_infos[-1].target_fields 

503 if len(target_fields) > 1: 

504 raise exceptions.FieldError( 

505 "The relation has multiple target fields, but only single target field " 

506 "was asked for" 

507 ) 

508 return target_fields[0] 

509 

510 def get_cache_name(self): 

511 return self.name 

512 

513 

514class ForeignObject(RelatedField): 

515 """ 

516 Abstraction of the ForeignKey relation to support multi-column relations. 

517 """ 

518 

519 # Field flags 

520 many_to_many = False 

521 many_to_one = True 

522 one_to_many = False 

523 one_to_one = False 

524 

525 requires_unique_target = True 

526 related_accessor_class = ReverseManyToOneDescriptor 

527 forward_related_accessor_class = ForwardManyToOneDescriptor 

528 rel_class = ForeignObjectRel 

529 

530 def __init__( 

531 self, 

532 to, 

533 on_delete, 

534 from_fields, 

535 to_fields, 

536 rel=None, 

537 related_name=None, 

538 related_query_name=None, 

539 limit_choices_to=None, 

540 parent_link=False, 

541 swappable=True, 

542 **kwargs, 

543 ): 

544 

545 if rel is None: 

546 rel = self.rel_class( 

547 self, 

548 to, 

549 related_name=related_name, 

550 related_query_name=related_query_name, 

551 limit_choices_to=limit_choices_to, 

552 parent_link=parent_link, 

553 on_delete=on_delete, 

554 ) 

555 

556 super().__init__( 

557 rel=rel, 

558 related_name=related_name, 

559 related_query_name=related_query_name, 

560 limit_choices_to=limit_choices_to, 

561 **kwargs, 

562 ) 

563 

564 self.from_fields = from_fields 

565 self.to_fields = to_fields 

566 self.swappable = swappable 

567 

568 def __copy__(self): 

569 obj = super().__copy__() 

570 # Remove any cached PathInfo values. 

571 obj.__dict__.pop("path_infos", None) 

572 obj.__dict__.pop("reverse_path_infos", None) 

573 return obj 

574 

575 def check(self, **kwargs): 

576 return [ 

577 *super().check(**kwargs), 

578 *self._check_to_fields_exist(), 

579 *self._check_unique_target(), 

580 ] 

581 

582 def _check_to_fields_exist(self): 

583 # Skip nonexistent models. 

584 if isinstance(self.remote_field.model, str): 

585 return [] 

586 

587 errors = [] 

588 for to_field in self.to_fields: 

589 if to_field: 

590 try: 

591 self.remote_field.model._meta.get_field(to_field) 

592 except exceptions.FieldDoesNotExist: 

593 errors.append( 

594 checks.Error( 

595 "The to_field '%s' doesn't exist on the related " 

596 "model '%s'." 

597 % (to_field, self.remote_field.model._meta.label), 

598 obj=self, 

599 id="fields.E312", 

600 ) 

601 ) 

602 return errors 

603 

604 def _check_unique_target(self): 

605 rel_is_string = isinstance(self.remote_field.model, str) 

606 if rel_is_string or not self.requires_unique_target: 

607 return [] 

608 

609 try: 

610 self.foreign_related_fields 

611 except exceptions.FieldDoesNotExist: 

612 return [] 

613 

614 if not self.foreign_related_fields: 

615 return [] 

616 

617 unique_foreign_fields = { 

618 frozenset([f.name]) 

619 for f in self.remote_field.model._meta.get_fields() 

620 if getattr(f, "unique", False) 

621 } 

622 unique_foreign_fields.update( 

623 {frozenset(ut) for ut in self.remote_field.model._meta.unique_together} 

624 ) 

625 unique_foreign_fields.update( 

626 { 

627 frozenset(uc.fields) 

628 for uc in self.remote_field.model._meta.total_unique_constraints 

629 } 

630 ) 

631 foreign_fields = {f.name for f in self.foreign_related_fields} 

632 has_unique_constraint = any(u <= foreign_fields for u in unique_foreign_fields) 

633 

634 if not has_unique_constraint and len(self.foreign_related_fields) > 1: 

635 field_combination = ", ".join( 

636 "'%s'" % rel_field.name for rel_field in self.foreign_related_fields 

637 ) 

638 model_name = self.remote_field.model.__name__ 

639 return [ 

640 checks.Error( 

641 "No subset of the fields %s on model '%s' is unique." 

642 % (field_combination, model_name), 

643 hint=( 

644 "Mark a single field as unique=True or add a set of " 

645 "fields to a unique constraint (via unique_together " 

646 "or a UniqueConstraint (without condition) in the " 

647 "model Meta.constraints)." 

648 ), 

649 obj=self, 

650 id="fields.E310", 

651 ) 

652 ] 

653 elif not has_unique_constraint: 

654 field_name = self.foreign_related_fields[0].name 

655 model_name = self.remote_field.model.__name__ 

656 return [ 

657 checks.Error( 

658 "'%s.%s' must be unique because it is referenced by " 

659 "a foreign key." % (model_name, field_name), 

660 hint=( 

661 "Add unique=True to this field or add a " 

662 "UniqueConstraint (without condition) in the model " 

663 "Meta.constraints." 

664 ), 

665 obj=self, 

666 id="fields.E311", 

667 ) 

668 ] 

669 else: 

670 return [] 

671 

672 def deconstruct(self): 

673 name, path, args, kwargs = super().deconstruct() 

674 kwargs["on_delete"] = self.remote_field.on_delete 

675 kwargs["from_fields"] = self.from_fields 

676 kwargs["to_fields"] = self.to_fields 

677 

678 if self.remote_field.parent_link: 

679 kwargs["parent_link"] = self.remote_field.parent_link 

680 if isinstance(self.remote_field.model, str): 

681 if "." in self.remote_field.model: 

682 app_label, model_name = self.remote_field.model.split(".") 

683 kwargs["to"] = "%s.%s" % (app_label, model_name.lower()) 

684 else: 

685 kwargs["to"] = self.remote_field.model.lower() 

686 else: 

687 kwargs["to"] = self.remote_field.model._meta.label_lower 

688 # If swappable is True, then see if we're actually pointing to the target 

689 # of a swap. 

690 swappable_setting = self.swappable_setting 

691 if swappable_setting is not None: 

692 # If it's already a settings reference, error 

693 if hasattr(kwargs["to"], "setting_name"): 

694 if kwargs["to"].setting_name != swappable_setting: 

695 raise ValueError( 

696 "Cannot deconstruct a ForeignKey pointing to a model " 

697 "that is swapped in place of more than one model (%s and %s)" 

698 % (kwargs["to"].setting_name, swappable_setting) 

699 ) 

700 # Set it 

701 kwargs["to"] = SettingsReference( 

702 kwargs["to"], 

703 swappable_setting, 

704 ) 

705 return name, path, args, kwargs 

706 

707 def resolve_related_fields(self): 

708 if not self.from_fields or len(self.from_fields) != len(self.to_fields): 

709 raise ValueError( 

710 "Foreign Object from and to fields must be the same non-zero length" 

711 ) 

712 if isinstance(self.remote_field.model, str): 

713 raise ValueError( 

714 "Related model %r cannot be resolved" % self.remote_field.model 

715 ) 

716 related_fields = [] 

717 for index in range(len(self.from_fields)): 

718 from_field_name = self.from_fields[index] 

719 to_field_name = self.to_fields[index] 

720 from_field = ( 

721 self 

722 if from_field_name == RECURSIVE_RELATIONSHIP_CONSTANT 

723 else self.opts.get_field(from_field_name) 

724 ) 

725 to_field = ( 

726 self.remote_field.model._meta.pk 

727 if to_field_name is None 

728 else self.remote_field.model._meta.get_field(to_field_name) 

729 ) 

730 related_fields.append((from_field, to_field)) 

731 return related_fields 

732 

733 @cached_property 

734 def related_fields(self): 

735 return self.resolve_related_fields() 

736 

737 @cached_property 

738 def reverse_related_fields(self): 

739 return [(rhs_field, lhs_field) for lhs_field, rhs_field in self.related_fields] 

740 

741 @cached_property 

742 def local_related_fields(self): 

743 return tuple(lhs_field for lhs_field, rhs_field in self.related_fields) 

744 

745 @cached_property 

746 def foreign_related_fields(self): 

747 return tuple( 

748 rhs_field for lhs_field, rhs_field in self.related_fields if rhs_field 

749 ) 

750 

751 def get_local_related_value(self, instance): 

752 return self.get_instance_value_for_fields(instance, self.local_related_fields) 

753 

754 def get_foreign_related_value(self, instance): 

755 return self.get_instance_value_for_fields(instance, self.foreign_related_fields) 

756 

757 @staticmethod 

758 def get_instance_value_for_fields(instance, fields): 

759 ret = [] 

760 opts = instance._meta 

761 for field in fields: 

762 # Gotcha: in some cases (like fixture loading) a model can have 

763 # different values in parent_ptr_id and parent's id. So, use 

764 # instance.pk (that is, parent_ptr_id) when asked for instance.id. 

765 if field.primary_key: 

766 possible_parent_link = opts.get_ancestor_link(field.model) 

767 if ( 

768 not possible_parent_link 

769 or possible_parent_link.primary_key 

770 or possible_parent_link.model._meta.abstract 

771 ): 

772 ret.append(instance.pk) 

773 continue 

774 ret.append(getattr(instance, field.attname)) 

775 return tuple(ret) 

776 

777 def get_attname_column(self): 

778 attname, column = super().get_attname_column() 

779 return attname, None 

780 

781 def get_joining_columns(self, reverse_join=False): 

782 source = self.reverse_related_fields if reverse_join else self.related_fields 

783 return tuple( 

784 (lhs_field.column, rhs_field.column) for lhs_field, rhs_field in source 

785 ) 

786 

787 def get_reverse_joining_columns(self): 

788 return self.get_joining_columns(reverse_join=True) 

789 

790 def get_extra_descriptor_filter(self, instance): 

791 """ 

792 Return an extra filter condition for related object fetching when 

793 user does 'instance.fieldname', that is the extra filter is used in 

794 the descriptor of the field. 

795 

796 The filter should be either a dict usable in .filter(**kwargs) call or 

797 a Q-object. The condition will be ANDed together with the relation's 

798 joining columns. 

799 

800 A parallel method is get_extra_restriction() which is used in 

801 JOIN and subquery conditions. 

802 """ 

803 return {} 

804 

805 def get_extra_restriction(self, alias, related_alias): 

806 """ 

807 Return a pair condition used for joining and subquery pushdown. The 

808 condition is something that responds to as_sql(compiler, connection) 

809 method. 

810 

811 Note that currently referring both the 'alias' and 'related_alias' 

812 will not work in some conditions, like subquery pushdown. 

813 

814 A parallel method is get_extra_descriptor_filter() which is used in 

815 instance.fieldname related object fetching. 

816 """ 

817 return None 

818 

819 def get_path_info(self, filtered_relation=None): 

820 """Get path from this field to the related model.""" 

821 opts = self.remote_field.model._meta 

822 from_opts = self.model._meta 

823 return [ 

824 PathInfo( 

825 from_opts=from_opts, 

826 to_opts=opts, 

827 target_fields=self.foreign_related_fields, 

828 join_field=self, 

829 m2m=False, 

830 direct=True, 

831 filtered_relation=filtered_relation, 

832 ) 

833 ] 

834 

835 @cached_property 

836 def path_infos(self): 

837 return self.get_path_info() 

838 

839 def get_reverse_path_info(self, filtered_relation=None): 

840 """Get path from the related model to this field's model.""" 

841 opts = self.model._meta 

842 from_opts = self.remote_field.model._meta 

843 return [ 

844 PathInfo( 

845 from_opts=from_opts, 

846 to_opts=opts, 

847 target_fields=(opts.pk,), 

848 join_field=self.remote_field, 

849 m2m=not self.unique, 

850 direct=False, 

851 filtered_relation=filtered_relation, 

852 ) 

853 ] 

854 

855 @cached_property 

856 def reverse_path_infos(self): 

857 return self.get_reverse_path_info() 

858 

859 @classmethod 

860 @functools.lru_cache(maxsize=None) 

861 def get_class_lookups(cls): 

862 bases = inspect.getmro(cls) 

863 bases = bases[: bases.index(ForeignObject) + 1] 

864 class_lookups = [parent.__dict__.get("class_lookups", {}) for parent in bases] 

865 return cls.merge_dicts(class_lookups) 

866 

867 def contribute_to_class(self, cls, name, private_only=False, **kwargs): 

868 super().contribute_to_class(cls, name, private_only=private_only, **kwargs) 

869 setattr(cls, self.name, self.forward_related_accessor_class(self)) 

870 

871 def contribute_to_related_class(self, cls, related): 

872 # Internal FK's - i.e., those with a related name ending with '+' - 

873 # and swapped models don't get a related descriptor. 

874 if ( 

875 not self.remote_field.is_hidden() 

876 and not related.related_model._meta.swapped 

877 ): 

878 setattr( 

879 cls._meta.concrete_model, 

880 related.get_accessor_name(), 

881 self.related_accessor_class(related), 

882 ) 

883 # While 'limit_choices_to' might be a callable, simply pass 

884 # it along for later - this is too early because it's still 

885 # model load time. 

886 if self.remote_field.limit_choices_to: 

887 cls._meta.related_fkey_lookups.append( 

888 self.remote_field.limit_choices_to 

889 ) 

890 

891 

892ForeignObject.register_lookup(RelatedIn) 

893ForeignObject.register_lookup(RelatedExact) 

894ForeignObject.register_lookup(RelatedLessThan) 

895ForeignObject.register_lookup(RelatedGreaterThan) 

896ForeignObject.register_lookup(RelatedGreaterThanOrEqual) 

897ForeignObject.register_lookup(RelatedLessThanOrEqual) 

898ForeignObject.register_lookup(RelatedIsNull) 

899 

900 

901class ForeignKey(ForeignObject): 

902 """ 

903 Provide a many-to-one relation by adding a column to the local model 

904 to hold the remote value. 

905 

906 By default ForeignKey will target the pk of the remote model but this 

907 behavior can be changed by using the ``to_field`` argument. 

908 """ 

909 

910 descriptor_class = ForeignKeyDeferredAttribute 

911 # Field flags 

912 many_to_many = False 

913 many_to_one = True 

914 one_to_many = False 

915 one_to_one = False 

916 

917 rel_class = ManyToOneRel 

918 

919 empty_strings_allowed = False 

920 default_error_messages = { 

921 "invalid": _("%(model)s instance with %(field)s %(value)r does not exist.") 

922 } 

923 description = _("Foreign Key (type determined by related field)") 

924 

925 def __init__( 

926 self, 

927 to, 

928 on_delete, 

929 related_name=None, 

930 related_query_name=None, 

931 limit_choices_to=None, 

932 parent_link=False, 

933 to_field=None, 

934 db_constraint=True, 

935 **kwargs, 

936 ): 

937 try: 

938 to._meta.model_name 

939 except AttributeError: 

940 if not isinstance(to, str): 

941 raise TypeError( 

942 "%s(%r) is invalid. First parameter to ForeignKey must be " 

943 "either a model, a model name, or the string %r" 

944 % ( 

945 self.__class__.__name__, 

946 to, 

947 RECURSIVE_RELATIONSHIP_CONSTANT, 

948 ) 

949 ) 

950 else: 

951 # For backwards compatibility purposes, we need to *try* and set 

952 # the to_field during FK construction. It won't be guaranteed to 

953 # be correct until contribute_to_class is called. Refs #12190. 

954 to_field = to_field or (to._meta.pk and to._meta.pk.name) 

955 if not callable(on_delete): 

956 raise TypeError("on_delete must be callable.") 

957 

958 kwargs["rel"] = self.rel_class( 

959 self, 

960 to, 

961 to_field, 

962 related_name=related_name, 

963 related_query_name=related_query_name, 

964 limit_choices_to=limit_choices_to, 

965 parent_link=parent_link, 

966 on_delete=on_delete, 

967 ) 

968 kwargs.setdefault("db_index", True) 

969 

970 super().__init__( 

971 to, 

972 on_delete, 

973 related_name=related_name, 

974 related_query_name=related_query_name, 

975 limit_choices_to=limit_choices_to, 

976 from_fields=[RECURSIVE_RELATIONSHIP_CONSTANT], 

977 to_fields=[to_field], 

978 **kwargs, 

979 ) 

980 self.db_constraint = db_constraint 

981 

982 def __class_getitem__(cls, *args, **kwargs): 

983 return cls 

984 

985 def check(self, **kwargs): 

986 return [ 

987 *super().check(**kwargs), 

988 *self._check_on_delete(), 

989 *self._check_unique(), 

990 ] 

991 

992 def _check_on_delete(self): 

993 on_delete = getattr(self.remote_field, "on_delete", None) 

994 if on_delete == SET_NULL and not self.null: 

995 return [ 

996 checks.Error( 

997 "Field specifies on_delete=SET_NULL, but cannot be null.", 

998 hint=( 

999 "Set null=True argument on the field, or change the on_delete " 

1000 "rule." 

1001 ), 

1002 obj=self, 

1003 id="fields.E320", 

1004 ) 

1005 ] 

1006 elif on_delete == SET_DEFAULT and not self.has_default(): 

1007 return [ 

1008 checks.Error( 

1009 "Field specifies on_delete=SET_DEFAULT, but has no default value.", 

1010 hint="Set a default value, or change the on_delete rule.", 

1011 obj=self, 

1012 id="fields.E321", 

1013 ) 

1014 ] 

1015 else: 

1016 return [] 

1017 

1018 def _check_unique(self, **kwargs): 

1019 return ( 

1020 [ 

1021 checks.Warning( 

1022 "Setting unique=True on a ForeignKey has the same effect as using " 

1023 "a OneToOneField.", 

1024 hint=( 

1025 "ForeignKey(unique=True) is usually better served by a " 

1026 "OneToOneField." 

1027 ), 

1028 obj=self, 

1029 id="fields.W342", 

1030 ) 

1031 ] 

1032 if self.unique 

1033 else [] 

1034 ) 

1035 

1036 def deconstruct(self): 

1037 name, path, args, kwargs = super().deconstruct() 

1038 del kwargs["to_fields"] 

1039 del kwargs["from_fields"] 

1040 # Handle the simpler arguments 

1041 if self.db_index: 

1042 del kwargs["db_index"] 

1043 else: 

1044 kwargs["db_index"] = False 

1045 if self.db_constraint is not True: 

1046 kwargs["db_constraint"] = self.db_constraint 

1047 # Rel needs more work. 

1048 to_meta = getattr(self.remote_field.model, "_meta", None) 

1049 if self.remote_field.field_name and ( 

1050 not to_meta 

1051 or (to_meta.pk and self.remote_field.field_name != to_meta.pk.name) 

1052 ): 

1053 kwargs["to_field"] = self.remote_field.field_name 

1054 return name, path, args, kwargs 

1055 

1056 def to_python(self, value): 

1057 return self.target_field.to_python(value) 

1058 

1059 @property 

1060 def target_field(self): 

1061 return self.foreign_related_fields[0] 

1062 

1063 def validate(self, value, model_instance): 

1064 if self.remote_field.parent_link: 

1065 return 

1066 super().validate(value, model_instance) 

1067 if value is None: 

1068 return 

1069 

1070 using = router.db_for_read(self.remote_field.model, instance=model_instance) 

1071 qs = self.remote_field.model._base_manager.using(using).filter( 

1072 **{self.remote_field.field_name: value} 

1073 ) 

1074 qs = qs.complex_filter(self.get_limit_choices_to()) 

1075 if not qs.exists(): 

1076 raise exceptions.ValidationError( 

1077 self.error_messages["invalid"], 

1078 code="invalid", 

1079 params={ 

1080 "model": self.remote_field.model._meta.verbose_name, 

1081 "pk": value, 

1082 "field": self.remote_field.field_name, 

1083 "value": value, 

1084 }, # 'pk' is included for backwards compatibility 

1085 ) 

1086 

1087 def resolve_related_fields(self): 

1088 related_fields = super().resolve_related_fields() 

1089 for from_field, to_field in related_fields: 

1090 if ( 

1091 to_field 

1092 and to_field.model != self.remote_field.model._meta.concrete_model 

1093 ): 

1094 raise exceptions.FieldError( 

1095 "'%s.%s' refers to field '%s' which is not local to model " 

1096 "'%s'." 

1097 % ( 

1098 self.model._meta.label, 

1099 self.name, 

1100 to_field.name, 

1101 self.remote_field.model._meta.concrete_model._meta.label, 

1102 ) 

1103 ) 

1104 return related_fields 

1105 

1106 def get_attname(self): 

1107 return "%s_id" % self.name 

1108 

1109 def get_attname_column(self): 

1110 attname = self.get_attname() 

1111 column = self.db_column or attname 

1112 return attname, column 

1113 

1114 def get_default(self): 

1115 """Return the to_field if the default value is an object.""" 

1116 field_default = super().get_default() 

1117 if isinstance(field_default, self.remote_field.model): 

1118 return getattr(field_default, self.target_field.attname) 

1119 return field_default 

1120 

1121 def get_db_prep_save(self, value, connection): 

1122 if value is None or ( 

1123 value == "" 

1124 and ( 

1125 not self.target_field.empty_strings_allowed 

1126 or connection.features.interprets_empty_strings_as_nulls 

1127 ) 

1128 ): 

1129 return None 

1130 else: 

1131 return self.target_field.get_db_prep_save(value, connection=connection) 

1132 

1133 def get_db_prep_value(self, value, connection, prepared=False): 

1134 return self.target_field.get_db_prep_value(value, connection, prepared) 

1135 

1136 def get_prep_value(self, value): 

1137 return self.target_field.get_prep_value(value) 

1138 

1139 def contribute_to_related_class(self, cls, related): 

1140 super().contribute_to_related_class(cls, related) 

1141 if self.remote_field.field_name is None: 

1142 self.remote_field.field_name = cls._meta.pk.name 

1143 

1144 def formfield(self, *, using=None, **kwargs): 

1145 if isinstance(self.remote_field.model, str): 

1146 raise ValueError( 

1147 "Cannot create form field for %r yet, because " 

1148 "its related model %r has not been loaded yet" 

1149 % (self.name, self.remote_field.model) 

1150 ) 

1151 return super().formfield( 

1152 **{ 

1153 "form_class": forms.ModelChoiceField, 

1154 "queryset": self.remote_field.model._default_manager.using(using), 

1155 "to_field_name": self.remote_field.field_name, 

1156 **kwargs, 

1157 "blank": self.blank, 

1158 } 

1159 ) 

1160 

1161 def db_check(self, connection): 

1162 return None 

1163 

1164 def db_type(self, connection): 

1165 return self.target_field.rel_db_type(connection=connection) 

1166 

1167 def db_parameters(self, connection): 

1168 target_db_parameters = self.target_field.db_parameters(connection) 

1169 return { 

1170 "type": self.db_type(connection), 

1171 "check": self.db_check(connection), 

1172 "collation": target_db_parameters.get("collation"), 

1173 } 

1174 

1175 def convert_empty_strings(self, value, expression, connection): 

1176 if (not value) and isinstance(value, str): 

1177 return None 

1178 return value 

1179 

1180 def get_db_converters(self, connection): 

1181 converters = super().get_db_converters(connection) 

1182 if connection.features.interprets_empty_strings_as_nulls: 

1183 converters += [self.convert_empty_strings] 

1184 return converters 

1185 

1186 def get_col(self, alias, output_field=None): 

1187 if output_field is None: 

1188 output_field = self.target_field 

1189 while isinstance(output_field, ForeignKey): 

1190 output_field = output_field.target_field 

1191 if output_field is self: 

1192 raise ValueError("Cannot resolve output_field.") 

1193 return super().get_col(alias, output_field) 

1194 

1195 

1196class OneToOneField(ForeignKey): 

1197 """ 

1198 A OneToOneField is essentially the same as a ForeignKey, with the exception 

1199 that it always carries a "unique" constraint with it and the reverse 

1200 relation always returns the object pointed to (since there will only ever 

1201 be one), rather than returning a list. 

1202 """ 

1203 

1204 # Field flags 

1205 many_to_many = False 

1206 many_to_one = False 

1207 one_to_many = False 

1208 one_to_one = True 

1209 

1210 related_accessor_class = ReverseOneToOneDescriptor 

1211 forward_related_accessor_class = ForwardOneToOneDescriptor 

1212 rel_class = OneToOneRel 

1213 

1214 description = _("One-to-one relationship") 

1215 

1216 def __init__(self, to, on_delete, to_field=None, **kwargs): 

1217 kwargs["unique"] = True 

1218 super().__init__(to, on_delete, to_field=to_field, **kwargs) 

1219 

1220 def deconstruct(self): 

1221 name, path, args, kwargs = super().deconstruct() 

1222 if "unique" in kwargs: 

1223 del kwargs["unique"] 

1224 return name, path, args, kwargs 

1225 

1226 def formfield(self, **kwargs): 

1227 if self.remote_field.parent_link: 

1228 return None 

1229 return super().formfield(**kwargs) 

1230 

1231 def save_form_data(self, instance, data): 

1232 if isinstance(data, self.remote_field.model): 

1233 setattr(instance, self.name, data) 

1234 else: 

1235 setattr(instance, self.attname, data) 

1236 # Remote field object must be cleared otherwise Model.save() 

1237 # will reassign attname using the related object pk. 

1238 if data is None: 

1239 setattr(instance, self.name, data) 

1240 

1241 def _check_unique(self, **kwargs): 

1242 # Override ForeignKey since check isn't applicable here. 

1243 return [] 

1244 

1245 

1246def create_many_to_many_intermediary_model(field, klass): 

1247 from django.db import models 

1248 

1249 def set_managed(model, related, through): 

1250 through._meta.managed = model._meta.managed or related._meta.managed 

1251 

1252 to_model = resolve_relation(klass, field.remote_field.model) 

1253 name = "%s_%s" % (klass._meta.object_name, field.name) 

1254 lazy_related_operation(set_managed, klass, to_model, name) 

1255 

1256 to = make_model_tuple(to_model)[1] 

1257 from_ = klass._meta.model_name 

1258 if to == from_: 

1259 to = "to_%s" % to 

1260 from_ = "from_%s" % from_ 

1261 

1262 meta = type( 

1263 "Meta", 

1264 (), 

1265 { 

1266 "db_table": field._get_m2m_db_table(klass._meta), 

1267 "auto_created": klass, 

1268 "app_label": klass._meta.app_label, 

1269 "db_tablespace": klass._meta.db_tablespace, 

1270 "unique_together": (from_, to), 

1271 "verbose_name": _("%(from)s-%(to)s relationship") 

1272 % {"from": from_, "to": to}, 

1273 "verbose_name_plural": _("%(from)s-%(to)s relationships") 

1274 % {"from": from_, "to": to}, 

1275 "apps": field.model._meta.apps, 

1276 }, 

1277 ) 

1278 # Construct and return the new class. 

1279 return type( 

1280 name, 

1281 (models.Model,), 

1282 { 

1283 "Meta": meta, 

1284 "__module__": klass.__module__, 

1285 from_: models.ForeignKey( 

1286 klass, 

1287 related_name="%s+" % name, 

1288 db_tablespace=field.db_tablespace, 

1289 db_constraint=field.remote_field.db_constraint, 

1290 on_delete=CASCADE, 

1291 ), 

1292 to: models.ForeignKey( 

1293 to_model, 

1294 related_name="%s+" % name, 

1295 db_tablespace=field.db_tablespace, 

1296 db_constraint=field.remote_field.db_constraint, 

1297 on_delete=CASCADE, 

1298 ), 

1299 }, 

1300 ) 

1301 

1302 

1303class ManyToManyField(RelatedField): 

1304 """ 

1305 Provide a many-to-many relation by using an intermediary model that 

1306 holds two ForeignKey fields pointed at the two sides of the relation. 

1307 

1308 Unless a ``through`` model was provided, ManyToManyField will use the 

1309 create_many_to_many_intermediary_model factory to automatically generate 

1310 the intermediary model. 

1311 """ 

1312 

1313 # Field flags 

1314 many_to_many = True 

1315 many_to_one = False 

1316 one_to_many = False 

1317 one_to_one = False 

1318 

1319 rel_class = ManyToManyRel 

1320 

1321 description = _("Many-to-many relationship") 

1322 

1323 def __init__( 

1324 self, 

1325 to, 

1326 related_name=None, 

1327 related_query_name=None, 

1328 limit_choices_to=None, 

1329 symmetrical=None, 

1330 through=None, 

1331 through_fields=None, 

1332 db_constraint=True, 

1333 db_table=None, 

1334 swappable=True, 

1335 **kwargs, 

1336 ): 

1337 try: 

1338 to._meta 

1339 except AttributeError: 

1340 if not isinstance(to, str): 

1341 raise TypeError( 

1342 "%s(%r) is invalid. First parameter to ManyToManyField " 

1343 "must be either a model, a model name, or the string %r" 

1344 % ( 

1345 self.__class__.__name__, 

1346 to, 

1347 RECURSIVE_RELATIONSHIP_CONSTANT, 

1348 ) 

1349 ) 

1350 

1351 if symmetrical is None: 

1352 symmetrical = to == RECURSIVE_RELATIONSHIP_CONSTANT 

1353 

1354 if through is not None and db_table is not None: 

1355 raise ValueError( 

1356 "Cannot specify a db_table if an intermediary model is used." 

1357 ) 

1358 

1359 kwargs["rel"] = self.rel_class( 

1360 self, 

1361 to, 

1362 related_name=related_name, 

1363 related_query_name=related_query_name, 

1364 limit_choices_to=limit_choices_to, 

1365 symmetrical=symmetrical, 

1366 through=through, 

1367 through_fields=through_fields, 

1368 db_constraint=db_constraint, 

1369 ) 

1370 self.has_null_arg = "null" in kwargs 

1371 

1372 super().__init__( 

1373 related_name=related_name, 

1374 related_query_name=related_query_name, 

1375 limit_choices_to=limit_choices_to, 

1376 **kwargs, 

1377 ) 

1378 

1379 self.db_table = db_table 

1380 self.swappable = swappable 

1381 

1382 def check(self, **kwargs): 

1383 return [ 

1384 *super().check(**kwargs), 

1385 *self._check_unique(**kwargs), 

1386 *self._check_relationship_model(**kwargs), 

1387 *self._check_ignored_options(**kwargs), 

1388 *self._check_table_uniqueness(**kwargs), 

1389 ] 

1390 

1391 def _check_unique(self, **kwargs): 

1392 if self.unique: 

1393 return [ 

1394 checks.Error( 

1395 "ManyToManyFields cannot be unique.", 

1396 obj=self, 

1397 id="fields.E330", 

1398 ) 

1399 ] 

1400 return [] 

1401 

1402 def _check_ignored_options(self, **kwargs): 

1403 warnings = [] 

1404 

1405 if self.has_null_arg: 

1406 warnings.append( 

1407 checks.Warning( 

1408 "null has no effect on ManyToManyField.", 

1409 obj=self, 

1410 id="fields.W340", 

1411 ) 

1412 ) 

1413 

1414 if self._validators: 

1415 warnings.append( 

1416 checks.Warning( 

1417 "ManyToManyField does not support validators.", 

1418 obj=self, 

1419 id="fields.W341", 

1420 ) 

1421 ) 

1422 if self.remote_field.symmetrical and self._related_name: 

1423 warnings.append( 

1424 checks.Warning( 

1425 "related_name has no effect on ManyToManyField " 

1426 'with a symmetrical relationship, e.g. to "self".', 

1427 obj=self, 

1428 id="fields.W345", 

1429 ) 

1430 ) 

1431 if self.db_comment: 

1432 warnings.append( 

1433 checks.Warning( 

1434 "db_comment has no effect on ManyToManyField.", 

1435 obj=self, 

1436 id="fields.W346", 

1437 ) 

1438 ) 

1439 

1440 return warnings 

1441 

1442 def _check_relationship_model(self, from_model=None, **kwargs): 

1443 if hasattr(self.remote_field.through, "_meta"): 

1444 qualified_model_name = "%s.%s" % ( 

1445 self.remote_field.through._meta.app_label, 

1446 self.remote_field.through.__name__, 

1447 ) 

1448 else: 

1449 qualified_model_name = self.remote_field.through 

1450 

1451 errors = [] 

1452 

1453 if self.remote_field.through not in self.opts.apps.get_models( 

1454 include_auto_created=True 

1455 ): 

1456 # The relationship model is not installed. 

1457 errors.append( 

1458 checks.Error( 

1459 "Field specifies a many-to-many relation through model " 

1460 "'%s', which has not been installed." % qualified_model_name, 

1461 obj=self, 

1462 id="fields.E331", 

1463 ) 

1464 ) 

1465 

1466 else: 

1467 assert from_model is not None, ( 

1468 "ManyToManyField with intermediate " 

1469 "tables cannot be checked if you don't pass the model " 

1470 "where the field is attached to." 

1471 ) 

1472 # Set some useful local variables 

1473 to_model = resolve_relation(from_model, self.remote_field.model) 

1474 from_model_name = from_model._meta.object_name 

1475 if isinstance(to_model, str): 

1476 to_model_name = to_model 

1477 else: 

1478 to_model_name = to_model._meta.object_name 

1479 relationship_model_name = self.remote_field.through._meta.object_name 

1480 self_referential = from_model == to_model 

1481 # Count foreign keys in intermediate model 

1482 if self_referential: 

1483 seen_self = sum( 

1484 from_model == getattr(field.remote_field, "model", None) 

1485 for field in self.remote_field.through._meta.fields 

1486 ) 

1487 

1488 if seen_self > 2 and not self.remote_field.through_fields: 

1489 errors.append( 

1490 checks.Error( 

1491 "The model is used as an intermediate model by " 

1492 "'%s', but it has more than two foreign keys " 

1493 "to '%s', which is ambiguous. You must specify " 

1494 "which two foreign keys Django should use via the " 

1495 "through_fields keyword argument." 

1496 % (self, from_model_name), 

1497 hint=( 

1498 "Use through_fields to specify which two foreign keys " 

1499 "Django should use." 

1500 ), 

1501 obj=self.remote_field.through, 

1502 id="fields.E333", 

1503 ) 

1504 ) 

1505 

1506 else: 

1507 # Count foreign keys in relationship model 

1508 seen_from = sum( 

1509 from_model == getattr(field.remote_field, "model", None) 

1510 for field in self.remote_field.through._meta.fields 

1511 ) 

1512 seen_to = sum( 

1513 to_model == getattr(field.remote_field, "model", None) 

1514 for field in self.remote_field.through._meta.fields 

1515 ) 

1516 

1517 if seen_from > 1 and not self.remote_field.through_fields: 

1518 errors.append( 

1519 checks.Error( 

1520 ( 

1521 "The model is used as an intermediate model by " 

1522 "'%s', but it has more than one foreign key " 

1523 "from '%s', which is ambiguous. You must specify " 

1524 "which foreign key Django should use via the " 

1525 "through_fields keyword argument." 

1526 ) 

1527 % (self, from_model_name), 

1528 hint=( 

1529 "If you want to create a recursive relationship, " 

1530 'use ManyToManyField("%s", through="%s").' 

1531 ) 

1532 % ( 

1533 RECURSIVE_RELATIONSHIP_CONSTANT, 

1534 relationship_model_name, 

1535 ), 

1536 obj=self, 

1537 id="fields.E334", 

1538 ) 

1539 ) 

1540 

1541 if seen_to > 1 and not self.remote_field.through_fields: 

1542 errors.append( 

1543 checks.Error( 

1544 "The model is used as an intermediate model by " 

1545 "'%s', but it has more than one foreign key " 

1546 "to '%s', which is ambiguous. You must specify " 

1547 "which foreign key Django should use via the " 

1548 "through_fields keyword argument." % (self, to_model_name), 

1549 hint=( 

1550 "If you want to create a recursive relationship, " 

1551 'use ManyToManyField("%s", through="%s").' 

1552 ) 

1553 % ( 

1554 RECURSIVE_RELATIONSHIP_CONSTANT, 

1555 relationship_model_name, 

1556 ), 

1557 obj=self, 

1558 id="fields.E335", 

1559 ) 

1560 ) 

1561 

1562 if seen_from == 0 or seen_to == 0: 

1563 errors.append( 

1564 checks.Error( 

1565 "The model is used as an intermediate model by " 

1566 "'%s', but it does not have a foreign key to '%s' or '%s'." 

1567 % (self, from_model_name, to_model_name), 

1568 obj=self.remote_field.through, 

1569 id="fields.E336", 

1570 ) 

1571 ) 

1572 

1573 # Validate `through_fields`. 

1574 if self.remote_field.through_fields is not None: 

1575 # Validate that we're given an iterable of at least two items 

1576 # and that none of them is "falsy". 

1577 if not ( 

1578 len(self.remote_field.through_fields) >= 2 

1579 and self.remote_field.through_fields[0] 

1580 and self.remote_field.through_fields[1] 

1581 ): 

1582 errors.append( 

1583 checks.Error( 

1584 "Field specifies 'through_fields' but does not provide " 

1585 "the names of the two link fields that should be used " 

1586 "for the relation through model '%s'." % qualified_model_name, 

1587 hint=( 

1588 "Make sure you specify 'through_fields' as " 

1589 "through_fields=('field1', 'field2')" 

1590 ), 

1591 obj=self, 

1592 id="fields.E337", 

1593 ) 

1594 ) 

1595 

1596 # Validate the given through fields -- they should be actual 

1597 # fields on the through model, and also be foreign keys to the 

1598 # expected models. 

1599 else: 

1600 assert from_model is not None, ( 

1601 "ManyToManyField with intermediate " 

1602 "tables cannot be checked if you don't pass the model " 

1603 "where the field is attached to." 

1604 ) 

1605 

1606 source, through, target = ( 

1607 from_model, 

1608 self.remote_field.through, 

1609 self.remote_field.model, 

1610 ) 

1611 source_field_name, target_field_name = self.remote_field.through_fields[ 

1612 :2 

1613 ] 

1614 

1615 for field_name, related_model in ( 

1616 (source_field_name, source), 

1617 (target_field_name, target), 

1618 ): 

1619 

1620 possible_field_names = [] 

1621 for f in through._meta.fields: 

1622 if ( 

1623 hasattr(f, "remote_field") 

1624 and getattr(f.remote_field, "model", None) == related_model 

1625 ): 

1626 possible_field_names.append(f.name) 

1627 if possible_field_names: 

1628 hint = ( 

1629 "Did you mean one of the following foreign keys to '%s': " 

1630 "%s?" 

1631 % ( 

1632 related_model._meta.object_name, 

1633 ", ".join(possible_field_names), 

1634 ) 

1635 ) 

1636 else: 

1637 hint = None 

1638 

1639 try: 

1640 field = through._meta.get_field(field_name) 

1641 except exceptions.FieldDoesNotExist: 

1642 errors.append( 

1643 checks.Error( 

1644 "The intermediary model '%s' has no field '%s'." 

1645 % (qualified_model_name, field_name), 

1646 hint=hint, 

1647 obj=self, 

1648 id="fields.E338", 

1649 ) 

1650 ) 

1651 else: 

1652 if not ( 

1653 hasattr(field, "remote_field") 

1654 and getattr(field.remote_field, "model", None) 

1655 == related_model 

1656 ): 

1657 errors.append( 

1658 checks.Error( 

1659 "'%s.%s' is not a foreign key to '%s'." 

1660 % ( 

1661 through._meta.object_name, 

1662 field_name, 

1663 related_model._meta.object_name, 

1664 ), 

1665 hint=hint, 

1666 obj=self, 

1667 id="fields.E339", 

1668 ) 

1669 ) 

1670 

1671 return errors 

1672 

1673 def _check_table_uniqueness(self, **kwargs): 

1674 if ( 

1675 isinstance(self.remote_field.through, str) 

1676 or not self.remote_field.through._meta.managed 

1677 ): 

1678 return [] 

1679 registered_tables = { 

1680 model._meta.db_table: model 

1681 for model in self.opts.apps.get_models(include_auto_created=True) 

1682 if model != self.remote_field.through and model._meta.managed 

1683 } 

1684 m2m_db_table = self.m2m_db_table() 

1685 model = registered_tables.get(m2m_db_table) 

1686 # The second condition allows multiple m2m relations on a model if 

1687 # some point to a through model that proxies another through model. 

1688 if ( 

1689 model 

1690 and model._meta.concrete_model 

1691 != self.remote_field.through._meta.concrete_model 

1692 ): 

1693 if model._meta.auto_created: 

1694 

1695 def _get_field_name(model): 

1696 for field in model._meta.auto_created._meta.many_to_many: 

1697 if field.remote_field.through is model: 

1698 return field.name 

1699 

1700 opts = model._meta.auto_created._meta 

1701 clashing_obj = "%s.%s" % (opts.label, _get_field_name(model)) 

1702 else: 

1703 clashing_obj = model._meta.label 

1704 if settings.DATABASE_ROUTERS: 

1705 error_class, error_id = checks.Warning, "fields.W344" 

1706 error_hint = ( 

1707 "You have configured settings.DATABASE_ROUTERS. Verify " 

1708 "that the table of %r is correctly routed to a separate " 

1709 "database." % clashing_obj 

1710 ) 

1711 else: 

1712 error_class, error_id = checks.Error, "fields.E340" 

1713 error_hint = None 

1714 return [ 

1715 error_class( 

1716 "The field's intermediary table '%s' clashes with the " 

1717 "table name of '%s'." % (m2m_db_table, clashing_obj), 

1718 obj=self, 

1719 hint=error_hint, 

1720 id=error_id, 

1721 ) 

1722 ] 

1723 return [] 

1724 

1725 def deconstruct(self): 

1726 name, path, args, kwargs = super().deconstruct() 

1727 # Handle the simpler arguments. 

1728 if self.db_table is not None: 

1729 kwargs["db_table"] = self.db_table 

1730 if self.remote_field.db_constraint is not True: 

1731 kwargs["db_constraint"] = self.remote_field.db_constraint 

1732 # Lowercase model names as they should be treated as case-insensitive. 

1733 if isinstance(self.remote_field.model, str): 

1734 if "." in self.remote_field.model: 

1735 app_label, model_name = self.remote_field.model.split(".") 

1736 kwargs["to"] = "%s.%s" % (app_label, model_name.lower()) 

1737 else: 

1738 kwargs["to"] = self.remote_field.model.lower() 

1739 else: 

1740 kwargs["to"] = self.remote_field.model._meta.label_lower 

1741 if getattr(self.remote_field, "through", None) is not None: 

1742 if isinstance(self.remote_field.through, str): 

1743 kwargs["through"] = self.remote_field.through 

1744 elif not self.remote_field.through._meta.auto_created: 

1745 kwargs["through"] = self.remote_field.through._meta.label 

1746 # If swappable is True, then see if we're actually pointing to the target 

1747 # of a swap. 

1748 swappable_setting = self.swappable_setting 

1749 if swappable_setting is not None: 

1750 # If it's already a settings reference, error. 

1751 if hasattr(kwargs["to"], "setting_name"): 

1752 if kwargs["to"].setting_name != swappable_setting: 

1753 raise ValueError( 

1754 "Cannot deconstruct a ManyToManyField pointing to a " 

1755 "model that is swapped in place of more than one model " 

1756 "(%s and %s)" % (kwargs["to"].setting_name, swappable_setting) 

1757 ) 

1758 

1759 kwargs["to"] = SettingsReference( 

1760 kwargs["to"], 

1761 swappable_setting, 

1762 ) 

1763 return name, path, args, kwargs 

1764 

1765 def _get_path_info(self, direct=False, filtered_relation=None): 

1766 """Called by both direct and indirect m2m traversal.""" 

1767 int_model = self.remote_field.through 

1768 linkfield1 = int_model._meta.get_field(self.m2m_field_name()) 

1769 linkfield2 = int_model._meta.get_field(self.m2m_reverse_field_name()) 

1770 if direct: 

1771 join1infos = linkfield1.reverse_path_infos 

1772 if filtered_relation: 

1773 join2infos = linkfield2.get_path_info(filtered_relation) 

1774 else: 

1775 join2infos = linkfield2.path_infos 

1776 else: 

1777 join1infos = linkfield2.reverse_path_infos 

1778 if filtered_relation: 

1779 join2infos = linkfield1.get_path_info(filtered_relation) 

1780 else: 

1781 join2infos = linkfield1.path_infos 

1782 # Get join infos between the last model of join 1 and the first model 

1783 # of join 2. Assume the only reason these may differ is due to model 

1784 # inheritance. 

1785 join1_final = join1infos[-1].to_opts 

1786 join2_initial = join2infos[0].from_opts 

1787 if join1_final is join2_initial: 

1788 intermediate_infos = [] 

1789 elif issubclass(join1_final.model, join2_initial.model): 

1790 intermediate_infos = join1_final.get_path_to_parent(join2_initial.model) 

1791 else: 

1792 intermediate_infos = join2_initial.get_path_from_parent(join1_final.model) 

1793 

1794 return [*join1infos, *intermediate_infos, *join2infos] 

1795 

1796 def get_path_info(self, filtered_relation=None): 

1797 return self._get_path_info(direct=True, filtered_relation=filtered_relation) 

1798 

1799 @cached_property 

1800 def path_infos(self): 

1801 return self.get_path_info() 

1802 

1803 def get_reverse_path_info(self, filtered_relation=None): 

1804 return self._get_path_info(direct=False, filtered_relation=filtered_relation) 

1805 

1806 @cached_property 

1807 def reverse_path_infos(self): 

1808 return self.get_reverse_path_info() 

1809 

1810 def _get_m2m_db_table(self, opts): 

1811 """ 

1812 Function that can be curried to provide the m2m table name for this 

1813 relation. 

1814 """ 

1815 if self.remote_field.through is not None: 

1816 return self.remote_field.through._meta.db_table 

1817 elif self.db_table: 

1818 return self.db_table 

1819 else: 

1820 m2m_table_name = "%s_%s" % (utils.strip_quotes(opts.db_table), self.name) 

1821 return utils.truncate_name(m2m_table_name, connection.ops.max_name_length()) 

1822 

1823 def _get_m2m_attr(self, related, attr): 

1824 """ 

1825 Function that can be curried to provide the source accessor or DB 

1826 column name for the m2m table. 

1827 """ 

1828 cache_attr = "_m2m_%s_cache" % attr 

1829 if hasattr(self, cache_attr): 

1830 return getattr(self, cache_attr) 

1831 if self.remote_field.through_fields is not None: 

1832 link_field_name = self.remote_field.through_fields[0] 

1833 else: 

1834 link_field_name = None 

1835 for f in self.remote_field.through._meta.fields: 

1836 if ( 

1837 f.is_relation 

1838 and f.remote_field.model == related.related_model 

1839 and (link_field_name is None or link_field_name == f.name) 

1840 ): 

1841 setattr(self, cache_attr, getattr(f, attr)) 

1842 return getattr(self, cache_attr) 

1843 

1844 def _get_m2m_reverse_attr(self, related, attr): 

1845 """ 

1846 Function that can be curried to provide the related accessor or DB 

1847 column name for the m2m table. 

1848 """ 

1849 cache_attr = "_m2m_reverse_%s_cache" % attr 

1850 if hasattr(self, cache_attr): 

1851 return getattr(self, cache_attr) 

1852 found = False 

1853 if self.remote_field.through_fields is not None: 

1854 link_field_name = self.remote_field.through_fields[1] 

1855 else: 

1856 link_field_name = None 

1857 for f in self.remote_field.through._meta.fields: 

1858 if f.is_relation and f.remote_field.model == related.model: 

1859 if link_field_name is None and related.related_model == related.model: 

1860 # If this is an m2m-intermediate to self, 

1861 # the first foreign key you find will be 

1862 # the source column. Keep searching for 

1863 # the second foreign key. 

1864 if found: 

1865 setattr(self, cache_attr, getattr(f, attr)) 

1866 break 

1867 else: 

1868 found = True 

1869 elif link_field_name is None or link_field_name == f.name: 

1870 setattr(self, cache_attr, getattr(f, attr)) 

1871 break 

1872 return getattr(self, cache_attr) 

1873 

1874 def contribute_to_class(self, cls, name, **kwargs): 

1875 # To support multiple relations to self, it's useful to have a non-None 

1876 # related name on symmetrical relations for internal reasons. The 

1877 # concept doesn't make a lot of sense externally ("you want me to 

1878 # specify *what* on my non-reversible relation?!"), so we set it up 

1879 # automatically. The funky name reduces the chance of an accidental 

1880 # clash. 

1881 if self.remote_field.symmetrical and ( 

1882 self.remote_field.model == RECURSIVE_RELATIONSHIP_CONSTANT 

1883 or self.remote_field.model == cls._meta.object_name 

1884 ): 

1885 self.remote_field.related_name = "%s_rel_+" % name 

1886 elif self.remote_field.is_hidden(): 

1887 # If the backwards relation is disabled, replace the original 

1888 # related_name with one generated from the m2m field name. Django 

1889 # still uses backwards relations internally and we need to avoid 

1890 # clashes between multiple m2m fields with related_name == '+'. 

1891 self.remote_field.related_name = "_%s_%s_%s_+" % ( 

1892 cls._meta.app_label, 

1893 cls.__name__.lower(), 

1894 name, 

1895 ) 

1896 

1897 super().contribute_to_class(cls, name, **kwargs) 

1898 

1899 # The intermediate m2m model is not auto created if: 

1900 # 1) There is a manually specified intermediate, or 

1901 # 2) The class owning the m2m field is abstract. 

1902 # 3) The class owning the m2m field has been swapped out. 

1903 if not cls._meta.abstract: 

1904 if self.remote_field.through: 

1905 

1906 def resolve_through_model(_, model, field): 

1907 field.remote_field.through = model 

1908 

1909 lazy_related_operation( 

1910 resolve_through_model, cls, self.remote_field.through, field=self 

1911 ) 

1912 elif not cls._meta.swapped: 

1913 self.remote_field.through = create_many_to_many_intermediary_model( 

1914 self, cls 

1915 ) 

1916 

1917 # Add the descriptor for the m2m relation. 

1918 setattr(cls, self.name, ManyToManyDescriptor(self.remote_field, reverse=False)) 

1919 

1920 # Set up the accessor for the m2m table name for the relation. 

1921 self.m2m_db_table = partial(self._get_m2m_db_table, cls._meta) 

1922 

1923 def contribute_to_related_class(self, cls, related): 

1924 # Internal M2Ms (i.e., those with a related name ending with '+') 

1925 # and swapped models don't get a related descriptor. 

1926 if ( 

1927 not self.remote_field.is_hidden() 

1928 and not related.related_model._meta.swapped 

1929 ): 

1930 setattr( 

1931 cls, 

1932 related.get_accessor_name(), 

1933 ManyToManyDescriptor(self.remote_field, reverse=True), 

1934 ) 

1935 

1936 # Set up the accessors for the column names on the m2m table. 

1937 self.m2m_column_name = partial(self._get_m2m_attr, related, "column") 

1938 self.m2m_reverse_name = partial(self._get_m2m_reverse_attr, related, "column") 

1939 

1940 self.m2m_field_name = partial(self._get_m2m_attr, related, "name") 

1941 self.m2m_reverse_field_name = partial( 

1942 self._get_m2m_reverse_attr, related, "name" 

1943 ) 

1944 

1945 get_m2m_rel = partial(self._get_m2m_attr, related, "remote_field") 

1946 self.m2m_target_field_name = lambda: get_m2m_rel().field_name 

1947 get_m2m_reverse_rel = partial( 

1948 self._get_m2m_reverse_attr, related, "remote_field" 

1949 ) 

1950 self.m2m_reverse_target_field_name = lambda: get_m2m_reverse_rel().field_name 

1951 

1952 def set_attributes_from_rel(self): 

1953 pass 

1954 

1955 def value_from_object(self, obj): 

1956 return [] if obj.pk is None else list(getattr(obj, self.attname).all()) 

1957 

1958 def save_form_data(self, instance, data): 

1959 getattr(instance, self.attname).set(data) 

1960 

1961 def formfield(self, *, using=None, **kwargs): 

1962 defaults = { 

1963 "form_class": forms.ModelMultipleChoiceField, 

1964 "queryset": self.remote_field.model._default_manager.using(using), 

1965 **kwargs, 

1966 } 

1967 # If initial is passed in, it's a list of related objects, but the 

1968 # MultipleChoiceField takes a list of IDs. 

1969 if defaults.get("initial") is not None: 

1970 initial = defaults["initial"] 

1971 if callable(initial): 

1972 initial = initial() 

1973 defaults["initial"] = [i.pk for i in initial] 

1974 return super().formfield(**defaults) 

1975 

1976 def db_check(self, connection): 

1977 return None 

1978 

1979 def db_type(self, connection): 

1980 # A ManyToManyField is not represented by a single column, 

1981 # so return None. 

1982 return None 

1983 

1984 def db_parameters(self, connection): 

1985 return {"type": None, "check": None}