Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/django/db/models/fields/related.py: 72%

739 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

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("+")): 135 ↛ 136line 135 didn't jump to line 136, because the condition on line 135 was never true

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("_"): 159 ↛ 160line 159 didn't jump to line 160, because the condition on line 159 was never true

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: 172 ↛ 173line 172 didn't jump to line 173, because the condition on line 172 was never true

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 ( 195 ↛ 198line 195 didn't jump to line 198, because the condition on line 195 was never true

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 ( 209 ↛ 214line 209 didn't jump to line 214

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): 235 ↛ 236line 235 didn't jump to line 236, because the condition on line 235 was never true

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: 267 ↛ 268line 267 didn't jump to line 268, because the condition on line 267 was never true

268 errors.append( 

269 checks.Error( 

270 "Reverse accessor for '%s' clashes with field name '%s'." 

271 % (field_name, clash_name), 

272 hint=( 

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

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

275 ) 

276 % (clash_name, field_name), 

277 obj=self, 

278 id="fields.E302", 

279 ) 

280 ) 

281 

282 if clash_field.name == rel_query_name: 282 ↛ 283line 282 didn't jump to line 283, because the condition on line 282 was never true

283 errors.append( 

284 checks.Error( 

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

286 % (field_name, clash_name), 

287 hint=( 

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

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

290 ) 

291 % (clash_name, field_name), 

292 obj=self, 

293 id="fields.E303", 

294 ) 

295 ) 

296 

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

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

299 # Model.m2m accessor. 

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

301 for clash_field in potential_clashes: 

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

303 clash_name = "%s.%s" % ( 

304 clash_field.related_model._meta.label, 

305 clash_field.field.name, 

306 ) 

307 if not rel_is_hidden and clash_field.get_accessor_name() == rel_name: 307 ↛ 308line 307 didn't jump to line 308, because the condition on line 307 was never true

308 errors.append( 

309 checks.Error( 

310 "Reverse accessor for '%s' clashes with reverse accessor for " 

311 "'%s'." % (field_name, clash_name), 

312 hint=( 

313 "Add or change a related_name argument " 

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

315 ) 

316 % (field_name, clash_name), 

317 obj=self, 

318 id="fields.E304", 

319 ) 

320 ) 

321 

322 if clash_field.get_accessor_name() == rel_query_name: 322 ↛ 323line 322 didn't jump to line 323, because the condition on line 322 was never true

323 errors.append( 

324 checks.Error( 

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

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

327 hint=( 

328 "Add or change a related_name argument " 

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

330 ) 

331 % (field_name, clash_name), 

332 obj=self, 

333 id="fields.E305", 

334 ) 

335 ) 

336 

337 return errors 

338 

339 def db_type(self, connection): 

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

341 # columns from another table. 

342 return None 

343 

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

345 

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

347 

348 self.opts = cls._meta 

349 

350 if not cls._meta.abstract: 

351 if self.remote_field.related_name: 

352 related_name = self.remote_field.related_name 

353 else: 

354 related_name = self.opts.default_related_name 

355 if related_name: 

356 related_name = related_name % { 

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

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

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

360 } 

361 self.remote_field.related_name = related_name 

362 

363 if self.remote_field.related_query_name: 

364 related_query_name = self.remote_field.related_query_name % { 

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

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

367 } 

368 self.remote_field.related_query_name = related_query_name 

369 

370 def resolve_related_class(model, related, field): 

371 field.remote_field.model = related 

372 field.do_related_class(related, model) 

373 

374 lazy_related_operation( 

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

376 ) 

377 

378 def deconstruct(self): 

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

380 if self._limit_choices_to: 380 ↛ 381line 380 didn't jump to line 381, because the condition on line 380 was never true

381 kwargs["limit_choices_to"] = self._limit_choices_to 

382 if self._related_name is not None: 

383 kwargs["related_name"] = self._related_name 

384 if self._related_query_name is not None: 

385 kwargs["related_query_name"] = self._related_query_name 

386 return name, path, args, kwargs 

387 

388 def get_forward_related_filter(self, obj): 

389 """ 

390 Return the keyword arguments that when supplied to 

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

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

393 returned by related descriptors. obj is an instance of 

394 self.related_field.model. 

395 """ 

396 return { 

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

398 for _, rh_field in self.related_fields 

399 } 

400 

401 def get_reverse_related_filter(self, obj): 

402 """ 

403 Complement to get_forward_related_filter(). Return the keyword 

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

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

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

407 """ 

408 base_filter = ( 

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

410 for lh_field, rh_field in self.related_fields 

411 ) 

412 descriptor_filter = self.get_extra_descriptor_filter(obj) 

413 base_q = Q(*base_filter) 

414 if isinstance(descriptor_filter, dict): 414 ↛ 416line 414 didn't jump to line 416, because the condition on line 414 was never false

415 return base_q & Q(**descriptor_filter) 

416 elif descriptor_filter: 

417 return base_q & descriptor_filter 

418 return base_q 

419 

420 @property 

421 def swappable_setting(self): 

422 """ 

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

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

425 """ 

426 if self.swappable: 426 ↛ 433line 426 didn't jump to line 433, because the condition on line 426 was never false

427 # Work out string form of "to" 

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

429 to_string = self.remote_field.model 

430 else: 

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

432 return apps.get_swappable_settings_name(to_string) 

433 return None 

434 

435 def set_attributes_from_rel(self): 

436 self.name = self.name or ( 

437 self.remote_field.model._meta.model_name 

438 + "_" 

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

440 ) 

441 if self.verbose_name is None: 441 ↛ 442line 441 didn't jump to line 442, because the condition on line 441 was never true

442 self.verbose_name = self.remote_field.model._meta.verbose_name 

443 self.remote_field.set_field_name() 

444 

445 def do_related_class(self, other, cls): 

446 self.set_attributes_from_rel() 

447 self.contribute_to_related_class(other, self.remote_field) 

448 

449 def get_limit_choices_to(self): 

450 """ 

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

452 

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

454 returned. 

455 """ 

456 if callable(self.remote_field.limit_choices_to): 456 ↛ 457line 456 didn't jump to line 457, because the condition on line 456 was never true

457 return self.remote_field.limit_choices_to() 

458 return self.remote_field.limit_choices_to 

459 

460 def formfield(self, **kwargs): 

461 """ 

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

463 

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

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

466 being constructed. 

467 """ 

468 defaults = {} 

469 if hasattr(self.remote_field, "get_related_field"): 469 ↛ 479line 469 didn't jump to line 479, because the condition on line 469 was never false

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

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

472 # instantiated. 

473 limit_choices_to = self.remote_field.limit_choices_to 

474 defaults.update( 

475 { 

476 "limit_choices_to": limit_choices_to, 

477 } 

478 ) 

479 defaults.update(kwargs) 

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

481 

482 def related_query_name(self): 

483 """ 

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

485 table-spanning query. 

486 """ 

487 return ( 

488 self.remote_field.related_query_name 

489 or self.remote_field.related_name 

490 or self.opts.model_name 

491 ) 

492 

493 @property 

494 def target_field(self): 

495 """ 

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

497 model against which the filtering should happen. 

498 """ 

499 target_fields = self.get_path_info()[-1].target_fields 

500 if len(target_fields) > 1: 

501 raise exceptions.FieldError( 

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

503 "was asked for" 

504 ) 

505 return target_fields[0] 

506 

507 def get_cache_name(self): 

508 return self.name 

509 

510 

511class ForeignObject(RelatedField): 

512 """ 

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

514 """ 

515 

516 # Field flags 

517 many_to_many = False 

518 many_to_one = True 

519 one_to_many = False 

520 one_to_one = False 

521 

522 requires_unique_target = True 

523 related_accessor_class = ReverseManyToOneDescriptor 

524 forward_related_accessor_class = ForwardManyToOneDescriptor 

525 rel_class = ForeignObjectRel 

526 

527 def __init__( 

528 self, 

529 to, 

530 on_delete, 

531 from_fields, 

532 to_fields, 

533 rel=None, 

534 related_name=None, 

535 related_query_name=None, 

536 limit_choices_to=None, 

537 parent_link=False, 

538 swappable=True, 

539 **kwargs, 

540 ): 

541 

542 if rel is None: 542 ↛ 543line 542 didn't jump to line 543, because the condition on line 542 was never true

543 rel = self.rel_class( 

544 self, 

545 to, 

546 related_name=related_name, 

547 related_query_name=related_query_name, 

548 limit_choices_to=limit_choices_to, 

549 parent_link=parent_link, 

550 on_delete=on_delete, 

551 ) 

552 

553 super().__init__( 

554 rel=rel, 

555 related_name=related_name, 

556 related_query_name=related_query_name, 

557 limit_choices_to=limit_choices_to, 

558 **kwargs, 

559 ) 

560 

561 self.from_fields = from_fields 

562 self.to_fields = to_fields 

563 self.swappable = swappable 

564 

565 def check(self, **kwargs): 

566 return [ 

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

568 *self._check_to_fields_exist(), 

569 *self._check_unique_target(), 

570 ] 

571 

572 def _check_to_fields_exist(self): 

573 # Skip nonexistent models. 

574 if isinstance(self.remote_field.model, str): 574 ↛ 575line 574 didn't jump to line 575, because the condition on line 574 was never true

575 return [] 

576 

577 errors = [] 

578 for to_field in self.to_fields: 

579 if to_field: 

580 try: 

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

582 except exceptions.FieldDoesNotExist: 

583 errors.append( 

584 checks.Error( 

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

586 "model '%s'." 

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

588 obj=self, 

589 id="fields.E312", 

590 ) 

591 ) 

592 return errors 

593 

594 def _check_unique_target(self): 

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

596 if rel_is_string or not self.requires_unique_target: 596 ↛ 597line 596 didn't jump to line 597, because the condition on line 596 was never true

597 return [] 

598 

599 try: 

600 self.foreign_related_fields 

601 except exceptions.FieldDoesNotExist: 

602 return [] 

603 

604 if not self.foreign_related_fields: 604 ↛ 605line 604 didn't jump to line 605, because the condition on line 604 was never true

605 return [] 

606 

607 unique_foreign_fields = { 

608 frozenset([f.name]) 

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

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

611 } 

612 unique_foreign_fields.update( 

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

614 ) 

615 unique_foreign_fields.update( 

616 { 

617 frozenset(uc.fields) 

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

619 } 

620 ) 

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

622 has_unique_constraint = any(u <= foreign_fields for u in unique_foreign_fields) 622 ↛ exitline 622 didn't finish the generator expression on line 622

623 

624 if not has_unique_constraint and len(self.foreign_related_fields) > 1: 624 ↛ 625line 624 didn't jump to line 625, because the condition on line 624 was never true

625 field_combination = ", ".join( 

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

627 ) 

628 model_name = self.remote_field.model.__name__ 

629 return [ 

630 checks.Error( 

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

632 % (field_combination, model_name), 

633 hint=( 

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

635 "fields to a unique constraint (via unique_together " 

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

637 "model Meta.constraints)." 

638 ), 

639 obj=self, 

640 id="fields.E310", 

641 ) 

642 ] 

643 elif not has_unique_constraint: 643 ↛ 644line 643 didn't jump to line 644, because the condition on line 643 was never true

644 field_name = self.foreign_related_fields[0].name 

645 model_name = self.remote_field.model.__name__ 

646 return [ 

647 checks.Error( 

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

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

650 hint=( 

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

652 "UniqueConstraint (without condition) in the model " 

653 "Meta.constraints." 

654 ), 

655 obj=self, 

656 id="fields.E311", 

657 ) 

658 ] 

659 else: 

660 return [] 

661 

662 def deconstruct(self): 

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

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

665 kwargs["from_fields"] = self.from_fields 

666 kwargs["to_fields"] = self.to_fields 

667 

668 if self.remote_field.parent_link: 

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

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

671 if "." in self.remote_field.model: 671 ↛ 675line 671 didn't jump to line 675, because the condition on line 671 was never false

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

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

674 else: 

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

676 else: 

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

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

679 # of a swap. 

680 swappable_setting = self.swappable_setting 

681 if swappable_setting is not None: 

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

683 if hasattr(kwargs["to"], "setting_name"): 683 ↛ 684line 683 didn't jump to line 684, because the condition on line 683 was never true

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

685 raise ValueError( 

686 "Cannot deconstruct a ForeignKey pointing to a model " 

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

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

689 ) 

690 # Set it 

691 kwargs["to"] = SettingsReference( 

692 kwargs["to"], 

693 swappable_setting, 

694 ) 

695 return name, path, args, kwargs 

696 

697 def resolve_related_fields(self): 

698 if not self.from_fields or len(self.from_fields) != len(self.to_fields): 698 ↛ 699line 698 didn't jump to line 699, because the condition on line 698 was never true

699 raise ValueError( 

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

701 ) 

702 if isinstance(self.remote_field.model, str): 702 ↛ 703line 702 didn't jump to line 703, because the condition on line 702 was never true

703 raise ValueError( 

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

705 ) 

706 related_fields = [] 

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

708 from_field_name = self.from_fields[index] 

709 to_field_name = self.to_fields[index] 

710 from_field = ( 

711 self 

712 if from_field_name == RECURSIVE_RELATIONSHIP_CONSTANT 

713 else self.opts.get_field(from_field_name) 

714 ) 

715 to_field = ( 

716 self.remote_field.model._meta.pk 

717 if to_field_name is None 

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

719 ) 

720 related_fields.append((from_field, to_field)) 

721 return related_fields 

722 

723 @cached_property 

724 def related_fields(self): 

725 return self.resolve_related_fields() 

726 

727 @cached_property 

728 def reverse_related_fields(self): 

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

730 

731 @cached_property 

732 def local_related_fields(self): 

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

734 

735 @cached_property 

736 def foreign_related_fields(self): 

737 return tuple( 

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

739 ) 

740 

741 def get_local_related_value(self, instance): 

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

743 

744 def get_foreign_related_value(self, instance): 

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

746 

747 @staticmethod 

748 def get_instance_value_for_fields(instance, fields): 

749 ret = [] 

750 opts = instance._meta 

751 for field in fields: 

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

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

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

755 if field.primary_key: 

756 possible_parent_link = opts.get_ancestor_link(field.model) 

757 if ( 757 ↛ 764line 757 didn't jump to line 764

758 not possible_parent_link 

759 or possible_parent_link.primary_key 

760 or possible_parent_link.model._meta.abstract 

761 ): 

762 ret.append(instance.pk) 

763 continue 

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

765 return tuple(ret) 

766 

767 def get_attname_column(self): 

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

769 return attname, None 

770 

771 def get_joining_columns(self, reverse_join=False): 

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

773 return tuple( 

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

775 ) 

776 

777 def get_reverse_joining_columns(self): 

778 return self.get_joining_columns(reverse_join=True) 

779 

780 def get_extra_descriptor_filter(self, instance): 

781 """ 

782 Return an extra filter condition for related object fetching when 

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

784 the descriptor of the field. 

785 

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

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

788 joining columns. 

789 

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

791 JOIN and subquery conditions. 

792 """ 

793 return {} 

794 

795 def get_extra_restriction(self, alias, related_alias): 

796 """ 

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

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

799 method. 

800 

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

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

803 

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

805 instance.fieldname related object fetching. 

806 """ 

807 return None 

808 

809 def get_path_info(self, filtered_relation=None): 

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

811 opts = self.remote_field.model._meta 

812 from_opts = self.model._meta 

813 return [ 

814 PathInfo( 

815 from_opts=from_opts, 

816 to_opts=opts, 

817 target_fields=self.foreign_related_fields, 

818 join_field=self, 

819 m2m=False, 

820 direct=True, 

821 filtered_relation=filtered_relation, 

822 ) 

823 ] 

824 

825 def get_reverse_path_info(self, filtered_relation=None): 

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

827 opts = self.model._meta 

828 from_opts = self.remote_field.model._meta 

829 return [ 

830 PathInfo( 

831 from_opts=from_opts, 

832 to_opts=opts, 

833 target_fields=(opts.pk,), 

834 join_field=self.remote_field, 

835 m2m=not self.unique, 

836 direct=False, 

837 filtered_relation=filtered_relation, 

838 ) 

839 ] 

840 

841 @classmethod 

842 @functools.lru_cache(maxsize=None) 

843 def get_lookups(cls): 

844 bases = inspect.getmro(cls) 

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

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

847 return cls.merge_dicts(class_lookups) 

848 

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

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

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

852 

853 def contribute_to_related_class(self, cls, related): 

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

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

856 if ( 

857 not self.remote_field.is_hidden() 

858 and not related.related_model._meta.swapped 

859 ): 

860 setattr( 

861 cls._meta.concrete_model, 

862 related.get_accessor_name(), 

863 self.related_accessor_class(related), 

864 ) 

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

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

867 # model load time. 

868 if self.remote_field.limit_choices_to: 868 ↛ 869line 868 didn't jump to line 869, because the condition on line 868 was never true

869 cls._meta.related_fkey_lookups.append( 

870 self.remote_field.limit_choices_to 

871 ) 

872 

873 

874ForeignObject.register_lookup(RelatedIn) 

875ForeignObject.register_lookup(RelatedExact) 

876ForeignObject.register_lookup(RelatedLessThan) 

877ForeignObject.register_lookup(RelatedGreaterThan) 

878ForeignObject.register_lookup(RelatedGreaterThanOrEqual) 

879ForeignObject.register_lookup(RelatedLessThanOrEqual) 

880ForeignObject.register_lookup(RelatedIsNull) 

881 

882 

883class ForeignKey(ForeignObject): 

884 """ 

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

886 to hold the remote value. 

887 

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

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

890 """ 

891 

892 descriptor_class = ForeignKeyDeferredAttribute 

893 # Field flags 

894 many_to_many = False 

895 many_to_one = True 

896 one_to_many = False 

897 one_to_one = False 

898 

899 rel_class = ManyToOneRel 

900 

901 empty_strings_allowed = False 

902 default_error_messages = { 

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

904 } 

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

906 

907 def __init__( 

908 self, 

909 to, 

910 on_delete, 

911 related_name=None, 

912 related_query_name=None, 

913 limit_choices_to=None, 

914 parent_link=False, 

915 to_field=None, 

916 db_constraint=True, 

917 **kwargs, 

918 ): 

919 try: 

920 to._meta.model_name 

921 except AttributeError: 

922 if not isinstance(to, str): 922 ↛ 923line 922 didn't jump to line 923, because the condition on line 922 was never true

923 raise TypeError( 

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

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

926 % ( 

927 self.__class__.__name__, 

928 to, 

929 RECURSIVE_RELATIONSHIP_CONSTANT, 

930 ) 

931 ) 

932 else: 

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

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

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

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

937 if not callable(on_delete): 937 ↛ 938line 937 didn't jump to line 938, because the condition on line 937 was never true

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

939 

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

941 self, 

942 to, 

943 to_field, 

944 related_name=related_name, 

945 related_query_name=related_query_name, 

946 limit_choices_to=limit_choices_to, 

947 parent_link=parent_link, 

948 on_delete=on_delete, 

949 ) 

