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

477 statements  

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

1import bisect 

2import copy 

3import inspect 

4import warnings 

5from collections import defaultdict 

6 

7from django.apps import apps 

8from django.conf import settings 

9from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured 

10from django.db import connections 

11from django.db.models import AutoField, Manager, OrderWrt, UniqueConstraint 

12from django.db.models.query_utils import PathInfo 

13from django.utils.datastructures import ImmutableList, OrderedSet 

14from django.utils.deprecation import RemovedInDjango51Warning 

15from django.utils.functional import cached_property 

16from django.utils.module_loading import import_string 

17from django.utils.text import camel_case_to_spaces, format_lazy 

18from django.utils.translation import override 

19 

20PROXY_PARENTS = object() 

21 

22EMPTY_RELATION_TREE = () 

23 

24IMMUTABLE_WARNING = ( 

25 "The return type of '%s' should never be mutated. If you want to manipulate this " 

26 "list for your own use, make a copy first." 

27) 

28 

29DEFAULT_NAMES = ( 

30 "verbose_name", 

31 "verbose_name_plural", 

32 "db_table", 

33 "db_table_comment", 

34 "ordering", 

35 "unique_together", 

36 "permissions", 

37 "get_latest_by", 

38 "order_with_respect_to", 

39 "app_label", 

40 "db_tablespace", 

41 "abstract", 

42 "managed", 

43 "proxy", 

44 "swappable", 

45 "auto_created", 

46 # Must be kept for backward compatibility with old migrations. 

47 "index_together", 

48 "apps", 

49 "default_permissions", 

50 "select_on_save", 

51 "default_related_name", 

52 "required_db_features", 

53 "required_db_vendor", 

54 "base_manager_name", 

55 "default_manager_name", 

56 "indexes", 

57 "constraints", 

58) 

59 

60 

61def normalize_together(option_together): 

62 """ 

63 option_together can be either a tuple of tuples, or a single 

64 tuple of two strings. Normalize it to a tuple of tuples, so that 

65 calling code can uniformly expect that. 

66 """ 

67 try: 

68 if not option_together: 

69 return () 

70 if not isinstance(option_together, (tuple, list)): 

71 raise TypeError 

72 first_element = option_together[0] 

73 if not isinstance(first_element, (tuple, list)): 

74 option_together = (option_together,) 

75 # Normalize everything to tuples 

76 return tuple(tuple(ot) for ot in option_together) 

77 except TypeError: 

78 # If the value of option_together isn't valid, return it 

79 # verbatim; this will be picked up by the check framework later. 

80 return option_together 

81 

82 

83def make_immutable_fields_list(name, data): 

84 return ImmutableList(data, warning=IMMUTABLE_WARNING % name) 

85 

86 

87class Options: 

88 FORWARD_PROPERTIES = { 

89 "fields", 

90 "many_to_many", 

91 "concrete_fields", 

92 "local_concrete_fields", 

93 "_non_pk_concrete_field_names", 

94 "_forward_fields_map", 

95 "managers", 

96 "managers_map", 

97 "base_manager", 

98 "default_manager", 

99 } 

100 REVERSE_PROPERTIES = {"related_objects", "fields_map", "_relation_tree"} 

101 

102 default_apps = apps 

103 

104 def __init__(self, meta, app_label=None): 

105 self._get_fields_cache = {} 

106 self.local_fields = [] 

107 self.local_many_to_many = [] 

108 self.private_fields = [] 

109 self.local_managers = [] 

110 self.base_manager_name = None 

111 self.default_manager_name = None 

112 self.model_name = None 

113 self.verbose_name = None 

114 self.verbose_name_plural = None 

115 self.db_table = "" 

116 self.db_table_comment = "" 

117 self.ordering = [] 

118 self._ordering_clash = False 

119 self.indexes = [] 

120 self.constraints = [] 

121 self.unique_together = [] 

122 self.index_together = [] # RemovedInDjango51Warning. 

123 self.select_on_save = False 

124 self.default_permissions = ("add", "change", "delete", "view") 

125 self.permissions = [] 

126 self.object_name = None 

127 self.app_label = app_label 

128 self.get_latest_by = None 

129 self.order_with_respect_to = None 

130 self.db_tablespace = settings.DEFAULT_TABLESPACE 

131 self.required_db_features = [] 

132 self.required_db_vendor = None 

133 self.meta = meta 

134 self.pk = None 

135 self.auto_field = None 

136 self.abstract = False 

137 self.managed = True 

138 self.proxy = False 

139 # For any class that is a proxy (including automatically created 

140 # classes for deferred object loading), proxy_for_model tells us 

141 # which class this model is proxying. Note that proxy_for_model 

142 # can create a chain of proxy models. For non-proxy models, the 

143 # variable is always None. 

144 self.proxy_for_model = None 

145 # For any non-abstract class, the concrete class is the model 

146 # in the end of the proxy_for_model chain. In particular, for 

147 # concrete models, the concrete_model is always the class itself. 

148 self.concrete_model = None 

149 self.swappable = None 

150 self.parents = {} 

151 self.auto_created = False 

152 

153 # List of all lookups defined in ForeignKey 'limit_choices_to' options 

154 # from *other* models. Needed for some admin checks. Internal use only. 

155 self.related_fkey_lookups = [] 

156 

157 # A custom app registry to use, if you're making a separate model set. 

158 self.apps = self.default_apps 

159 

160 self.default_related_name = None 

161 

162 @property 

163 def label(self): 

164 return "%s.%s" % (self.app_label, self.object_name) 

165 

166 @property 

167 def label_lower(self): 

168 return "%s.%s" % (self.app_label, self.model_name) 

169 

170 @property 

171 def app_config(self): 

172 # Don't go through get_app_config to avoid triggering imports. 

173 return self.apps.app_configs.get(self.app_label) 

174 

175 def contribute_to_class(self, cls, name): 

176 from django.db import connection 

177 from django.db.backends.utils import truncate_name 

178 

179 cls._meta = self 

180 self.model = cls 

181 # First, construct the default values for these options. 

182 self.object_name = cls.__name__ 

183 self.model_name = self.object_name.lower() 

184 self.verbose_name = camel_case_to_spaces(self.object_name) 

185 

186 # Store the original user-defined values for each option, 

187 # for use when serializing the model definition 

188 self.original_attrs = {} 

189 

190 # Next, apply any overridden values from 'class Meta'. 

191 if self.meta: 

192 meta_attrs = self.meta.__dict__.copy() 

193 for name in self.meta.__dict__: 

194 # Ignore any private attributes that Django doesn't care about. 

195 # NOTE: We can't modify a dictionary's contents while looping 

196 # over it, so we loop over the *original* dictionary instead. 

197 if name.startswith("_"): 

198 del meta_attrs[name] 

199 for attr_name in DEFAULT_NAMES: 

200 if attr_name in meta_attrs: 

201 setattr(self, attr_name, meta_attrs.pop(attr_name)) 

202 self.original_attrs[attr_name] = getattr(self, attr_name) 

203 elif hasattr(self.meta, attr_name): 

204 setattr(self, attr_name, getattr(self.meta, attr_name)) 

205 self.original_attrs[attr_name] = getattr(self, attr_name) 

206 

207 self.unique_together = normalize_together(self.unique_together) 

208 self.index_together = normalize_together(self.index_together) 

209 if self.index_together: 

210 warnings.warn( 

211 f"'index_together' is deprecated. Use 'Meta.indexes' in " 

212 f"{self.label!r} instead.", 

213 RemovedInDjango51Warning, 

214 ) 

215 # App label/class name interpolation for names of constraints and 

216 # indexes. 

217 if not getattr(cls._meta, "abstract", False): 

218 for attr_name in {"constraints", "indexes"}: 

219 objs = getattr(self, attr_name, []) 

220 setattr(self, attr_name, self._format_names_with_class(cls, objs)) 

221 

222 # verbose_name_plural is a special case because it uses a 's' 

223 # by default. 

224 if self.verbose_name_plural is None: 

225 self.verbose_name_plural = format_lazy("{}s", self.verbose_name) 

226 

227 # order_with_respect_and ordering are mutually exclusive. 

228 self._ordering_clash = bool(self.ordering and self.order_with_respect_to) 

229 

230 # Any leftover attributes must be invalid. 

231 if meta_attrs != {}: 

232 raise TypeError( 

233 "'class Meta' got invalid attribute(s): %s" % ",".join(meta_attrs) 

234 ) 

235 else: 

236 self.verbose_name_plural = format_lazy("{}s", self.verbose_name) 

237 del self.meta 

238 

239 # If the db_table wasn't provided, use the app_label + model_name. 

240 if not self.db_table: 

241 self.db_table = "%s_%s" % (self.app_label, self.model_name) 