950 kwargs.setdefault("db_index", True) 

951 

952 super().__init__( 

953 to, 

954 on_delete, 

955 related_name=related_name, 

956 related_query_name=related_query_name, 

957 limit_choices_to=limit_choices_to, 

958 from_fields=[RECURSIVE_RELATIONSHIP_CONSTANT], 

959 to_fields=[to_field], 

960 **kwargs, 

961 ) 

962 self.db_constraint = db_constraint 

963 

964 def check(self, **kwargs): 

965 return [ 

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

967 *self._check_on_delete(), 

968 *self._check_unique(), 

969 ] 

970 

971 def _check_on_delete(self): 

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

973 if on_delete == SET_NULL and not self.null: 973 ↛ 974line 973 didn't jump to line 974, because the condition on line 973 was never true

974 return [ 

975 checks.Error( 

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

977 hint=( 

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

979 "rule." 

980 ), 

981 obj=self, 

982 id="fields.E320", 

983 ) 

984 ] 

985 elif on_delete == SET_DEFAULT and not self.has_default(): 985 ↛ 986line 985 didn't jump to line 986, because the condition on line 985 was never true

986 return [ 

987 checks.Error( 

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

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

990 obj=self, 

991 id="fields.E321", 

992 ) 

993 ] 

994 else: 