242 self.db_table = truncate_name( 

243 self.db_table, connection.ops.max_name_length() 

244 ) 

245 

246 def _format_names_with_class(self, cls, objs): 

247 """App label/class name interpolation for object names.""" 

248 new_objs = [] 

249 for obj in objs: 

250 obj = obj.clone() 

251 obj.name = obj.name % { 

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

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

254 } 

255 new_objs.append(obj) 

256 return new_objs 

257 

258 def _get_default_pk_class(self): 

259 pk_class_path = getattr( 

260 self.app_config, 

261 "default_auto_field", 

262 settings.DEFAULT_AUTO_FIELD, 

263 ) 

264 if self.app_config and self.app_config._is_default_auto_field_overridden: 

265 app_config_class = type(self.app_config) 

266 source = ( 

267 f"{app_config_class.__module__}." 

268 f"{app_config_class.__qualname__}.default_auto_field" 

269 ) 

270 else: 

271 source = "DEFAULT_AUTO_FIELD" 

272 if not pk_class_path: 

273 raise ImproperlyConfigured(f"{source} must not be empty.") 

274 try: 

275 pk_class = import_string(pk_class_path) 

276 except ImportError as e: 

277 msg = ( 

278 f"{source} refers to the module '{pk_class_path}' that could " 

279 f"not be imported." 

280 ) 

281 raise ImproperlyConfigured(msg) from e 

282 if not issubclass(pk_class, AutoField): 

283 raise ValueError( 

284 f"Primary key '{pk_class_path}' referred by {source} must " 

285 f"subclass AutoField." 

286 ) 

287 return pk_class 

288 

289 def _prepare(self, model): 

290 if self.order_with_respect_to: 

291 # The app registry will not be ready at this point, so we cannot 

292 # use get_field(). 

293 query = self.order_with_respect_to 

294 try: 

295 self.order_with_respect_to = next( 

296 f 

297 for f in self._get_fields(reverse=False) 

298 if f.name == query or f.attname == query 

299 ) 

300 except StopIteration: 

301 raise FieldDoesNotExist( 

302 "%s has no field named '%s'" % (self.object_name, query) 

303 ) 

304 

305 self.ordering = ("_order",) 

306 if not any( 

307 isinstance(field, OrderWrt) for field in model._meta.local_fields 

308 ): 

309 model.add_to_class("_order", OrderWrt()) 

310 else: 

311 self.order_with_respect_to = None 

312 

313 if self.pk is None: 

314 if self.parents: 

315 # Promote the first parent link in lieu of adding yet another 

316 # field. 

317 field = next(iter(self.parents.values())) 

318 # Look for a local field with the same name as the 

319 # first parent link. If a local field has already been 

320 # created, use it instead of promoting the parent 

321 already_created = [ 

322 fld for fld in self.local_fields if fld.name == field.name 

323 ] 

324 if already_created: 

325 field = already_created[0] 

326 field.primary_key = True 

327 self.setup_pk(field) 

328 else: 

329 pk_class = self._get_default_pk_class() 

330 auto = pk_class(verbose_name="ID", primary_key=True, auto_created=True) 

331 model.add_to_class("id", auto) 

332 

333 def add_manager(self, manager): 

334 self.local_managers.append(manager) 

335 self._expire_cache() 

336 

337 def add_field(self, field, private=False): 

338 # Insert the given field in the order in which it was created, using 

339 # the "creation_counter" attribute of the field. 

340 # Move many-to-many related fields from self.fields into 

341 # self.many_to_many. 

342 if private: 

343 self.private_fields.append(field) 

344 elif field.is_relation and field.many_to_many: 

345 bisect.insort(self.local_many_to_many, field) 

346 else: 

347 bisect.insort(self.local_fields, field) 

348 self.setup_pk(field) 

349 

350 # If the field being added is a relation to another known field, 

351 # expire the cache on this field and the forward cache on the field 

352 # being referenced, because there will be new relationships in the 

353 # cache. Otherwise, expire the cache of references *to* this field. 

354 # The mechanism for getting at the related model is slightly odd - 

355 # ideally, we'd just ask for field.related_model. However, related_model 

356 # is a cached property, and all the models haven't been loaded yet, so 

357 # we need to make sure we don't cache a string reference. 

358 if ( 

359 field.is_relation 

360 and hasattr(field.remote_field, "model") 

361 and field.remote_field.model 

362 ): 

363 try: 

364 field.remote_field.model._meta._expire_cache(forward=False) 

365 except AttributeError: 

366 pass 

367 self._expire_cache() 

368 else: 

369 self._expire_cache(reverse=False) 

370 

371 def setup_pk(self, field): 

372 if not self.pk and field.primary_key: 

373 self.pk = field 

374 field.serialize = False 

375 

376 def setup_proxy(self, target): 

377 """ 

378 Do the internal setup so that the current model is a proxy for 

379 "target". 

380 """ 

381 self.pk = target._meta.pk 

382 self.proxy_for_model = target 

383 self.db_table = target._meta.db_table 

384 

385 def __repr__(self): 

386 return "<Options for %s>" % self.object_name 

387 

388 def __str__(self): 

389 return self.label_lower 

390 

391 def can_migrate(self, connection): 

392 """ 

393 Return True if the model can/should be migrated on the `connection`. 

394 `connection` can be either a real connection or a connection alias. 

395 """ 

396 if self.proxy or self.swapped or not self.managed: 

397 return False 

398 if isinstance(connection, str): 

399 connection = connections[connection] 

400 if self.required_db_vendor: 

401 return self.required_db_vendor == connection.vendor 

402 if self.required_db_features: 

403 return all( 

404 getattr(connection.features, feat, False) 

405 for feat in self.required_db_features 

406 ) 

407 return True 

408 

409 @property 

410 def verbose_name_raw(self): 

411 """Return the untranslated verbose name.""" 

412 with override(None): 

413 return str(self.verbose_name) 

414 

415 @property 

416 def swapped(self): 

417 """ 

418 Has this model been swapped out for another? If so, return the model 

419 name of the replacement; otherwise, return None. 

420 

421 For historical reasons, model name lookups using get_model() are 

422 case insensitive, so we make sure we are case insensitive here. 

423 """ 

424 if self.swappable: 

425 swapped_for = getattr(settings, self.swappable, None) 

426 if swapped_for: 

427 try: 

428 swapped_label, swapped_object = swapped_for.split(".") 

429 except ValueError: 

430 # setting not in the format app_label.model_name 

431 # raising ImproperlyConfigured here causes problems with 

432 # test cleanup code - instead it is raised in get_user_model 

433 # or as part of validation. 

434 return swapped_for 

435 

436 if ( 

437 "%s.%s" % (swapped_label, swapped_object.lower()) 

438 != self.label_lower 

439 ): 

440 return swapped_for 

441 return None 

442 

443 @cached_property 

444 def managers(self): 

445 managers = [] 

446 seen_managers = set() 

447 bases = (b for b in self.model.mro() if hasattr(b, "_meta")) 

448 for depth, base in enumerate(bases): 

449 for manager in base._meta.local_managers: 

450 if manager.name in seen_managers: 

451 continue 

452 

453 manager = copy.copy(manager) 

454 manager.model = self.model 

455 seen_managers.add(manager.name) 

456 managers.append((depth, manager.creation_counter, manager)) 

457 

458 return make_immutable_fields_list( 

459 "managers", 

460 (m[2] for m in sorted(managers)), 

461 ) 

462 

463 @cached_property 

464 def managers_map(self): 

465 return {manager.name: manager for manager in self.managers} 

466 

467 @cached_property 

468 def base_manager(self): 

469 base_manager_name = self.base_manager_name 

470 if not base_manager_name: 

471 # Get the first parent's base_manager_name if there's one. 

472 for parent in self.model.mro()[1:]: 

473 if hasattr(parent, "_meta"): 

474 if parent._base_manager.name != "_base_manager": 

475 base_manager_name = parent._base_manager.name 

476 break 

477 

478 if base_manager_name: 

479 try: 

480 return self.managers_map[base_manager_name] 

481 except KeyError: 

482 raise ValueError( 

483 "%s has no manager named %r" 

484 % ( 

485 self.object_name, 

486 base_manager_name, 

487 ) 

488 ) 

489 

490 manager = Manager() 

491 manager.name = "_base_manager" 

492 manager.model = self.model 

493 manager.auto_created = True 

494 return manager 

495 

496 @cached_property 

497 def default_manager(self): 

498 default_manager_name = self.default_manager_name 

499 if not default_manager_name and not self.local_managers: 

500 # Get the first parent's default_manager_name if there's one. 

501 for parent in self.model.mro()[1:]: 

502 if hasattr(parent, "_meta"): 

503 default_manager_name = parent._meta.default_manager_name 

504 break 

505 