995 return [] 

996 

997 def _check_unique(self, **kwargs): 

998 return ( 

999 [ 

1000 checks.Warning( 

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

1002 "a OneToOneField.", 

1003 hint=( 

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

1005 "OneToOneField." 

1006 ), 

1007 obj=self, 

1008 id="fields.W342", 

1009 ) 

1010 ] 

1011 if self.unique 

1012 else [] 

1013 ) 

1014 

1015 def deconstruct(self): 

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

1017 del kwargs["to_fields"] 

1018 del kwargs["from_fields"] 

1019 # Handle the simpler arguments 

1020 if self.db_index: 1020 ↛ 1023line 1020 didn't jump to line 1023, because the condition on line 1020 was never false

1021 del kwargs["db_index"] 

1022 else: 

1023 kwargs["db_index"] = False 

1024 if self.db_constraint is not True: 1024 ↛ 1025line 1024 didn't jump to line 1025, because the condition on line 1024 was never true

1025 kwargs["db_constraint"] = self.db_constraint 

1026 # Rel needs more work. 

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

1028 if self.remote_field.field_name and ( 1028 ↛ 1032line 1028 didn't jump to line 1032, because the condition on line 1028 was never true

1029 not to_meta 

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

1031 ): 

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

1033 return name, path, args, kwargs 