506 if default_manager_name: 

507 try: 

508 return self.managers_map[default_manager_name] 

509 except KeyError: 

510 raise ValueError( 

511 "%s has no manager named %r" 

512 % ( 

513 self.object_name, 

514 default_manager_name, 

515 ) 

516 ) 

517 

518 if self.managers: 

519 return self.managers[0] 

520 

521 @cached_property 

522 def fields(self): 

523 """ 

524 Return a list of all forward fields on the model and its parents, 

525 excluding ManyToManyFields. 

526 

527 Private API intended only to be used by Django itself; get_fields() 

528 combined with filtering of field properties is the public API for 

529 obtaining this field list. 

530 """ 

531 # For legacy reasons, the fields property should only contain forward 

532 # fields that are not private or with a m2m cardinality. Therefore we 

533 # pass these three filters as filters to the generator. 

534 # The third lambda is a longwinded way of checking f.related_model - we don't 

535 # use that property directly because related_model is a cached property, 

536 # and all the models may not have been loaded yet; we don't want to cache 

537 # the string reference to the related_model. 

538 def is_not_an_m2m_field(f): 

539 return not (f.is_relation and f.many_to_many) 

540 

541 def is_not_a_generic_relation(f): 

542 return not (f.is_relation and f.one_to_many) 

543 

544 def is_not_a_generic_foreign_key(f): 

545 return not ( 

546 f.is_relation 

547 and f.many_to_one 

548 and not (hasattr(f.remote_field, "model") and f.remote_field.model) 

549 ) 

550 

551 return make_immutable_fields_list( 

552 "fields", 

553 ( 

554 f 

555 for f in self._get_fields(reverse=False) 

556 if is_not_an_m2m_field(f) 

557 and is_not_a_generic_relation(f) 

558 and is_not_a_generic_foreign_key(f) 

559 ), 

560 ) 

561 

562 @cached_property 

563 def concrete_fields(self): 

564 """ 

565 Return a list of all concrete fields on the model and its parents. 

566 

567 Private API intended only to be used by Django itself; get_fields() 

568 combined with filtering of field properties is the public API for 

569 obtaining this field list. 

570 """ 

571 return make_immutable_fields_list( 

572 "concrete_fields", (f for f in self.fields if f.concrete) 

573 ) 

574 

575 @cached_property 

576 def local_concrete_fields(self): 

577 """ 

578 Return a list of all concrete fields on the model. 

579 

580 Private API intended only to be used by Django itself; get_fields() 

581 combined with filtering of field properties is the public API for 

582 obtaining this field list. 

583 """ 

584 return make_immutable_fields_list( 

585 "local_concrete_fields", (f for f in self.local_fields if f.concrete) 

586 ) 

587 

588 @cached_property 

589 def many_to_many(self): 

590 """ 

591 Return a list of all many to many fields on the model and its parents. 

592 

593 Private API intended only to be used by Django itself; get_fields() 

594 combined with filtering of field properties is the public API for 

595 obtaining this list. 

596 """ 

597 return make_immutable_fields_list( 

598 "many_to_many", 

599 ( 

600 f 

601 for f in self._get_fields(reverse=False) 

602 if f.is_relation and f.many_to_many 

603 ), 

604 ) 

605 

606 @cached_property 

607 def related_objects(self): 

608 """ 

609 Return all related objects pointing to the current model. The related 

610 objects can come from a one-to-one, one-to-many, or many-to-many field 

611 relation type. 

612 

613 Private API intended only to be used by Django itself; get_fields() 

614 combined with filtering of field properties is the public API for 

615 obtaining this field list. 

616 """ 

617 all_related_fields = self._get_fields( 

618 forward=False, reverse=True, include_hidden=True 

619 ) 

620 return make_immutable_fields_list( 

621 "related_objects", 

622 ( 

623 obj 

624 for obj in all_related_fields 

625 if not obj.hidden or obj.field.many_to_many 

626 ), 

627 ) 

628 

629 @cached_property 

630 def _forward_fields_map(self): 

631 res = {} 

632 fields = self._get_fields(reverse=False) 

633 for field in fields: 

634 res[field.name] = field 

635 # Due to the way Django's internals work, get_field() should also 

636 # be able to fetch a field by attname. In the case of a concrete 

637 # field with relation, includes the *_id name too 

638 try: 

639 res[field.attname] = field 

640 except AttributeError: 

641 pass 

642 return res 

643 

644 @cached_property 

645 def fields_map(self): 

646 res = {} 

647 fields = self._get_fields(forward=False, include_hidden=True) 

648 for field in fields: 

649 res[field.name] = field 

650 # Due to the way Django's internals work, get_field() should also 

651 # be able to fetch a field by attname. In the case of a concrete 

652 # field with relation, includes the *_id name too 

653 try: 

654 res[field.attname] = field 

655 except AttributeError: 

656 pass 

657 return res 

658 

659 def get_field(self, field_name): 

660 """ 

661 Return a field instance given the name of a forward or reverse field. 

662 """ 

663 try: 

664 # In order to avoid premature loading of the relation tree 

665 # (expensive) we prefer checking if the field is a forward field. 

666 return self._forward_fields_map[field_name] 

667 except KeyError: 

668 # If the app registry is not ready, reverse fields are 

669 # unavailable, therefore we throw a FieldDoesNotExist exception. 

670 if not self.apps.models_ready: 

671 raise FieldDoesNotExist( 

672 "%s has no field named '%s'. The app cache isn't ready yet, " 

673 "so if this is an auto-created related field, it won't " 

674 "be available yet." % (self.object_name, field_name) 

675 ) 

676 

677 try: 

678 # Retrieve field instance by name from cached or just-computed 

679 # field map. 

680 return self.fields_map[field_name] 

681 except KeyError: 

682 raise FieldDoesNotExist( 

683 "%s has no field named '%s'" % (self.object_name, field_name) 

684 ) 

685 

686 def get_base_chain(self, model): 

687 """ 

688 Return a list of parent classes leading to `model` (ordered from 

689 closest to most distant ancestor). This has to handle the case where 

690 `model` is a grandparent or even more distant relation. 

691 """ 

692 if not self.parents: 

693 return [] 

694 if model in self.parents: 

695 return [model] 

696 for parent in self.parents: 

697 res = parent._meta.get_base_chain(model) 

698 if res: 

699 res.insert(0, parent) 

700 return res 

701 return [] 

702 

703 def get_parent_list(self): 

704 """ 

705 Return all the ancestors of this model as a list ordered by MRO. 

706 Useful for determining if something is an ancestor, regardless of lineage. 

707 """ 

708 result = OrderedSet(self.parents) 

709 for parent in self.parents: 

710 for ancestor in parent._meta.get_parent_list(): 

711 result.add(ancestor) 

712 return list(result) 

713 

714 def get_ancestor_link(self, ancestor): 

715 """ 

716 Return the field on the current model which points to the given 

717 "ancestor". This is possible an indirect link (a pointer to a parent 

718 model, which points, eventually, to the ancestor). Used when 

719 constructing table joins for model inheritance. 

720 

721 Return None if the model isn't an ancestor of this one. 

722 """ 

723 if ancestor in self.parents: 

724 return self.parents[ancestor] 

725 for parent in self.parents: 

726 # Tries to get a link field from the immediate parent 

727 parent_link = parent._meta.get_ancestor_link(ancestor) 

728 if parent_link: 

729 # In case of a proxied model, the first link 

730 # of the chain to the ancestor is that parent 

731 # links 

732 return self.parents[parent] or parent_link 

733 

734 def get_path_to_parent(self, parent): 

735 """ 

736 Return a list of PathInfos containing the path from the current 

737 model to the parent model, or an empty list if parent is not a 

738 parent of the current model. 

739 """ 

740 if self.model is parent: 

741 return [] 

742 # Skip the chain of proxy to the concrete proxied model. 

743 proxied_model = self.concrete_model 

744 path = [] 

745 opts = self 

746 for int_model in self.get_base_chain(parent): 

747 if int_model is proxied_model: 

748 opts = int_model._meta 

749 else: 

750 final_field = opts.parents[int_model] 

751 targets = (final_field.remote_field.get_related_field(),) 

752 opts = int_model._meta 

753 path.append( 

754 PathInfo( 

755 from_opts=final_field.model._meta, 

756 to_opts=opts, 

757 target_fields=targets, 

758 join_field=final_field, 

759 m2m=False, 

760 direct=True, 

761 filtered_relation=None, 

762 ) 

763 ) 

764 return path 

765 

766 def get_path_from_parent(self, parent): 

767 """ 

768 Return a list of PathInfos containing the path from the parent 

769 model to the current model, or an empty list if parent is not a 

770 parent of the current model. 

771 """ 

772 if self.model is parent: 

773 return [] 