1034 

1035 def to_python(self, value): 

1036 return self.target_field.to_python(value) 

1037 

1038 @property 

1039 def target_field(self): 

1040 return self.foreign_related_fields[0] 

1041 

1042 def get_reverse_path_info(self, filtered_relation=None): 

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

1044 opts = self.model._meta 

1045 from_opts = self.remote_field.model._meta 

1046 return [ 

1047 PathInfo( 

1048 from_opts=from_opts, 

1049 to_opts=opts, 

1050 target_fields=(opts.pk,), 

1051 join_field=self.remote_field, 

1052 m2m=not self.unique, 

1053 direct=False, 

1054 filtered_relation=filtered_relation, 

1055 ) 

1056 ] 

1057 

1058 def validate(self, value, model_instance): 

1059 if self.remote_field.parent_link: 

1060 return 

1061 super().validate(value, model_instance) 

1062 if value is None: 

1063 return 

1064 

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

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

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

1068 ) 

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

1070 if not qs.exists(): 

1071 raise exceptions.ValidationError( 

1072 self.error_messages["invalid"], 

1073 code="invalid", 

1074 params={ 

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

1076 "pk": value, 

1077 "field": self.remote_field.field_name, 

1078 "value": value, 

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

1080 ) 

1081 

1082 def resolve_related_fields(self): 

1083 related_fields = super().resolve_related_fields() 

1084 for from_field, to_field in related_fields: 

1085 if ( 1085 ↛ 1089line 1085 didn't jump to line 1089

1086 to_field 

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

1088 ): 

1089 raise exceptions.FieldError( 

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

1091 "'%s'." 

1092 % ( 

1093 self.model._meta.label, 

1094 self.name, 

1095 to_field.name, 

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

1097 ) 

1098 ) 

1099 return related_fields 

1100 

1101 def get_attname(self): 

1102 return "%s_id" % self.name 

1103 

1104 def get_attname_column(self): 

1105 attname = self.get_attname() 

1106 column = self.db_column or attname 

1107 return attname, column 

1108 

1109 def get_default(self): 

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

1111 field_default = super().get_default() 

1112 if isinstance(field_default, self.remote_field.model): 1112 ↛ 1113line 1112 didn't jump to line 1113, because the condition on line 1112 was never true

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

1114 return field_default 

1115 

1116 def get_db_prep_save(self, value, connection): 

1117 if value is None or ( 

1118 value == "" 

1119 and ( 

1120 not self.target_field.empty_strings_allowed 

1121 or connection.features.interprets_empty_strings_as_nulls 

1122 ) 

1123 ): 

1124 return None 

1125 else: 

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

1127 

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

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

1130 

1131 def get_prep_value(self, value): 

1132 return self.target_field.get_prep_value(value) 

1133 

1134 def contribute_to_related_class(self, cls, related): 

1135 super().contribute_to_related_class(cls, related) 

1136 if self.remote_field.field_name is None: 1136 ↛ 1137line 1136 didn't jump to line 1137, because the condition on line 1136 was never true

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

1138 

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

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

1141 raise ValueError( 

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

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

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

1145 ) 

1146 return super().formfield( 

1147 **{ 

1148 "form_class": forms.ModelChoiceField, 

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

1150 "to_field_name": self.remote_field.field_name, 

1151 **kwargs, 

1152 "blank": self.blank, 

1153 } 

1154 ) 

1155 

1156 def db_check(self, connection): 

1157 return [] 

1158 

1159 def db_type(self, connection): 

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

1161 

1162 def db_parameters(self, connection): 

1163 return {"type": self.db_type(connection), "check": self.db_check(connection)} 

1164 

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

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

1167 return None 

1168 return value 

1169 

1170 def get_db_converters(self, connection): 

1171 converters = super().get_db_converters(connection) 

1172 if connection.features.interprets_empty_strings_as_nulls: 1172 ↛ 1173line 1172 didn't jump to line 1173, because the condition on line 1172 was never true

1173 converters += [self.convert_empty_strings] 

1174 return converters 

1175 

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

1177 if output_field is None: 

1178 output_field = self.target_field 

1179 while isinstance(output_field, ForeignKey): 

1180 output_field = output_field.target_field 

1181 if output_field is self: 1181 ↛ 1182line 1181 didn't jump to line 1182, because the condition on line 1181 was never true

1182 raise ValueError("Cannot resolve output_field.") 

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

1184 

1185 

1186class OneToOneField(ForeignKey): 

1187 """ 

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

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

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

1191 be one), rather than returning a list. 

1192 """ 

1193 

1194 # Field flags 

1195 many_to_many = False 

1196 many_to_one = False 

1197 one_to_many = False 

1198 one_to_one = True 

1199 

1200 related_accessor_class = ReverseOneToOneDescriptor 

1201 forward_related_accessor_class = ForwardOneToOneDescriptor 

1202 rel_class = OneToOneRel 

1203 

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

1205 

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

1207 kwargs["unique"] = True 

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

1209 

1210 def deconstruct(self): 

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

1212 if "unique" in kwargs: 1212 ↛ 1214line 1212 didn't jump to line 1214, because the condition on line 1212 was never false

1213 del kwargs["unique"] 

1214 return name, path, args, kwargs 

1215 

1216 def formfield(self, **kwargs): 

1217 if self.remote_field.parent_link: 

1218 return None 

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

1220 

1221 def save_form_data(self, instance, data): 

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

1223 setattr(instance, self.name, data) 

1224 else: 

1225 setattr(instance, self.attname, data) 

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

1227 # will reassign attname using the related object pk. 

1228 if data is None: 

1229 setattr(instance, self.name, data) 

1230 

1231 def _check_unique(self, **kwargs): 

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

1233 return [] 

1234 

1235 

1236def create_many_to_many_intermediary_model(field, klass): 

1237 from django.db import models 

1238 

1239 def set_managed(model, related, through): 

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

1241 

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

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

1244 lazy_related_operation(set_managed, klass, to_model, name) 

1245 

1246 to = make_model_tuple(to_model)[1] 

1247 from_ = klass._meta.model_name 

1248 if to == from_: 1248 ↛ 1249line 1248 didn't jump to line 1249, because the condition on line 1248 was never true

1249 to = "to_%s" % to 

1250 from_ = "from_%s" % from_ 

1251 

1252 meta = type( 

1253 "Meta", 

1254 (), 

1255 { 

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

1257 "auto_created": klass, 

1258 "app_label": klass._meta.app_label, 

1259 "db_tablespace": klass._meta.db_tablespace, 

1260 "unique_together": (from_, to), 

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

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

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

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

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

1266 }, 

1267 ) 

1268 # Construct and return the new class. 

1269 return type( 

1270 name, 

1271 (models.Model,), 

1272 { 

1273 "Meta": meta, 

1274 "__module__": klass.__module__, 

1275 from_: models.ForeignKey( 

1276 klass, 

1277 related_name="%s+" % name, 

1278 db_tablespace=field.db_tablespace, 

1279 db_constraint=field.remote_field.db_constraint, 

1280 on_delete=CASCADE, 

1281 ), 

1282 to: models.ForeignKey( 

1283 to_model, 

1284 related_name="%s+" % name, 

1285 db_tablespace=field.db_tablespace, 

1286 db_constraint=field.remote_field.db_constraint, 

1287 on_delete=CASCADE, 

1288 ), 

1289 }, 

1290 ) 

1291 

1292 

1293class ManyToManyField(RelatedField): 

1294 """ 

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

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

1297 

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

1299 create_many_to_many_intermediary_model factory to automatically generate 

1300 the intermediary model. 

1301 """ 

1302 

1303 # Field flags 

1304 many_to_many = True 

1305 many_to_one = False 

1306 one_to_many = False 

1307 one_to_one = False 

1308 

1309 rel_class = ManyToManyRel 

1310 

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

1312 

1313 def __init__( 

1314 self, 

1315 to, 

1316 related_name=None, 

1317 related_query_name=None, 

1318 limit_choices_to=None, 

1319 symmetrical=None, 

1320 through=None, 

1321 through_fields=None, 

1322 db_constraint=True, 

1323 db_table=None, 

1324 swappable=True, 

1325 **kwargs, 

1326 ): 

1327 try: 

1328 to._meta 

1329 except AttributeError: 

1330 if not isinstance(to, str): 1330 ↛ 1331line 1330 didn't jump to line 1331, because the condition on line 1330 was never true

1331 raise TypeError( 

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

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

1334 % ( 

1335 self.__class__.__name__, 

1336 to, 

1337 RECURSIVE_RELATIONSHIP_CONSTANT, 

1338 ) 

1339 ) 

1340 

1341 if symmetrical is None: 1341 ↛ 1344line 1341 didn't jump to line 1344, because the condition on line 1341 was never false

1342 symmetrical = to == RECURSIVE_RELATIONSHIP_CONSTANT 

1343 

1344 if through is not None and db_table is not None: 1344 ↛ 1345line 1344 didn't jump to line 1345, because the condition on line 1344 was never true

1345 raise ValueError( 

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

1347 ) 

1348 

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

1350 self, 

1351 to, 

1352 related_name=related_name, 

1353 related_query_name=related_query_name, 

1354 limit_choices_to=limit_choices_to, 

1355 symmetrical=symmetrical, 

1356 through=through, 

1357 through_fields=through_fields, 

1358 db_constraint=db_constraint, 

1359 ) 

1360 self.has_null_arg = "null" in kwargs 

1361 

1362 super().__init__( 

1363 related_name=related_name, 

1364 related_query_name=related_query_name, 

1365 limit_choices_to=limit_choices_to, 

1366 **kwargs, 

1367 ) 

1368 

1369 self.db_table = db_table 

1370 self.swappable = swappable 

1371 

1372 def check(self, **kwargs): 

1373 return [ 

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

1375 *self._check_unique(**kwargs), 

1376 *self._check_relationship_model(**kwargs), 

1377 *self._check_ignored_options(**kwargs), 

1378 *self._check_table_uniqueness(**kwargs), 

1379 ] 

1380 

1381 def _check_unique(self, **kwargs): 

1382 if self.unique: 1382 ↛ 1383line 1382 didn't jump to line 1383, because the condition on line 1382 was never true

1383 return [ 

1384 checks.Error( 

1385 "ManyToManyFields cannot be unique.", 

1386 obj=self, 

1387 id="fields.E330", 

1388 ) 

1389 ] 

1390 return [] 

1391 

1392 def _check_ignored_options(self, **kwargs): 

1393 warnings = [] 

1394 

1395 if self.has_null_arg: 1395 ↛ 1396line 1395 didn't jump to line 1396, because the condition on line 1395 was never true