774 model = self.concrete_model 

775 # Get a reversed base chain including both the current and parent 

776 # models. 

777 chain = model._meta.get_base_chain(parent) 

778 chain.reverse() 

779 chain.append(model) 

780 # Construct a list of the PathInfos between models in chain. 

781 path = [] 

782 for i, ancestor in enumerate(chain[:-1]): 

783 child = chain[i + 1] 

784 link = child._meta.get_ancestor_link(ancestor) 

785 path.extend(link.reverse_path_infos) 

786 return path 

787 

788 def _populate_directed_relation_graph(self): 

789 """ 

790 This method is used by each model to find its reverse objects. As this 

791 method is very expensive and is accessed frequently (it looks up every 

792 field in a model, in every app), it is computed on first access and then 

793 is set as a property on every model. 

794 """ 

795 related_objects_graph = defaultdict(list) 

796 

797 all_models = self.apps.get_models(include_auto_created=True) 

798 for model in all_models: 

799 opts = model._meta 

800 # Abstract model's fields are copied to child models, hence we will 

801 # see the fields from the child models. 

802 if opts.abstract: 

803 continue 

804 fields_with_relations = ( 

805 f 

806 for f in opts._get_fields(reverse=False, include_parents=False) 

807 if f.is_relation and f.related_model is not None 

808 ) 

809 for f in fields_with_relations: 

810 if not isinstance(f.remote_field.model, str): 

811 remote_label = f.remote_field.model._meta.concrete_model._meta.label 

812 related_objects_graph[remote_label].append(f) 

813 

814 for model in all_models: 

815 # Set the relation_tree using the internal __dict__. In this way 

816 # we avoid calling the cached property. In attribute lookup, 

817 # __dict__ takes precedence over a data descriptor (such as 

818 # @cached_property). This means that the _meta._relation_tree is 

819 # only called if related_objects is not in __dict__. 

820 related_objects = related_objects_graph[ 

821 model._meta.concrete_model._meta.label 

822 ] 

823 model._meta.__dict__["_relation_tree"] = related_objects 

824 # It seems it is possible that self is not in all_models, so guard 

825 # against that with default for get(). 

826 return self.__dict__.get("_relation_tree", EMPTY_RELATION_TREE) 

827 

828 @cached_property 

829 def _relation_tree(self): 

830 return self._populate_directed_relation_graph() 

831 

832 def _expire_cache(self, forward=True, reverse=True): 

833 # This method is usually called by apps.cache_clear(), when the 

834 # registry is finalized, or when a new field is added. 

835 if forward: 

836 for cache_key in self.FORWARD_PROPERTIES: 

837 if cache_key in self.__dict__: 

838 delattr(self, cache_key) 

839 if reverse and not self.abstract: 

840 for cache_key in self.REVERSE_PROPERTIES: 

841 if cache_key in self.__dict__: 

842 delattr(self, cache_key) 

843 self._get_fields_cache = {} 

844 

845 def get_fields(self, include_parents=True, include_hidden=False): 

846 """ 

847 Return a list of fields associated to the model. By default, include 

848 forward and reverse fields, fields derived from inheritance, but not 

849 hidden fields. The returned fields can be changed using the parameters: 

850 

851 - include_parents: include fields derived from inheritance 

852 - include_hidden: include fields that have a related_name that 

853 starts with a "+" 

854 """ 

855 if include_parents is False: 

856 include_parents = PROXY_PARENTS 

857 return self._get_fields( 

858 include_parents=include_parents, include_hidden=include_hidden 

859 ) 

860 

861 def _get_fields( 

862 self, 

863 forward=True, 

864 reverse=True, 

865 include_parents=True, 

866 include_hidden=False, 

867 seen_models=None, 

868 ): 

869 """ 

870 Internal helper function to return fields of the model. 

871 * If forward=True, then fields defined on this model are returned. 

872 * If reverse=True, then relations pointing to this model are returned. 

873 * If include_hidden=True, then fields with is_hidden=True are returned. 

874 * The include_parents argument toggles if fields from parent models 

875 should be included. It has three values: True, False, and 

876 PROXY_PARENTS. When set to PROXY_PARENTS, the call will return all 

877 fields defined for the current model or any of its parents in the 

878 parent chain to the model's concrete model. 

879 """ 

880 if include_parents not in (True, False, PROXY_PARENTS): 

881 raise TypeError( 

882 "Invalid argument for include_parents: %s" % (include_parents,) 

883 ) 