1396 warnings.append( 

1397 checks.Warning( 

1398 "null has no effect on ManyToManyField.", 

1399 obj=self, 

1400 id="fields.W340", 

1401 ) 

1402 ) 

1403 

1404 if self._validators: 1404 ↛ 1405line 1404 didn't jump to line 1405, because the condition on line 1404 was never true

1405 warnings.append( 

1406 checks.Warning( 

1407 "ManyToManyField does not support validators.", 

1408 obj=self, 

1409 id="fields.W341", 

1410 ) 

1411 ) 

1412 if self.remote_field.symmetrical and self._related_name: 1412 ↛ 1413line 1412 didn't jump to line 1413, because the condition on line 1412 was never true

1413 warnings.append( 

1414 checks.Warning( 

1415 "related_name has no effect on ManyToManyField " 

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

1417 obj=self, 

1418 id="fields.W345", 

1419 ) 

1420 ) 

1421 

1422 return warnings 

1423 

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

1425 if hasattr(self.remote_field.through, "_meta"): 1425 ↛ 1431line 1425 didn't jump to line 1431, because the condition on line 1425 was never false

1426 qualified_model_name = "%s.%s" % ( 

1427 self.remote_field.through._meta.app_label, 

1428 self.remote_field.through.__name__, 

1429 ) 

1430 else: 

1431 qualified_model_name = self.remote_field.through 

1432 

1433 errors = [] 

1434 

1435 if self.remote_field.through not in self.opts.apps.get_models( 1435 ↛ 1439line 1435 didn't jump to line 1439, because the condition on line 1435 was never true

1436 include_auto_created=True 

1437 ): 

1438 # The relationship model is not installed. 

1439 errors.append( 

1440 checks.Error( 

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

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

1443 obj=self, 

1444 id="fields.E331", 

1445 ) 

1446 ) 

1447 

1448 else: 

1449 assert from_model is not None, ( 

1450 "ManyToManyField with intermediate " 

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

1452 "where the field is attached to." 

1453 ) 

1454 # Set some useful local variables 

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

1456 from_model_name = from_model._meta.object_name 

1457 if isinstance(to_model, str): 1457 ↛ 1458line 1457 didn't jump to line 1458, because the condition on line 1457 was never true

1458 to_model_name = to_model 

1459 else: 

1460 to_model_name = to_model._meta.object_name 

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

1462 self_referential = from_model == to_model 

1463 # Count foreign keys in intermediate model 

1464 if self_referential: 1464 ↛ 1465line 1464 didn't jump to line 1465, because the condition on line 1464 was never true

1465 seen_self = sum( 

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

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

1468 ) 

1469 

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

1471 errors.append( 

1472 checks.Error( 

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

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

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

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

1477 "through_fields keyword argument." 

1478 % (self, from_model_name), 

1479 hint=( 

1480 "Use through_fields to specify which two foreign keys " 

1481 "Django should use." 

1482 ), 

1483 obj=self.remote_field.through, 

1484 id="fields.E333", 

1485 ) 

1486 ) 

1487 

1488 else: 

1489 # Count foreign keys in relationship model 

1490 seen_from = sum( 

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

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

1493 ) 

1494 seen_to = sum( 

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

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

1497 ) 

1498 

1499 if seen_from > 1 and not self.remote_field.through_fields: 1499 ↛ 1500line 1499 didn't jump to line 1500, because the condition on line 1499 was never true

1500 errors.append( 

1501 checks.Error( 

1502 ( 

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

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

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

1506 "which foreign key Django should use via the " 

1507 "through_fields keyword argument." 

1508 ) 

1509 % (self, from_model_name), 

1510 hint=( 

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

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

1513 ) 

1514 % ( 

1515 RECURSIVE_RELATIONSHIP_CONSTANT, 

1516 relationship_model_name, 

1517 ), 

1518 obj=self, 

1519 id="fields.E334", 

1520 ) 

1521 ) 

1522 

1523 if seen_to > 1 and not self.remote_field.through_fields: 1523 ↛ 1524line 1523 didn't jump to line 1524, because the condition on line 1523 was never true

1524 errors.append( 

1525 checks.Error( 

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

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

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

1529 "which foreign key Django should use via the " 

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

1531 hint=( 

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

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

1534 ) 

1535 % ( 

1536 RECURSIVE_RELATIONSHIP_CONSTANT, 

1537 relationship_model_name, 

1538 ), 

1539 obj=self, 

1540 id="fields.E335", 

1541 ) 

1542 ) 

1543 

1544 if seen_from == 0 or seen_to == 0: 1544 ↛ 1545line 1544 didn't jump to line 1545, because the condition on line 1544 was never true

1545 errors.append( 

1546 checks.Error( 

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

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

1549 % (self, from_model_name, to_model_name), 

1550 obj=self.remote_field.through, 

1551 id="fields.E336", 

1552 ) 

1553 ) 

1554 

1555 # Validate `through_fields`. 

1556 if self.remote_field.through_fields is not None: 1556 ↛ 1559line 1556 didn't jump to line 1559, because the condition on line 1556 was never true

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

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

1559 if not ( 

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

1561 and self.remote_field.through_fields[0] 

1562 and self.remote_field.through_fields[1] 

1563 ): 

1564 errors.append( 

1565 checks.Error( 

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

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

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

1569 hint=( 

1570 "Make sure you specify 'through_fields' as " 

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

1572 ), 

1573 obj=self, 

1574 id="fields.E337", 

1575 ) 

1576 ) 

1577 

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

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

1580 # expected models. 

1581 else: 

1582 assert from_model is not None, ( 

1583 "ManyToManyField with intermediate " 

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

1585 "where the field is attached to." 

1586 ) 

1587 

1588 source, through, target = ( 

1589 from_model, 

1590 self.remote_field.through, 

1591 self.remote_field.model, 

1592 ) 

1593 source_field_name, target_field_name = self.remote_field.through_fields[ 

1594 :2 

1595 ] 

1596 

1597 for field_name, related_model in ( 

1598 (source_field_name, source), 

1599 (target_field_name, target), 

1600 ): 

1601 

1602 possible_field_names = [] 

1603 for f in through._meta.fields: 

1604 if ( 

1605 hasattr(f, "remote_field") 

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

1607 ): 

1608 possible_field_names.append(f.name) 

1609 if possible_field_names: 

1610 hint = ( 

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

1612 "%s?" 

1613 % ( 

1614 related_model._meta.object_name, 

1615 ", ".join(possible_field_names), 

1616 ) 

1617 ) 

1618 else: 

1619 hint = None 

1620 

1621 try: 

1622 field = through._meta.get_field(field_name) 

1623 except exceptions.FieldDoesNotExist: 

1624 errors.append( 

1625 checks.Error( 

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

1627 % (qualified_model_name, field_name), 

1628 hint=hint, 

1629 obj=self, 

1630 id="fields.E338", 

1631 ) 

1632 ) 

1633 else: 

1634 if not ( 

1635 hasattr(field, "remote_field") 

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

1637 == related_model 

1638 ): 

1639 errors.append( 

1640 checks.Error( 

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

1642 % ( 

1643 through._meta.object_name, 

1644 field_name, 

1645 related_model._meta.object_name, 

1646 ), 

1647 hint=hint, 

1648 obj=self, 

1649 id="fields.E339", 

1650 ) 

1651 ) 

1652 

1653 return errors 

1654 

1655 def _check_table_uniqueness(self, **kwargs): 

1656 if ( 1656 ↛ 1660line 1656 didn't jump to line 1660

1657 isinstance(self.remote_field.through, str) 

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

1659 ): 

1660 return [] 

1661 registered_tables = { 

1662 model._meta.db_table: model 

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

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

1665 } 

1666 m2m_db_table = self.m2m_db_table() 

1667 model = registered_tables.get(m2m_db_table) 

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

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

1670 if ( 1670 ↛ 1675line 1670 didn't jump to line 1675

1671 model 

1672 and model._meta.concrete_model 

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

1674 ): 

1675 if model._meta.auto_created: 

1676 

1677 def _get_field_name(model): 

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

1679 if field.remote_field.through is model: 

1680 return field.name 

1681 

1682 opts = model._meta.auto_created._meta 

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

1684 else: 

1685 clashing_obj = model._meta.label 

1686 if settings.DATABASE_ROUTERS: 

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

1688 error_hint = ( 

1689 "You have configured settings.DATABASE_ROUTERS. Verify " 

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

1691 "database." % clashing_obj 

1692 ) 

1693 else: 

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

1695 error_hint = None 

1696 return [ 

1697 error_class( 

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

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

1700 obj=self, 

1701 hint=error_hint, 

1702 id=error_id, 

1703 ) 

1704 ] 

1705 return [] 

1706 

1707 def deconstruct(self): 

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

1709 # Handle the simpler arguments. 

1710 if self.db_table is not None: 1710 ↛ 1711line 1710 didn't jump to line 1711, because the condition on line 1710 was never true

1711 kwargs["db_table"] = self.db_table 

1712 if self.remote_field.db_constraint is not True: 1712 ↛ 1713line 1712 didn't jump to line 1713, because the condition on line 1712 was never true

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

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

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

1716 if "." in self.remote_field.model: 1716 ↛ 1720line 1716 didn't jump to line 1720, because the condition on line 1716 was never false

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

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

1719 else: 

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

1721 else: 

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

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

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

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

1726 elif not self.remote_field.through._meta.auto_created: 1726 ↛ 1727line 1726 didn't jump to line 1727, because the condition on line 1726 was never true

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

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

1729 # of a swap. 

1730 swappable_setting = self.swappable_setting 

1731 if swappable_setting is not None: 

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

1733 if hasattr(kwargs["to"], "setting_name"): 1733 ↛ 1734line 1733 didn't jump to line 1734, because the condition on line 1733 was never true

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

1735 raise ValueError( 

1736 "Cannot deconstruct a ManyToManyField pointing to a " 

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

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

1739 ) 

1740 

1741 kwargs["to"] = SettingsReference( 

1742 kwargs["to"], 

1743 swappable_setting, 

1744 ) 

1745 return name, path, args, kwargs 

1746 

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

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

1749 int_model = self.remote_field.through 

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

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

1752 if direct: 

1753 join1infos = linkfield1.get_reverse_path_info() 

1754 join2infos = linkfield2.get_path_info(filtered_relation) 

1755 else: 

1756 join1infos = linkfield2.get_reverse_path_info() 

1757 join2infos = linkfield1.get_path_info(filtered_relation) 

1758 

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

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

1761 # inheritance. 

1762 join1_final = join1infos[-1].to_opts 