884 # This helper function is used to allow recursion in ``get_fields()`` 

885 # implementation and to provide a fast way for Django's internals to 

886 # access specific subsets of fields. 

887 

888 # We must keep track of which models we have already seen. Otherwise we 

889 # could include the same field multiple times from different models. 

890 topmost_call = seen_models is None 

891 if topmost_call: 

892 seen_models = set() 

893 seen_models.add(self.model) 

894 

895 # Creates a cache key composed of all arguments 

896 cache_key = (forward, reverse, include_parents, include_hidden, topmost_call) 

897 

898 try: 

899 # In order to avoid list manipulation. Always return a shallow copy 

900 # of the results. 

901 return self._get_fields_cache[cache_key] 

902 except KeyError: 

903 pass 

904 

905 fields = [] 

906 # Recursively call _get_fields() on each parent, with the same 

907 # options provided in this call. 

908 if include_parents is not False: 

909 for parent in self.parents: 

910 # In diamond inheritance it is possible that we see the same 

911 # model from two different routes. In that case, avoid adding 

912 # fields from the same parent again. 

913 if parent in seen_models: 

914 continue 

915 if ( 

916 parent._meta.concrete_model != self.concrete_model 

917 and include_parents == PROXY_PARENTS 

918 ): 

919 continue 

920 for obj in parent._meta._get_fields( 

921 forward=forward, 

922 reverse=reverse, 

923 include_parents=include_parents, 

924 include_hidden=include_hidden, 

925 seen_models=seen_models, 

926 ): 

927 if ( 

928 not getattr(obj, "parent_link", False) 

929 or obj.model == self.concrete_model 

930 ): 

931 fields.append(obj) 

932 if reverse and not self.proxy: 

933 # Tree is computed once and cached until the app cache is expired. 

934 # It is composed of a list of fields pointing to the current model 

935 # from other models. 

936 all_fields = self._relation_tree 

937 for field in all_fields: 

938 # If hidden fields should be included or the relation is not 

939 # intentionally hidden, add to the fields dict. 

940 if include_hidden or not field.remote_field.hidden: 

941 fields.append(field.remote_field) 

942 

943 if forward: 

944 fields += self.local_fields 

945 fields += self.local_many_to_many 

946 # Private fields are recopied to each child model, and they get a 

947 # different model as field.model in each child. Hence we have to 

948 # add the private fields separately from the topmost call. If we 

949 # did this recursively similar to local_fields, we would get field 

950 # instances with field.model != self.model. 

951 if topmost_call: 

952 fields += self.private_fields 

953 

954 # In order to avoid list manipulation. Always 

955 # return a shallow copy of the results 

956 fields = make_immutable_fields_list("get_fields()", fields) 

957 

958 # Store result into cache for later access 

959 self._get_fields_cache[cache_key] = fields 

960 return fields 

961 

962 @cached_property 

963 def total_unique_constraints(self): 

964 """ 

965 Return a list of total unique constraints. Useful for determining set 

966 of fields guaranteed to be unique for all rows. 

967 """ 

968 return [ 

969 constraint 

970 for constraint in self.constraints 

971 if ( 

972 isinstance(constraint, UniqueConstraint) 

973 and constraint.condition is None 

974 and not constraint.contains_expressions 

975 ) 

976 ] 

977 

978 @cached_property 

979 def _property_names(self): 

980 """Return a set of the names of the properties defined on the model.""" 

981 names = [] 

982 for name in dir(self.model): 

983 attr = inspect.getattr_static(self.model, name) 

984 if isinstance(attr, property): 

985 names.append(name) 

986 return frozenset(names) 

987 

988 @cached_property 

989 def _non_pk_concrete_field_names(self): 

990 """ 

991 Return a set of the non-pk concrete field names defined on the model. 

992 """ 

993 names = [] 

994 for field in self.concrete_fields: 

995 if not field.primary_key: 

996 names.append(field.name) 

997 if field.name != field.attname: 

998 names.append(field.attname) 

999 return frozenset(names) 

1000 

1001 @cached_property 

1002 def db_returning_fields(self): 

1003 """ 

1004 Private API intended only to be used by Django itself. 

1005 Fields to be returned after a database insert. 

1006 """ 

1007 return [ 

1008 field 

1009 for field in self._get_fields( 

1010 forward=True, reverse=False, include_parents=PROXY_PARENTS 

1011 ) 

1012 if getattr(field, "db_returning", False) 

1013 ]