1763 join2_initial = join2infos[0].from_opts 

1764 if join1_final is join2_initial: 1764 ↛ 1766line 1764 didn't jump to line 1766, because the condition on line 1764 was never false

1765 intermediate_infos = [] 

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

1767 intermediate_infos = join1_final.get_path_to_parent(join2_initial.model) 

1768 else: 

1769 intermediate_infos = join2_initial.get_path_from_parent(join1_final.model) 

1770 

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

1772 

1773 def get_path_info(self, filtered_relation=None): 

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

1775 

1776 def get_reverse_path_info(self, filtered_relation=None): 

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

1778 

1779 def _get_m2m_db_table(self, opts): 

1780 """ 

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

1782 relation. 

1783 """ 

1784 if self.remote_field.through is not None: 

1785 return self.remote_field.through._meta.db_table 

1786 elif self.db_table: 1786 ↛ 1787line 1786 didn't jump to line 1787, because the condition on line 1786 was never true

1787 return self.db_table 

1788 else: 

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

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

1791 

1792 def _get_m2m_attr(self, related, attr): 

1793 """ 

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

1795 column name for the m2m table. 

1796 """ 

1797 cache_attr = "_m2m_%s_cache" % attr 

1798 if hasattr(self, cache_attr): 

1799 return getattr(self, cache_attr) 

1800 if self.remote_field.through_fields is not None: 1800 ↛ 1801line 1800 didn't jump to line 1801, because the condition on line 1800 was never true

1801 link_field_name = self.remote_field.through_fields[0] 

1802 else: 

1803 link_field_name = None 

1804 for f in self.remote_field.through._meta.fields: 1804 ↛ exitline 1804 didn't return from function '_get_m2m_attr', because the loop on line 1804 didn't complete

1805 if ( 

1806 f.is_relation 

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

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

1809 ): 

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

1811 return getattr(self, cache_attr) 

1812 

1813 def _get_m2m_reverse_attr(self, related, attr): 

1814 """ 

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

1816 column name for the m2m table. 

1817 """ 

1818 cache_attr = "_m2m_reverse_%s_cache" % attr 

1819 if hasattr(self, cache_attr): 

1820 return getattr(self, cache_attr) 

1821 found = False 

1822 if self.remote_field.through_fields is not None: 1822 ↛ 1823line 1822 didn't jump to line 1823, because the condition on line 1822 was never true

1823 link_field_name = self.remote_field.through_fields[1] 

1824 else: 

1825 link_field_name = None 

1826 for f in self.remote_field.through._meta.fields: 1826 ↛ 1841line 1826 didn't jump to line 1841, because the loop on line 1826 didn't complete

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

1828 if link_field_name is None and related.related_model == related.model: 1828 ↛ 1833line 1828 didn't jump to line 1833, because the condition on line 1828 was never true

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

1830 # the first foreign key you find will be 

1831 # the source column. Keep searching for 

1832 # the second foreign key. 

1833 if found: 

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

1835 break 

1836 else: 

1837 found = True 

1838 elif link_field_name is None or link_field_name == f.name: 1838 ↛ 1826line 1838 didn't jump to line 1826, because the condition on line 1838 was never false

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

1840 break 

1841 return getattr(self, cache_attr) 

1842 

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

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

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

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

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

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

1849 # clash. 

1850 if self.remote_field.symmetrical and ( 1850 ↛ 1854line 1850 didn't jump to line 1854, because the condition on line 1850 was never true

1851 self.remote_field.model == RECURSIVE_RELATIONSHIP_CONSTANT 

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

1853 ): 

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

1855 elif self.remote_field.is_hidden(): 1855 ↛ 1860line 1855 didn't jump to line 1860, because the condition on line 1855 was never true

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

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

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

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

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

1861 cls._meta.app_label, 

1862 cls.__name__.lower(), 

1863 name, 

1864 ) 

1865 

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

1867 

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

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

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

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

1872 if not cls._meta.abstract: 

1873 if self.remote_field.through: 

1874 

1875 def resolve_through_model(_, model, field): 

1876 field.remote_field.through = model 

1877 

1878 lazy_related_operation( 

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

1880 ) 

1881 elif not cls._meta.swapped: 

1882 self.remote_field.through = create_many_to_many_intermediary_model( 

1883 self, cls 

1884 ) 

1885 

1886 # Add the descriptor for the m2m relation. 

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

1888 

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

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

1891 

1892 def contribute_to_related_class(self, cls, related): 

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

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

1895 if ( 

1896 not self.remote_field.is_hidden() 

1897 and not related.related_model._meta.swapped 

1898 ): 

1899 setattr( 

1900 cls, 

1901 related.get_accessor_name(), 

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

1903 ) 

1904 

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

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

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

1908 

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

1910 self.m2m_reverse_field_name = partial( 

1911 self._get_m2m_reverse_attr, related, "name" 

1912 ) 

1913 

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

1915 self.m2m_target_field_name = lambda: get_m2m_rel().field_name 1915 ↛ exitline 1915 didn't run the lambda on line 1915

1916 get_m2m_reverse_rel = partial( 

1917 self._get_m2m_reverse_attr, related, "remote_field" 

1918 ) 

1919 self.m2m_reverse_target_field_name = lambda: get_m2m_reverse_rel().field_name 1919 ↛ exitline 1919 didn't run the lambda on line 1919

1920 

1921 def set_attributes_from_rel(self): 

1922 pass 

1923 

1924 def value_from_object(self, obj): 

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

1926 

1927 def save_form_data(self, instance, data): 

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

1929 

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

1931 defaults = { 

1932 "form_class": forms.ModelMultipleChoiceField, 

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

1934 **kwargs, 

1935 } 

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

1937 # MultipleChoiceField takes a list of IDs. 

1938 if defaults.get("initial") is not None: 1938 ↛ 1939line 1938 didn't jump to line 1939, because the condition on line 1938 was never true

1939 initial = defaults["initial"] 

1940 if callable(initial): 

1941 initial = initial() 

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

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

1944 

1945 def db_check(self, connection): 

1946 return None 

1947 

1948 def db_type(self, connection): 

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

1950 # so return None. 

1951 return None 

1952 

1953 def db_parameters(self, connection): 

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