Coverage for /Users/davegaeddert/Development/dropseed/plain/plain-models/plain/models/base.py: 38%

983 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-10-16 22:03 -0500

1import copy 

2import inspect 

3import warnings 

4from functools import partialmethod 

5from itertools import chain 

6 

7import plain.runtime 

8from plain import preflight 

9from plain.exceptions import ( 

10 NON_FIELD_ERRORS, 

11 FieldDoesNotExist, 

12 FieldError, 

13 MultipleObjectsReturned, 

14 ObjectDoesNotExist, 

15 ValidationError, 

16) 

17from plain.models import transaction 

18from plain.models.aggregates import Max 

19from plain.models.constants import LOOKUP_SEP 

20from plain.models.constraints import CheckConstraint, UniqueConstraint 

21from plain.models.db import ( 

22 PLAIN_VERSION_PICKLE_KEY, 

23 DatabaseError, 

24 connection, 

25 connections, 

26 router, 

27) 

28from plain.models.deletion import CASCADE, Collector 

29from plain.models.expressions import ExpressionWrapper, RawSQL, Value 

30from plain.models.fields import NOT_PROVIDED, IntegerField 

31from plain.models.fields.related import ( 

32 ForeignObjectRel, 

33 OneToOneField, 

34 lazy_related_operation, 

35 resolve_relation, 

36) 

37from plain.models.functions import Coalesce 

38from plain.models.manager import Manager 

39from plain.models.options import Options 

40from plain.models.query import F, Q 

41from plain.models.signals import ( 

42 class_prepared, 

43 post_init, 

44 post_save, 

45 pre_init, 

46 pre_save, 

47) 

48from plain.models.utils import AltersData, make_model_tuple 

49from plain.packages import packages 

50from plain.utils.encoding import force_str 

51from plain.utils.hashable import make_hashable 

52 

53 

54class Deferred: 

55 def __repr__(self): 

56 return "<Deferred field>" 

57 

58 def __str__(self): 

59 return "<Deferred field>" 

60 

61 

62DEFERRED = Deferred() 

63 

64 

65def subclass_exception(name, bases, module, attached_to): 

66 """ 

67 Create exception subclass. Used by ModelBase below. 

68 

69 The exception is created in a way that allows it to be pickled, assuming 

70 that the returned exception class will be added as an attribute to the 

71 'attached_to' class. 

72 """ 

73 return type( 

74 name, 

75 bases, 

76 { 

77 "__module__": module, 

78 "__qualname__": f"{attached_to.__qualname__}.{name}", 

79 }, 

80 ) 

81 

82 

83def _has_contribute_to_class(value): 

84 # Only call contribute_to_class() if it's bound. 

85 return not inspect.isclass(value) and hasattr(value, "contribute_to_class") 

86 

87 

88class ModelBase(type): 

89 """Metaclass for all models.""" 

90 

91 def __new__(cls, name, bases, attrs, **kwargs): 

92 super_new = super().__new__ 

93 

94 # Also ensure initialization is only performed for subclasses of Model 

95 # (excluding Model class itself). 

96 parents = [b for b in bases if isinstance(b, ModelBase)] 

97 if not parents: 

98 return super_new(cls, name, bases, attrs) 

99 

100 # Create the class. 

101 module = attrs.pop("__module__") 

102 new_attrs = {"__module__": module} 

103 classcell = attrs.pop("__classcell__", None) 

104 if classcell is not None: 

105 new_attrs["__classcell__"] = classcell 

106 attr_meta = attrs.pop("Meta", None) 

107 # Pass all attrs without a (Plain-specific) contribute_to_class() 

108 # method to type.__new__() so that they're properly initialized 

109 # (i.e. __set_name__()). 

110 contributable_attrs = {} 

111 for obj_name, obj in attrs.items(): 

112 if _has_contribute_to_class(obj): 

113 contributable_attrs[obj_name] = obj 

114 else: 

115 new_attrs[obj_name] = obj 

116 new_class = super_new(cls, name, bases, new_attrs, **kwargs) 

117 

118 abstract = getattr(attr_meta, "abstract", False) 

119 meta = attr_meta or getattr(new_class, "Meta", None) 

120 base_meta = getattr(new_class, "_meta", None) 

121 

122 package_label = None 

123 

124 # Look for an application configuration to attach the model to. 

125 package_config = packages.get_containing_package_config(module) 

126 

127 if getattr(meta, "package_label", None) is None: 

128 if package_config is None: 

129 if not abstract: 

130 raise RuntimeError( 

131 f"Model class {module}.{name} doesn't declare an explicit " 

132 "package_label and isn't in an application in " 

133 "INSTALLED_PACKAGES." 

134 ) 

135 

136 else: 

137 package_label = package_config.label 

138 

139 new_class.add_to_class("_meta", Options(meta, package_label)) 

140 if not abstract: 

141 new_class.add_to_class( 

142 "DoesNotExist", 

143 subclass_exception( 

144 "DoesNotExist", 

145 tuple( 

146 x.DoesNotExist 

147 for x in parents 

148 if hasattr(x, "_meta") and not x._meta.abstract 

149 ) 

150 or (ObjectDoesNotExist,), 

151 module, 

152 attached_to=new_class, 

153 ), 

154 ) 

155 new_class.add_to_class( 

156 "MultipleObjectsReturned", 

157 subclass_exception( 

158 "MultipleObjectsReturned", 

159 tuple( 

160 x.MultipleObjectsReturned 

161 for x in parents 

162 if hasattr(x, "_meta") and not x._meta.abstract 

163 ) 

164 or (MultipleObjectsReturned,), 

165 module, 

166 attached_to=new_class, 

167 ), 

168 ) 

169 if base_meta and not base_meta.abstract: 

170 # Non-abstract child classes inherit some attributes from their 

171 # non-abstract parent (unless an ABC comes before it in the 

172 # method resolution order). 

173 if not hasattr(meta, "ordering"): 

174 new_class._meta.ordering = base_meta.ordering 

175 if not hasattr(meta, "get_latest_by"): 

176 new_class._meta.get_latest_by = base_meta.get_latest_by 

177 

178 # Add remaining attributes (those with a contribute_to_class() method) 

179 # to the class. 

180 for obj_name, obj in contributable_attrs.items(): 

181 new_class.add_to_class(obj_name, obj) 

182 

183 # All the fields of any type declared on this model 

184 new_fields = chain( 

185 new_class._meta.local_fields, 

186 new_class._meta.local_many_to_many, 

187 new_class._meta.private_fields, 

188 ) 

189 field_names = {f.name for f in new_fields} 

190 

191 new_class._meta.concrete_model = new_class 

192 

193 # Collect the parent links for multi-table inheritance. 

194 parent_links = {} 

195 for base in reversed([new_class] + parents): 

196 # Conceptually equivalent to `if base is Model`. 

197 if not hasattr(base, "_meta"): 

198 continue 

199 # Skip concrete parent classes. 

200 if base != new_class and not base._meta.abstract: 

201 continue 

202 # Locate OneToOneField instances. 

203 for field in base._meta.local_fields: 

204 if isinstance(field, OneToOneField) and field.remote_field.parent_link: 

205 related = resolve_relation(new_class, field.remote_field.model) 

206 parent_links[make_model_tuple(related)] = field 

207 

208 # Track fields inherited from base models. 

209 inherited_attributes = set() 

210 # Do the appropriate setup for any model parents. 

211 for base in new_class.mro(): 

212 if base not in parents or not hasattr(base, "_meta"): 

213 # Things without _meta aren't functional models, so they're 

214 # uninteresting parents. 

215 inherited_attributes.update(base.__dict__) 

216 continue 

217 

218 parent_fields = base._meta.local_fields + base._meta.local_many_to_many 

219 if not base._meta.abstract: 

220 # Check for clashes between locally declared fields and those 

221 # on the base classes. 

222 for field in parent_fields: 

223 if field.name in field_names: 

224 raise FieldError( 

225 "Local field {!r} in class {!r} clashes with field of " 

226 "the same name from base class {!r}.".format( 

227 field.name, 

228 name, 

229 base.__name__, 

230 ) 

231 ) 

232 else: 

233 inherited_attributes.add(field.name) 

234 

235 # Concrete classes... 

236 base = base._meta.concrete_model 

237 base_key = make_model_tuple(base) 

238 if base_key in parent_links: 

239 field = parent_links[base_key] 

240 else: 

241 attr_name = "%s_ptr" % base._meta.model_name 

242 field = OneToOneField( 

243 base, 

244 on_delete=CASCADE, 

245 name=attr_name, 

246 auto_created=True, 

247 parent_link=True, 

248 ) 

249 

250 if attr_name in field_names: 

251 raise FieldError( 

252 f"Auto-generated field '{attr_name}' in class {name!r} for " 

253 f"parent_link to base class {base.__name__!r} clashes with " 

254 "declared field of the same name." 

255 ) 

256 

257 # Only add the ptr field if it's not already present; 

258 # e.g. migrations will already have it specified 

259 if not hasattr(new_class, attr_name): 

260 new_class.add_to_class(attr_name, field) 

261 new_class._meta.parents[base] = field 

262 else: 

263 base_parents = base._meta.parents.copy() 

264 

265 # Add fields from abstract base class if it wasn't overridden. 

266 for field in parent_fields: 

267 if ( 

268 field.name not in field_names 

269 and field.name not in new_class.__dict__ 

270 and field.name not in inherited_attributes 

271 ): 

272 new_field = copy.deepcopy(field) 

273 new_class.add_to_class(field.name, new_field) 

274 # Replace parent links defined on this base by the new 

275 # field. It will be appropriately resolved if required. 

276 if field.one_to_one: 

277 for parent, parent_link in base_parents.items(): 

278 if field == parent_link: 

279 base_parents[parent] = new_field 

280 

281 # Pass any non-abstract parent classes onto child. 

282 new_class._meta.parents.update(base_parents) 

283 

284 # Inherit private fields (like GenericForeignKey) from the parent 

285 # class 

286 for field in base._meta.private_fields: 

287 if field.name in field_names: 

288 if not base._meta.abstract: 

289 raise FieldError( 

290 "Local field {!r} in class {!r} clashes with field of " 

291 "the same name from base class {!r}.".format( 

292 field.name, 

293 name, 

294 base.__name__, 

295 ) 

296 ) 

297 else: 

298 field = copy.deepcopy(field) 

299 if not base._meta.abstract: 

300 field.mti_inherited = True 

301 new_class.add_to_class(field.name, field) 

302 

303 # Copy indexes so that index names are unique when models extend an 

304 # abstract model. 

305 new_class._meta.indexes = [ 

306 copy.deepcopy(idx) for idx in new_class._meta.indexes 

307 ] 

308 

309 if abstract: 

310 # Abstract base models can't be instantiated and don't appear in 

311 # the list of models for an app. We do the final setup for them a 

312 # little differently from normal models. 

313 attr_meta.abstract = False 

314 new_class.Meta = attr_meta 

315 return new_class 

316 

317 new_class._prepare() 

318 new_class._meta.packages.register_model( 

319 new_class._meta.package_label, new_class 

320 ) 

321 return new_class 

322 

323 def add_to_class(cls, name, value): 

324 if _has_contribute_to_class(value): 

325 value.contribute_to_class(cls, name) 

326 else: 

327 setattr(cls, name, value) 

328 

329 def _prepare(cls): 

330 """Create some methods once self._meta has been populated.""" 

331 opts = cls._meta 

332 opts._prepare(cls) 

333 

334 if opts.order_with_respect_to: 

335 cls.get_next_in_order = partialmethod( 

336 cls._get_next_or_previous_in_order, is_next=True 

337 ) 

338 cls.get_previous_in_order = partialmethod( 

339 cls._get_next_or_previous_in_order, is_next=False 

340 ) 

341 

342 # Defer creating accessors on the foreign class until it has been 

343 # created and registered. If remote_field is None, we're ordering 

344 # with respect to a GenericForeignKey and don't know what the 

345 # foreign class is - we'll add those accessors later in 

346 # contribute_to_class(). 

347 if opts.order_with_respect_to.remote_field: 

348 wrt = opts.order_with_respect_to 

349 remote = wrt.remote_field.model 

350 lazy_related_operation(make_foreign_order_accessors, cls, remote) 

351 

352 # Give the class a docstring -- its definition. 

353 if cls.__doc__ is None: 

354 cls.__doc__ = "{}({})".format( 

355 cls.__name__, 

356 ", ".join(f.name for f in opts.fields), 

357 ) 

358 

359 if not opts.managers: 

360 if any(f.name == "objects" for f in opts.fields): 

361 raise ValueError( 

362 "Model %s must specify a custom Manager, because it has a " 

363 "field named 'objects'." % cls.__name__ 

364 ) 

365 manager = Manager() 

366 manager.auto_created = True 

367 cls.add_to_class("objects", manager) 

368 

369 # Set the name of _meta.indexes. This can't be done in 

370 # Options.contribute_to_class() because fields haven't been added to 

371 # the model at that point. 

372 for index in cls._meta.indexes: 

373 if not index.name: 

374 index.set_name_with_model(cls) 

375 

376 class_prepared.send(sender=cls) 

377 

378 @property 

379 def _base_manager(cls): 

380 return cls._meta.base_manager 

381 

382 @property 

383 def _default_manager(cls): 

384 return cls._meta.default_manager 

385 

386 

387class ModelStateFieldsCacheDescriptor: 

388 def __get__(self, instance, cls=None): 

389 if instance is None: 

390 return self 

391 res = instance.fields_cache = {} 

392 return res 

393 

394 

395class ModelState: 

396 """Store model instance state.""" 

397 

398 db = None 

399 # If true, uniqueness validation checks will consider this a new, unsaved 

400 # object. Necessary for correct validation of new instances of objects with 

401 # explicit (non-auto) PKs. This impacts validation only; it has no effect 

402 # on the actual save. 

403 adding = True 

404 fields_cache = ModelStateFieldsCacheDescriptor() 

405 

406 

407class Model(AltersData, metaclass=ModelBase): 

408 def __init__(self, *args, **kwargs): 

409 # Alias some things as locals to avoid repeat global lookups 

410 cls = self.__class__ 

411 opts = self._meta 

412 _setattr = setattr 

413 _DEFERRED = DEFERRED 

414 if opts.abstract: 

415 raise TypeError("Abstract models cannot be instantiated.") 

416 

417 pre_init.send(sender=cls, args=args, kwargs=kwargs) 

418 

419 # Set up the storage for instance state 

420 self._state = ModelState() 

421 

422 # There is a rather weird disparity here; if kwargs, it's set, then args 

423 # overrides it. It should be one or the other; don't duplicate the work 

424 # The reason for the kwargs check is that standard iterator passes in by 

425 # args, and instantiation for iteration is 33% faster. 

426 if len(args) > len(opts.concrete_fields): 

427 # Daft, but matches old exception sans the err msg. 

428 raise IndexError("Number of args exceeds number of fields") 

429 

430 if not kwargs: 

431 fields_iter = iter(opts.concrete_fields) 

432 # The ordering of the zip calls matter - zip throws StopIteration 

433 # when an iter throws it. So if the first iter throws it, the second 

434 # is *not* consumed. We rely on this, so don't change the order 

435 # without changing the logic. 

436 for val, field in zip(args, fields_iter): 

437 if val is _DEFERRED: 

438 continue 

439 _setattr(self, field.attname, val) 

440 else: 

441 # Slower, kwargs-ready version. 

442 fields_iter = iter(opts.fields) 

443 for val, field in zip(args, fields_iter): 

444 if val is _DEFERRED: 

445 continue 

446 _setattr(self, field.attname, val) 

447 if kwargs.pop(field.name, NOT_PROVIDED) is not NOT_PROVIDED: 

448 raise TypeError( 

449 f"{cls.__qualname__}() got both positional and " 

450 f"keyword arguments for field '{field.name}'." 

451 ) 

452 

453 # Now we're left with the unprocessed fields that *must* come from 

454 # keywords, or default. 

455 

456 for field in fields_iter: 

457 is_related_object = False 

458 # Virtual field 

459 if field.attname not in kwargs and field.column is None: 

460 continue 

461 if kwargs: 

462 if isinstance(field.remote_field, ForeignObjectRel): 

463 try: 

464 # Assume object instance was passed in. 

465 rel_obj = kwargs.pop(field.name) 

466 is_related_object = True 

467 except KeyError: 

468 try: 

469 # Object instance wasn't passed in -- must be an ID. 

470 val = kwargs.pop(field.attname) 

471 except KeyError: 

472 val = field.get_default() 

473 else: 

474 try: 

475 val = kwargs.pop(field.attname) 

476 except KeyError: 

477 # This is done with an exception rather than the 

478 # default argument on pop because we don't want 

479 # get_default() to be evaluated, and then not used. 

480 # Refs #12057. 

481 val = field.get_default() 

482 else: 

483 val = field.get_default() 

484 

485 if is_related_object: 

486 # If we are passed a related instance, set it using the 

487 # field.name instead of field.attname (e.g. "user" instead of 

488 # "user_id") so that the object gets properly cached (and type 

489 # checked) by the RelatedObjectDescriptor. 

490 if rel_obj is not _DEFERRED: 

491 _setattr(self, field.name, rel_obj) 

492 else: 

493 if val is not _DEFERRED: 

494 _setattr(self, field.attname, val) 

495 

496 if kwargs: 

497 property_names = opts._property_names 

498 unexpected = () 

499 for prop, value in kwargs.items(): 

500 # Any remaining kwargs must correspond to properties or virtual 

501 # fields. 

502 if prop in property_names: 

503 if value is not _DEFERRED: 

504 _setattr(self, prop, value) 

505 else: 

506 try: 

507 opts.get_field(prop) 

508 except FieldDoesNotExist: 

509 unexpected += (prop,) 

510 else: 

511 if value is not _DEFERRED: 

512 _setattr(self, prop, value) 

513 if unexpected: 

514 unexpected_names = ", ".join(repr(n) for n in unexpected) 

515 raise TypeError( 

516 f"{cls.__name__}() got unexpected keyword arguments: " 

517 f"{unexpected_names}" 

518 ) 

519 super().__init__() 

520 post_init.send(sender=cls, instance=self) 

521 

522 @classmethod 

523 def from_db(cls, db, field_names, values): 

524 if len(values) != len(cls._meta.concrete_fields): 

525 values_iter = iter(values) 

526 values = [ 

527 next(values_iter) if f.attname in field_names else DEFERRED 

528 for f in cls._meta.concrete_fields 

529 ] 

530 new = cls(*values) 

531 new._state.adding = False 

532 new._state.db = db 

533 return new 

534 

535 def __repr__(self): 

536 return f"<{self.__class__.__name__}: {self}>" 

537 

538 def __str__(self): 

539 return f"{self.__class__.__name__} object ({self.pk})" 

540 

541 def __eq__(self, other): 

542 if not isinstance(other, Model): 

543 return NotImplemented 

544 if self._meta.concrete_model != other._meta.concrete_model: 

545 return False 

546 my_pk = self.pk 

547 if my_pk is None: 

548 return self is other 

549 return my_pk == other.pk 

550 

551 def __hash__(self): 

552 if self.pk is None: 

553 raise TypeError("Model instances without primary key value are unhashable") 

554 return hash(self.pk) 

555 

556 def __reduce__(self): 

557 data = self.__getstate__() 

558 data[PLAIN_VERSION_PICKLE_KEY] = plain.runtime.__version__ 

559 class_id = self._meta.package_label, self._meta.object_name 

560 return model_unpickle, (class_id,), data 

561 

562 def __getstate__(self): 

563 """Hook to allow choosing the attributes to pickle.""" 

564 state = self.__dict__.copy() 

565 state["_state"] = copy.copy(state["_state"]) 

566 state["_state"].fields_cache = state["_state"].fields_cache.copy() 

567 # memoryview cannot be pickled, so cast it to bytes and store 

568 # separately. 

569 _memoryview_attrs = [] 

570 for attr, value in state.items(): 

571 if isinstance(value, memoryview): 

572 _memoryview_attrs.append((attr, bytes(value))) 

573 if _memoryview_attrs: 

574 state["_memoryview_attrs"] = _memoryview_attrs 

575 for attr, value in _memoryview_attrs: 

576 state.pop(attr) 

577 return state 

578 

579 def __setstate__(self, state): 

580 pickled_version = state.get(PLAIN_VERSION_PICKLE_KEY) 

581 if pickled_version: 

582 if pickled_version != plain.runtime.__version__: 

583 warnings.warn( 

584 f"Pickled model instance's Plain version {pickled_version} does not " 

585 f"match the current version {plain.runtime.__version__}.", 

586 RuntimeWarning, 

587 stacklevel=2, 

588 ) 

589 else: 

590 warnings.warn( 

591 "Pickled model instance's Plain version is not specified.", 

592 RuntimeWarning, 

593 stacklevel=2, 

594 ) 

595 if "_memoryview_attrs" in state: 

596 for attr, value in state.pop("_memoryview_attrs"): 

597 state[attr] = memoryview(value) 

598 self.__dict__.update(state) 

599 

600 def _get_pk_val(self, meta=None): 

601 meta = meta or self._meta 

602 return getattr(self, meta.pk.attname) 

603 

604 def _set_pk_val(self, value): 

605 for parent_link in self._meta.parents.values(): 

606 if parent_link and parent_link != self._meta.pk: 

607 setattr(self, parent_link.target_field.attname, value) 

608 return setattr(self, self._meta.pk.attname, value) 

609 

610 pk = property(_get_pk_val, _set_pk_val) 

611 

612 def get_deferred_fields(self): 

613 """ 

614 Return a set containing names of deferred fields for this instance. 

615 """ 

616 return { 

617 f.attname 

618 for f in self._meta.concrete_fields 

619 if f.attname not in self.__dict__ 

620 } 

621 

622 def refresh_from_db(self, using=None, fields=None): 

623 """ 

624 Reload field values from the database. 

625 

626 By default, the reloading happens from the database this instance was 

627 loaded from, or by the read router if this instance wasn't loaded from 

628 any database. The using parameter will override the default. 

629 

630 Fields can be used to specify which fields to reload. The fields 

631 should be an iterable of field attnames. If fields is None, then 

632 all non-deferred fields are reloaded. 

633 

634 When accessing deferred fields of an instance, the deferred loading 

635 of the field will call this method. 

636 """ 

637 if fields is None: 

638 self._prefetched_objects_cache = {} 

639 else: 

640 prefetched_objects_cache = getattr(self, "_prefetched_objects_cache", ()) 

641 for field in fields: 

642 if field in prefetched_objects_cache: 

643 del prefetched_objects_cache[field] 

644 fields.remove(field) 

645 if not fields: 

646 return 

647 if any(LOOKUP_SEP in f for f in fields): 

648 raise ValueError( 

649 'Found "%s" in fields argument. Relations and transforms ' 

650 "are not allowed in fields." % LOOKUP_SEP 

651 ) 

652 

653 hints = {"instance": self} 

654 db_instance_qs = self.__class__._base_manager.db_manager( 

655 using, hints=hints 

656 ).filter(pk=self.pk) 

657 

658 # Use provided fields, if not set then reload all non-deferred fields. 

659 deferred_fields = self.get_deferred_fields() 

660 if fields is not None: 

661 fields = list(fields) 

662 db_instance_qs = db_instance_qs.only(*fields) 

663 elif deferred_fields: 

664 fields = [ 

665 f.attname 

666 for f in self._meta.concrete_fields 

667 if f.attname not in deferred_fields 

668 ] 

669 db_instance_qs = db_instance_qs.only(*fields) 

670 

671 db_instance = db_instance_qs.get() 

672 non_loaded_fields = db_instance.get_deferred_fields() 

673 for field in self._meta.concrete_fields: 

674 if field.attname in non_loaded_fields: 

675 # This field wasn't refreshed - skip ahead. 

676 continue 

677 setattr(self, field.attname, getattr(db_instance, field.attname)) 

678 # Clear cached foreign keys. 

679 if field.is_relation and field.is_cached(self): 

680 field.delete_cached_value(self) 

681 

682 # Clear cached relations. 

683 for field in self._meta.related_objects: 

684 if field.is_cached(self): 

685 field.delete_cached_value(self) 

686 

687 # Clear cached private relations. 

688 for field in self._meta.private_fields: 

689 if field.is_relation and field.is_cached(self): 

690 field.delete_cached_value(self) 

691 

692 self._state.db = db_instance._state.db 

693 

694 def serializable_value(self, field_name): 

695 """ 

696 Return the value of the field name for this instance. If the field is 

697 a foreign key, return the id value instead of the object. If there's 

698 no Field object with this name on the model, return the model 

699 attribute's value. 

700 

701 Used to serialize a field's value (in the serializer, or form output, 

702 for example). Normally, you would just access the attribute directly 

703 and not use this method. 

704 """ 

705 try: 

706 field = self._meta.get_field(field_name) 

707 except FieldDoesNotExist: 

708 return getattr(self, field_name) 

709 return getattr(self, field.attname) 

710 

711 def save( 

712 self, 

713 *, 

714 clean_and_validate=True, 

715 force_insert=False, 

716 force_update=False, 

717 using=None, 

718 update_fields=None, 

719 ): 

720 """ 

721 Save the current instance. Override this in a subclass if you want to 

722 control the saving process. 

723 

724 The 'force_insert' and 'force_update' parameters can be used to insist 

725 that the "save" must be an SQL insert or update (or equivalent for 

726 non-SQL backends), respectively. Normally, they should not be set. 

727 """ 

728 self._prepare_related_fields_for_save(operation_name="save") 

729 

730 using = using or router.db_for_write(self.__class__, instance=self) 

731 if force_insert and (force_update or update_fields): 

732 raise ValueError("Cannot force both insert and updating in model saving.") 

733 

734 deferred_fields = self.get_deferred_fields() 

735 if update_fields is not None: 

736 # If update_fields is empty, skip the save. We do also check for 

737 # no-op saves later on for inheritance cases. This bailout is 

738 # still needed for skipping signal sending. 

739 if not update_fields: 

740 return 

741 

742 update_fields = frozenset(update_fields) 

743 field_names = self._meta._non_pk_concrete_field_names 

744 non_model_fields = update_fields.difference(field_names) 

745 

746 if non_model_fields: 

747 raise ValueError( 

748 "The following fields do not exist in this model, are m2m " 

749 "fields, or are non-concrete fields: %s" 

750 % ", ".join(non_model_fields) 

751 ) 

752 

753 # If saving to the same database, and this model is deferred, then 

754 # automatically do an "update_fields" save on the loaded fields. 

755 elif not force_insert and deferred_fields and using == self._state.db: 

756 field_names = set() 

757 for field in self._meta.concrete_fields: 

758 if not field.primary_key and not hasattr(field, "through"): 

759 field_names.add(field.attname) 

760 loaded_fields = field_names.difference(deferred_fields) 

761 if loaded_fields: 

762 update_fields = frozenset(loaded_fields) 

763 

764 if clean_and_validate: 

765 self.full_clean(exclude=deferred_fields) 

766 

767 self.save_base( 

768 using=using, 

769 force_insert=force_insert, 

770 force_update=force_update, 

771 update_fields=update_fields, 

772 ) 

773 

774 save.alters_data = True 

775 

776 def save_base( 

777 self, 

778 *, 

779 raw=False, 

780 force_insert=False, 

781 force_update=False, 

782 using=None, 

783 update_fields=None, 

784 ): 

785 """ 

786 Handle the parts of saving which should be done only once per save, 

787 yet need to be done in raw saves, too. This includes some sanity 

788 checks and signal sending. 

789 

790 The 'raw' argument is telling save_base not to save any parent 

791 models and not to do any changes to the values before save. This 

792 is used by fixture loading. 

793 """ 

794 using = using or router.db_for_write(self.__class__, instance=self) 

795 assert not (force_insert and (force_update or update_fields)) 

796 assert update_fields is None or update_fields 

797 cls = origin = self.__class__ 

798 meta = cls._meta 

799 if not meta.auto_created: 

800 pre_save.send( 

801 sender=origin, 

802 instance=self, 

803 raw=raw, 

804 using=using, 

805 update_fields=update_fields, 

806 ) 

807 # A transaction isn't needed if one query is issued. 

808 if meta.parents: 

809 context_manager = transaction.atomic(using=using, savepoint=False) 

810 else: 

811 context_manager = transaction.mark_for_rollback_on_error(using=using) 

812 with context_manager: 

813 parent_inserted = False 

814 if not raw: 

815 parent_inserted = self._save_parents(cls, using, update_fields) 

816 updated = self._save_table( 

817 raw, 

818 cls, 

819 force_insert or parent_inserted, 

820 force_update, 

821 using, 

822 update_fields, 

823 ) 

824 # Store the database on which the object was saved 

825 self._state.db = using 

826 # Once saved, this is no longer a to-be-added instance. 

827 self._state.adding = False 

828 

829 # Signal that the save is complete 

830 if not meta.auto_created: 

831 post_save.send( 

832 sender=origin, 

833 instance=self, 

834 created=(not updated), 

835 update_fields=update_fields, 

836 raw=raw, 

837 using=using, 

838 ) 

839 

840 save_base.alters_data = True 

841 

842 def _save_parents(self, cls, using, update_fields): 

843 """Save all the parents of cls using values from self.""" 

844 meta = cls._meta 

845 inserted = False 

846 for parent, field in meta.parents.items(): 

847 # Make sure the link fields are synced between parent and self. 

848 if ( 

849 field 

850 and getattr(self, parent._meta.pk.attname) is None 

851 and getattr(self, field.attname) is not None 

852 ): 

853 setattr(self, parent._meta.pk.attname, getattr(self, field.attname)) 

854 parent_inserted = self._save_parents( 

855 cls=parent, using=using, update_fields=update_fields 

856 ) 

857 updated = self._save_table( 

858 cls=parent, 

859 using=using, 

860 update_fields=update_fields, 

861 force_insert=parent_inserted, 

862 ) 

863 if not updated: 

864 inserted = True 

865 # Set the parent's PK value to self. 

866 if field: 

867 setattr(self, field.attname, self._get_pk_val(parent._meta)) 

868 # Since we didn't have an instance of the parent handy set 

869 # attname directly, bypassing the descriptor. Invalidate 

870 # the related object cache, in case it's been accidentally 

871 # populated. A fresh instance will be re-built from the 

872 # database if necessary. 

873 if field.is_cached(self): 

874 field.delete_cached_value(self) 

875 return inserted 

876 

877 def _save_table( 

878 self, 

879 raw=False, 

880 cls=None, 

881 force_insert=False, 

882 force_update=False, 

883 using=None, 

884 update_fields=None, 

885 ): 

886 """ 

887 Do the heavy-lifting involved in saving. Update or insert the data 

888 for a single table. 

889 """ 

890 meta = cls._meta 

891 non_pks = [f for f in meta.local_concrete_fields if not f.primary_key] 

892 

893 if update_fields: 

894 non_pks = [ 

895 f 

896 for f in non_pks 

897 if f.name in update_fields or f.attname in update_fields 

898 ] 

899 

900 pk_val = self._get_pk_val(meta) 

901 if pk_val is None: 

902 pk_val = meta.pk.get_pk_value_on_save(self) 

903 setattr(self, meta.pk.attname, pk_val) 

904 pk_set = pk_val is not None 

905 if not pk_set and (force_update or update_fields): 

906 raise ValueError("Cannot force an update in save() with no primary key.") 

907 updated = False 

908 # Skip an UPDATE when adding an instance and primary key has a default. 

909 if ( 

910 not raw 

911 and not force_insert 

912 and self._state.adding 

913 and meta.pk.default 

914 and meta.pk.default is not NOT_PROVIDED 

915 ): 

916 force_insert = True 

917 # If possible, try an UPDATE. If that doesn't update anything, do an INSERT. 

918 if pk_set and not force_insert: 

919 base_qs = cls._base_manager.using(using) 

920 values = [ 

921 ( 

922 f, 

923 None, 

924 (getattr(self, f.attname) if raw else f.pre_save(self, False)), 

925 ) 

926 for f in non_pks 

927 ] 

928 forced_update = update_fields or force_update 

929 updated = self._do_update( 

930 base_qs, using, pk_val, values, update_fields, forced_update 

931 ) 

932 if force_update and not updated: 

933 raise DatabaseError("Forced update did not affect any rows.") 

934 if update_fields and not updated: 

935 raise DatabaseError("Save with update_fields did not affect any rows.") 

936 if not updated: 

937 if meta.order_with_respect_to: 

938 # If this is a model with an order_with_respect_to 

939 # autopopulate the _order field 

940 field = meta.order_with_respect_to 

941 filter_args = field.get_filter_kwargs_for_object(self) 

942 self._order = ( 

943 cls._base_manager.using(using) 

944 .filter(**filter_args) 

945 .aggregate( 

946 _order__max=Coalesce( 

947 ExpressionWrapper( 

948 Max("_order") + Value(1), output_field=IntegerField() 

949 ), 

950 Value(0), 

951 ), 

952 )["_order__max"] 

953 ) 

954 fields = meta.local_concrete_fields 

955 if not pk_set: 

956 fields = [f for f in fields if f is not meta.auto_field] 

957 

958 returning_fields = meta.db_returning_fields 

959 results = self._do_insert( 

960 cls._base_manager, using, fields, returning_fields, raw 

961 ) 

962 if results: 

963 for value, field in zip(results[0], returning_fields): 

964 setattr(self, field.attname, value) 

965 return updated 

966 

967 def _do_update(self, base_qs, using, pk_val, values, update_fields, forced_update): 

968 """ 

969 Try to update the model. Return True if the model was updated (if an 

970 update query was done and a matching row was found in the DB). 

971 """ 

972 filtered = base_qs.filter(pk=pk_val) 

973 if not values: 

974 # We can end up here when saving a model in inheritance chain where 

975 # update_fields doesn't target any field in current model. In that 

976 # case we just say the update succeeded. Another case ending up here 

977 # is a model with just PK - in that case check that the PK still 

978 # exists. 

979 return update_fields is not None or filtered.exists() 

980 if self._meta.select_on_save and not forced_update: 

981 return ( 

982 filtered.exists() 

983 and 

984 # It may happen that the object is deleted from the DB right after 

985 # this check, causing the subsequent UPDATE to return zero matching 

986 # rows. The same result can occur in some rare cases when the 

987 # database returns zero despite the UPDATE being executed 

988 # successfully (a row is matched and updated). In order to 

989 # distinguish these two cases, the object's existence in the 

990 # database is again checked for if the UPDATE query returns 0. 

991 (filtered._update(values) > 0 or filtered.exists()) 

992 ) 

993 return filtered._update(values) > 0 

994 

995 def _do_insert(self, manager, using, fields, returning_fields, raw): 

996 """ 

997 Do an INSERT. If returning_fields is defined then this method should 

998 return the newly created data for the model. 

999 """ 

1000 return manager._insert( 

1001 [self], 

1002 fields=fields, 

1003 returning_fields=returning_fields, 

1004 using=using, 

1005 raw=raw, 

1006 ) 

1007 

1008 def _prepare_related_fields_for_save(self, operation_name, fields=None): 

1009 # Ensure that a model instance without a PK hasn't been assigned to 

1010 # a ForeignKey, GenericForeignKey or OneToOneField on this model. If 

1011 # the field is nullable, allowing the save would result in silent data 

1012 # loss. 

1013 for field in self._meta.concrete_fields: 

1014 if fields and field not in fields: 

1015 continue 

1016 # If the related field isn't cached, then an instance hasn't been 

1017 # assigned and there's no need to worry about this check. 

1018 if field.is_relation and field.is_cached(self): 

1019 obj = getattr(self, field.name, None) 

1020 if not obj: 

1021 continue 

1022 # A pk may have been assigned manually to a model instance not 

1023 # saved to the database (or auto-generated in a case like 

1024 # UUIDField), but we allow the save to proceed and rely on the 

1025 # database to raise an IntegrityError if applicable. If 

1026 # constraints aren't supported by the database, there's the 

1027 # unavoidable risk of data corruption. 

1028 if obj.pk is None: 

1029 # Remove the object from a related instance cache. 

1030 if not field.remote_field.multiple: 

1031 field.remote_field.delete_cached_value(obj) 

1032 raise ValueError( 

1033 "{}() prohibited to prevent data loss due to unsaved " 

1034 "related object '{}'.".format(operation_name, field.name) 

1035 ) 

1036 elif getattr(self, field.attname) in field.empty_values: 

1037 # Set related object if it has been saved after an 

1038 # assignment. 

1039 setattr(self, field.name, obj) 

1040 # If the relationship's pk/to_field was changed, clear the 

1041 # cached relationship. 

1042 if getattr(obj, field.target_field.attname) != getattr( 

1043 self, field.attname 

1044 ): 

1045 field.delete_cached_value(self) 

1046 # GenericForeignKeys are private. 

1047 for field in self._meta.private_fields: 

1048 if fields and field not in fields: 

1049 continue 

1050 if ( 

1051 field.is_relation 

1052 and field.is_cached(self) 

1053 and hasattr(field, "fk_field") 

1054 ): 

1055 obj = field.get_cached_value(self, default=None) 

1056 if obj and obj.pk is None: 

1057 raise ValueError( 

1058 f"{operation_name}() prohibited to prevent data loss due to " 

1059 f"unsaved related object '{field.name}'." 

1060 ) 

1061 

1062 def delete(self, using=None, keep_parents=False): 

1063 if self.pk is None: 

1064 raise ValueError( 

1065 "{} object can't be deleted because its {} attribute is set " 

1066 "to None.".format(self._meta.object_name, self._meta.pk.attname) 

1067 ) 

1068 using = using or router.db_for_write(self.__class__, instance=self) 

1069 collector = Collector(using=using, origin=self) 

1070 collector.collect([self], keep_parents=keep_parents) 

1071 return collector.delete() 

1072 

1073 delete.alters_data = True 

1074 

1075 def _get_FIELD_display(self, field): 

1076 value = getattr(self, field.attname) 

1077 choices_dict = dict(make_hashable(field.flatchoices)) 

1078 # force_str() to coerce lazy strings. 

1079 return force_str( 

1080 choices_dict.get(make_hashable(value), value), strings_only=True 

1081 ) 

1082 

1083 def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs): 

1084 if not self.pk: 

1085 raise ValueError("get_next/get_previous cannot be used on unsaved objects.") 

1086 op = "gt" if is_next else "lt" 

1087 order = "" if is_next else "-" 

1088 param = getattr(self, field.attname) 

1089 q = Q.create([(field.name, param), (f"pk__{op}", self.pk)], connector=Q.AND) 

1090 q = Q.create([q, (f"{field.name}__{op}", param)], connector=Q.OR) 

1091 qs = ( 

1092 self.__class__._default_manager.using(self._state.db) 

1093 .filter(**kwargs) 

1094 .filter(q) 

1095 .order_by(f"{order}{field.name}", "%spk" % order) 

1096 ) 

1097 try: 

1098 return qs[0] 

1099 except IndexError: 

1100 raise self.DoesNotExist( 

1101 "%s matching query does not exist." % self.__class__._meta.object_name 

1102 ) 

1103 

1104 def _get_next_or_previous_in_order(self, is_next): 

1105 cachename = "__%s_order_cache" % is_next 

1106 if not hasattr(self, cachename): 

1107 op = "gt" if is_next else "lt" 

1108 order = "_order" if is_next else "-_order" 

1109 order_field = self._meta.order_with_respect_to 

1110 filter_args = order_field.get_filter_kwargs_for_object(self) 

1111 obj = ( 

1112 self.__class__._default_manager.filter(**filter_args) 

1113 .filter( 

1114 **{ 

1115 "_order__%s" % op: self.__class__._default_manager.values( 

1116 "_order" 

1117 ).filter(**{self._meta.pk.name: self.pk}) 

1118 } 

1119 ) 

1120 .order_by(order)[:1] 

1121 .get() 

1122 ) 

1123 setattr(self, cachename, obj) 

1124 return getattr(self, cachename) 

1125 

1126 def _get_field_value_map(self, meta, exclude=None): 

1127 if exclude is None: 

1128 exclude = set() 

1129 meta = meta or self._meta 

1130 return { 

1131 field.name: Value(getattr(self, field.attname), field) 

1132 for field in meta.local_concrete_fields 

1133 if field.name not in exclude 

1134 } 

1135 

1136 def prepare_database_save(self, field): 

1137 if self.pk is None: 

1138 raise ValueError( 

1139 "Unsaved model instance %r cannot be used in an ORM query." % self 

1140 ) 

1141 return getattr(self, field.remote_field.get_related_field().attname) 

1142 

1143 def clean(self): 

1144 """ 

1145 Hook for doing any extra model-wide validation after clean() has been 

1146 called on every field by self.clean_fields. Any ValidationError raised 

1147 by this method will not be associated with a particular field; it will 

1148 have a special-case association with the field defined by NON_FIELD_ERRORS. 

1149 """ 

1150 pass 

1151 

1152 def validate_unique(self, exclude=None): 

1153 """ 

1154 Check unique constraints on the model and raise ValidationError if any 

1155 failed. 

1156 """ 

1157 unique_checks = self._get_unique_checks(exclude=exclude) 

1158 

1159 if errors := self._perform_unique_checks(unique_checks): 

1160 raise ValidationError(errors) 

1161 

1162 def _get_unique_checks(self, exclude=None): 

1163 """ 

1164 Return a list of checks to perform. Since validate_unique() could be 

1165 called from a ModelForm, some fields may have been excluded; we can't 

1166 perform a unique check on a model that is missing fields involved 

1167 in that check. Fields that did not validate should also be excluded, 

1168 but they need to be passed in via the exclude argument. 

1169 """ 

1170 if exclude is None: 

1171 exclude = set() 

1172 unique_checks = [] 

1173 

1174 # Gather a list of checks for fields declared as unique and add them to 

1175 # the list of checks. 

1176 

1177 fields_with_class = [(self.__class__, self._meta.local_fields)] 

1178 for parent_class in self._meta.get_parent_list(): 

1179 fields_with_class.append((parent_class, parent_class._meta.local_fields)) 

1180 

1181 for model_class, fields in fields_with_class: 

1182 for f in fields: 

1183 name = f.name 

1184 if name in exclude: 

1185 continue 

1186 if f.unique: 

1187 unique_checks.append((model_class, (name,))) 

1188 

1189 return unique_checks 

1190 

1191 def _perform_unique_checks(self, unique_checks): 

1192 errors = {} 

1193 

1194 for model_class, unique_check in unique_checks: 

1195 # Try to look up an existing object with the same values as this 

1196 # object's values for all the unique field. 

1197 

1198 lookup_kwargs = {} 

1199 for field_name in unique_check: 

1200 f = self._meta.get_field(field_name) 

1201 lookup_value = getattr(self, f.attname) 

1202 # TODO: Handle multiple backends with different feature flags. 

1203 if lookup_value is None or ( 

1204 lookup_value == "" 

1205 and connection.features.interprets_empty_strings_as_nulls 

1206 ): 

1207 # no value, skip the lookup 

1208 continue 

1209 if f.primary_key and not self._state.adding: 

1210 # no need to check for unique primary key when editing 

1211 continue 

1212 lookup_kwargs[str(field_name)] = lookup_value 

1213 

1214 # some fields were skipped, no reason to do the check 

1215 if len(unique_check) != len(lookup_kwargs): 

1216 continue 

1217 

1218 qs = model_class._default_manager.filter(**lookup_kwargs) 

1219 

1220 # Exclude the current object from the query if we are editing an 

1221 # instance (as opposed to creating a new one) 

1222 # Note that we need to use the pk as defined by model_class, not 

1223 # self.pk. These can be different fields because model inheritance 

1224 # allows single model to have effectively multiple primary keys. 

1225 # Refs #17615. 

1226 model_class_pk = self._get_pk_val(model_class._meta) 

1227 if not self._state.adding and model_class_pk is not None: 

1228 qs = qs.exclude(pk=model_class_pk) 

1229 if qs.exists(): 

1230 if len(unique_check) == 1: 

1231 key = unique_check[0] 

1232 else: 

1233 key = NON_FIELD_ERRORS 

1234 errors.setdefault(key, []).append( 

1235 self.unique_error_message(model_class, unique_check) 

1236 ) 

1237 

1238 return errors 

1239 

1240 def unique_error_message(self, model_class, unique_check): 

1241 opts = model_class._meta 

1242 

1243 params = { 

1244 "model": self, 

1245 "model_class": model_class, 

1246 "model_name": opts.model_name, 

1247 "unique_check": unique_check, 

1248 } 

1249 

1250 if len(unique_check) == 1: 

1251 field = opts.get_field(unique_check[0]) 

1252 params["field_label"] = field.name 

1253 return ValidationError( 

1254 message=field.error_messages["unique"], 

1255 code="unique", 

1256 params=params, 

1257 ) 

1258 else: 

1259 field_names = [opts.get_field(f).name for f in unique_check] 

1260 

1261 # Put an "and" before the last one 

1262 field_names[-1] = f"and {field_names[-1]}" 

1263 

1264 if len(field_names) > 2: 

1265 # Comma join if more than 2 

1266 params["field_label"] = ", ".join(field_names) 

1267 else: 

1268 # Just a space if there are only 2 

1269 params["field_label"] = " ".join(field_names) 

1270 

1271 # Use the first field as the message format... 

1272 message = opts.get_field(unique_check[0]).error_messages["unique"] 

1273 

1274 return ValidationError( 

1275 message=message, 

1276 code="unique", 

1277 params=params, 

1278 ) 

1279 

1280 def get_constraints(self): 

1281 constraints = [(self.__class__, self._meta.constraints)] 

1282 for parent_class in self._meta.get_parent_list(): 

1283 if parent_class._meta.constraints: 

1284 constraints.append((parent_class, parent_class._meta.constraints)) 

1285 return constraints 

1286 

1287 def validate_constraints(self, exclude=None): 

1288 constraints = self.get_constraints() 

1289 using = router.db_for_write(self.__class__, instance=self) 

1290 

1291 errors = {} 

1292 for model_class, model_constraints in constraints: 

1293 for constraint in model_constraints: 

1294 try: 

1295 constraint.validate(model_class, self, exclude=exclude, using=using) 

1296 except ValidationError as e: 

1297 if ( 

1298 getattr(e, "code", None) == "unique" 

1299 and len(constraint.fields) == 1 

1300 ): 

1301 errors.setdefault(constraint.fields[0], []).append(e) 

1302 else: 

1303 errors = e.update_error_dict(errors) 

1304 if errors: 

1305 raise ValidationError(errors) 

1306 

1307 def full_clean( 

1308 self, *, exclude=None, validate_unique=True, validate_constraints=True 

1309 ): 

1310 """ 

1311 Call clean_fields(), clean(), validate_unique(), and 

1312 validate_constraints() on the model. Raise a ValidationError for any 

1313 errors that occur. 

1314 """ 

1315 errors = {} 

1316 if exclude is None: 

1317 exclude = set() 

1318 else: 

1319 exclude = set(exclude) 

1320 

1321 try: 

1322 self.clean_fields(exclude=exclude) 

1323 except ValidationError as e: 

1324 errors = e.update_error_dict(errors) 

1325 

1326 # Form.clean() is run even if other validation fails, so do the 

1327 # same with Model.clean() for consistency. 

1328 try: 

1329 self.clean() 

1330 except ValidationError as e: 

1331 errors = e.update_error_dict(errors) 

1332 

1333 # Run unique checks, but only for fields that passed validation. 

1334 if validate_unique: 

1335 for name in errors: 

1336 if name != NON_FIELD_ERRORS and name not in exclude: 

1337 exclude.add(name) 

1338 try: 

1339 self.validate_unique(exclude=exclude) 

1340 except ValidationError as e: 

1341 errors = e.update_error_dict(errors) 

1342 

1343 # Run constraints checks, but only for fields that passed validation. 

1344 if validate_constraints: 

1345 for name in errors: 

1346 if name != NON_FIELD_ERRORS and name not in exclude: 

1347 exclude.add(name) 

1348 try: 

1349 self.validate_constraints(exclude=exclude) 

1350 except ValidationError as e: 

1351 errors = e.update_error_dict(errors) 

1352 

1353 if errors: 

1354 raise ValidationError(errors) 

1355 

1356 def clean_fields(self, exclude=None): 

1357 """ 

1358 Clean all fields and raise a ValidationError containing a dict 

1359 of all validation errors if any occur. 

1360 """ 

1361 if exclude is None: 

1362 exclude = set() 

1363 

1364 errors = {} 

1365 for f in self._meta.fields: 

1366 if f.name in exclude: 

1367 continue 

1368 # Skip validation for empty fields with blank=True. The developer 

1369 # is responsible for making sure they have a valid value. 

1370 raw_value = getattr(self, f.attname) 

1371 if f.blank and raw_value in f.empty_values: 

1372 continue 

1373 try: 

1374 setattr(self, f.attname, f.clean(raw_value, self)) 

1375 except ValidationError as e: 

1376 errors[f.name] = e.error_list 

1377 

1378 if errors: 

1379 raise ValidationError(errors) 

1380 

1381 @classmethod 

1382 def check(cls, **kwargs): 

1383 errors = [ 

1384 *cls._check_swappable(), 

1385 *cls._check_managers(**kwargs), 

1386 ] 

1387 if not cls._meta.swapped: 

1388 databases = kwargs.get("databases") or [] 

1389 errors += [ 

1390 *cls._check_fields(**kwargs), 

1391 *cls._check_m2m_through_same_relationship(), 

1392 *cls._check_long_column_names(databases), 

1393 ] 

1394 clash_errors = ( 

1395 *cls._check_id_field(), 

1396 *cls._check_field_name_clashes(), 

1397 *cls._check_model_name_db_lookup_clashes(), 

1398 *cls._check_property_name_related_field_accessor_clashes(), 

1399 *cls._check_single_primary_key(), 

1400 ) 

1401 errors.extend(clash_errors) 

1402 # If there are field name clashes, hide consequent column name 

1403 # clashes. 

1404 if not clash_errors: 

1405 errors.extend(cls._check_column_name_clashes()) 

1406 errors += [ 

1407 *cls._check_indexes(databases), 

1408 *cls._check_ordering(), 

1409 *cls._check_constraints(databases), 

1410 *cls._check_db_table_comment(databases), 

1411 ] 

1412 

1413 return errors 

1414 

1415 @classmethod 

1416 def _check_db_table_comment(cls, databases): 

1417 if not cls._meta.db_table_comment: 

1418 return [] 

1419 errors = [] 

1420 for db in databases: 

1421 if not router.allow_migrate_model(db, cls): 

1422 continue 

1423 connection = connections[db] 

1424 if not ( 

1425 connection.features.supports_comments 

1426 or "supports_comments" in cls._meta.required_db_features 

1427 ): 

1428 errors.append( 

1429 preflight.Warning( 

1430 f"{connection.display_name} does not support comments on " 

1431 f"tables (db_table_comment).", 

1432 obj=cls, 

1433 id="models.W046", 

1434 ) 

1435 ) 

1436 return errors 

1437 

1438 @classmethod 

1439 def _check_swappable(cls): 

1440 """Check if the swapped model exists.""" 

1441 errors = [] 

1442 if cls._meta.swapped: 

1443 try: 

1444 packages.get_model(cls._meta.swapped) 

1445 except ValueError: 

1446 errors.append( 

1447 preflight.Error( 

1448 "'%s' is not of the form 'package_label.package_name'." 

1449 % cls._meta.swappable, 

1450 id="models.E001", 

1451 ) 

1452 ) 

1453 except LookupError: 

1454 package_label, model_name = cls._meta.swapped.split(".") 

1455 errors.append( 

1456 preflight.Error( 

1457 "'{}' references '{}.{}', which has not been " 

1458 "installed, or is abstract.".format( 

1459 cls._meta.swappable, package_label, model_name 

1460 ), 

1461 id="models.E002", 

1462 ) 

1463 ) 

1464 return errors 

1465 

1466 @classmethod 

1467 def _check_managers(cls, **kwargs): 

1468 """Perform all manager checks.""" 

1469 errors = [] 

1470 for manager in cls._meta.managers: 

1471 errors.extend(manager.check(**kwargs)) 

1472 return errors 

1473 

1474 @classmethod 

1475 def _check_fields(cls, **kwargs): 

1476 """Perform all field checks.""" 

1477 errors = [] 

1478 for field in cls._meta.local_fields: 

1479 errors.extend(field.check(**kwargs)) 

1480 for field in cls._meta.local_many_to_many: 

1481 errors.extend(field.check(from_model=cls, **kwargs)) 

1482 return errors 

1483 

1484 @classmethod 

1485 def _check_m2m_through_same_relationship(cls): 

1486 """Check if no relationship model is used by more than one m2m field.""" 

1487 

1488 errors = [] 

1489 seen_intermediary_signatures = [] 

1490 

1491 fields = cls._meta.local_many_to_many 

1492 

1493 # Skip when the target model wasn't found. 

1494 fields = (f for f in fields if isinstance(f.remote_field.model, ModelBase)) 

1495 

1496 # Skip when the relationship model wasn't found. 

1497 fields = (f for f in fields if isinstance(f.remote_field.through, ModelBase)) 

1498 

1499 for f in fields: 

1500 signature = ( 

1501 f.remote_field.model, 

1502 cls, 

1503 f.remote_field.through, 

1504 f.remote_field.through_fields, 

1505 ) 

1506 if signature in seen_intermediary_signatures: 

1507 errors.append( 

1508 preflight.Error( 

1509 "The model has two identical many-to-many relations " 

1510 "through the intermediate model '%s'." 

1511 % f.remote_field.through._meta.label, 

1512 obj=cls, 

1513 id="models.E003", 

1514 ) 

1515 ) 

1516 else: 

1517 seen_intermediary_signatures.append(signature) 

1518 return errors 

1519 

1520 @classmethod 

1521 def _check_id_field(cls): 

1522 """Check if `id` field is a primary key.""" 

1523 fields = [ 

1524 f for f in cls._meta.local_fields if f.name == "id" and f != cls._meta.pk 

1525 ] 

1526 # fields is empty or consists of the invalid "id" field 

1527 if fields and not fields[0].primary_key and cls._meta.pk.name == "id": 

1528 return [ 

1529 preflight.Error( 

1530 "'id' can only be used as a field name if the field also " 

1531 "sets 'primary_key=True'.", 

1532 obj=cls, 

1533 id="models.E004", 

1534 ) 

1535 ] 

1536 else: 

1537 return [] 

1538 

1539 @classmethod 

1540 def _check_field_name_clashes(cls): 

1541 """Forbid field shadowing in multi-table inheritance.""" 

1542 errors = [] 

1543 used_fields = {} # name or attname -> field 

1544 

1545 # Check that multi-inheritance doesn't cause field name shadowing. 

1546 for parent in cls._meta.get_parent_list(): 

1547 for f in parent._meta.local_fields: 

1548 clash = used_fields.get(f.name) or used_fields.get(f.attname) or None 

1549 if clash: 

1550 errors.append( 

1551 preflight.Error( 

1552 f"The field '{clash.name}' from parent model " 

1553 f"'{clash.model._meta}' clashes with the field '{f.name}' " 

1554 f"from parent model '{f.model._meta}'.", 

1555 obj=cls, 

1556 id="models.E005", 

1557 ) 

1558 ) 

1559 used_fields[f.name] = f 

1560 used_fields[f.attname] = f 

1561 

1562 # Check that fields defined in the model don't clash with fields from 

1563 # parents, including auto-generated fields like multi-table inheritance 

1564 # child accessors. 

1565 for parent in cls._meta.get_parent_list(): 

1566 for f in parent._meta.get_fields(): 

1567 if f not in used_fields: 

1568 used_fields[f.name] = f 

1569 

1570 for f in cls._meta.local_fields: 

1571 clash = used_fields.get(f.name) or used_fields.get(f.attname) or None 

1572 # Note that we may detect clash between user-defined non-unique 

1573 # field "id" and automatically added unique field "id", both 

1574 # defined at the same model. This special case is considered in 

1575 # _check_id_field and here we ignore it. 

1576 id_conflict = ( 

1577 f.name == "id" and clash and clash.name == "id" and clash.model == cls 

1578 ) 

1579 if clash and not id_conflict: 

1580 errors.append( 

1581 preflight.Error( 

1582 f"The field '{f.name}' clashes with the field '{clash.name}' " 

1583 f"from model '{clash.model._meta}'.", 

1584 obj=f, 

1585 id="models.E006", 

1586 ) 

1587 ) 

1588 used_fields[f.name] = f 

1589 used_fields[f.attname] = f 

1590 

1591 return errors 

1592 

1593 @classmethod 

1594 def _check_column_name_clashes(cls): 

1595 # Store a list of column names which have already been used by other fields. 

1596 used_column_names = [] 

1597 errors = [] 

1598 

1599 for f in cls._meta.local_fields: 

1600 _, column_name = f.get_attname_column() 

1601 

1602 # Ensure the column name is not already in use. 

1603 if column_name and column_name in used_column_names: 

1604 errors.append( 

1605 preflight.Error( 

1606 "Field '{}' has column name '{}' that is used by " 

1607 "another field.".format(f.name, column_name), 

1608 hint="Specify a 'db_column' for the field.", 

1609 obj=cls, 

1610 id="models.E007", 

1611 ) 

1612 ) 

1613 else: 

1614 used_column_names.append(column_name) 

1615 

1616 return errors 

1617 

1618 @classmethod 

1619 def _check_model_name_db_lookup_clashes(cls): 

1620 errors = [] 

1621 model_name = cls.__name__ 

1622 if model_name.startswith("_") or model_name.endswith("_"): 

1623 errors.append( 

1624 preflight.Error( 

1625 "The model name '%s' cannot start or end with an underscore " 

1626 "as it collides with the query lookup syntax." % model_name, 

1627 obj=cls, 

1628 id="models.E023", 

1629 ) 

1630 ) 

1631 elif LOOKUP_SEP in model_name: 

1632 errors.append( 

1633 preflight.Error( 

1634 "The model name '%s' cannot contain double underscores as " 

1635 "it collides with the query lookup syntax." % model_name, 

1636 obj=cls, 

1637 id="models.E024", 

1638 ) 

1639 ) 

1640 return errors 

1641 

1642 @classmethod 

1643 def _check_property_name_related_field_accessor_clashes(cls): 

1644 errors = [] 

1645 property_names = cls._meta._property_names 

1646 related_field_accessors = ( 

1647 f.get_attname() 

1648 for f in cls._meta._get_fields(reverse=False) 

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

1650 ) 

1651 for accessor in related_field_accessors: 

1652 if accessor in property_names: 

1653 errors.append( 

1654 preflight.Error( 

1655 "The property '%s' clashes with a related field " 

1656 "accessor." % accessor, 

1657 obj=cls, 

1658 id="models.E025", 

1659 ) 

1660 ) 

1661 return errors 

1662 

1663 @classmethod 

1664 def _check_single_primary_key(cls): 

1665 errors = [] 

1666 if sum(1 for f in cls._meta.local_fields if f.primary_key) > 1: 

1667 errors.append( 

1668 preflight.Error( 

1669 "The model cannot have more than one field with " 

1670 "'primary_key=True'.", 

1671 obj=cls, 

1672 id="models.E026", 

1673 ) 

1674 ) 

1675 return errors 

1676 

1677 @classmethod 

1678 def _check_indexes(cls, databases): 

1679 """Check fields, names, and conditions of indexes.""" 

1680 errors = [] 

1681 references = set() 

1682 for index in cls._meta.indexes: 

1683 # Index name can't start with an underscore or a number, restricted 

1684 # for cross-database compatibility with Oracle. 

1685 if index.name[0] == "_" or index.name[0].isdigit(): 

1686 errors.append( 

1687 preflight.Error( 

1688 "The index name '%s' cannot start with an underscore " 

1689 "or a number." % index.name, 

1690 obj=cls, 

1691 id="models.E033", 

1692 ), 

1693 ) 

1694 if len(index.name) > index.max_name_length: 

1695 errors.append( 

1696 preflight.Error( 

1697 "The index name '%s' cannot be longer than %d " 

1698 "characters." % (index.name, index.max_name_length), 

1699 obj=cls, 

1700 id="models.E034", 

1701 ), 

1702 ) 

1703 if index.contains_expressions: 

1704 for expression in index.expressions: 

1705 references.update( 

1706 ref[0] for ref in cls._get_expr_references(expression) 

1707 ) 

1708 for db in databases: 

1709 if not router.allow_migrate_model(db, cls): 

1710 continue 

1711 connection = connections[db] 

1712 if not ( 

1713 connection.features.supports_partial_indexes 

1714 or "supports_partial_indexes" in cls._meta.required_db_features 

1715 ) and any(index.condition is not None for index in cls._meta.indexes): 

1716 errors.append( 

1717 preflight.Warning( 

1718 "%s does not support indexes with conditions." 

1719 % connection.display_name, 

1720 hint=( 

1721 "Conditions will be ignored. Silence this warning " 

1722 "if you don't care about it." 

1723 ), 

1724 obj=cls, 

1725 id="models.W037", 

1726 ) 

1727 ) 

1728 if not ( 

1729 connection.features.supports_covering_indexes 

1730 or "supports_covering_indexes" in cls._meta.required_db_features 

1731 ) and any(index.include for index in cls._meta.indexes): 

1732 errors.append( 

1733 preflight.Warning( 

1734 "%s does not support indexes with non-key columns." 

1735 % connection.display_name, 

1736 hint=( 

1737 "Non-key columns will be ignored. Silence this " 

1738 "warning if you don't care about it." 

1739 ), 

1740 obj=cls, 

1741 id="models.W040", 

1742 ) 

1743 ) 

1744 if not ( 

1745 connection.features.supports_expression_indexes 

1746 or "supports_expression_indexes" in cls._meta.required_db_features 

1747 ) and any(index.contains_expressions for index in cls._meta.indexes): 

1748 errors.append( 

1749 preflight.Warning( 

1750 "%s does not support indexes on expressions." 

1751 % connection.display_name, 

1752 hint=( 

1753 "An index won't be created. Silence this warning " 

1754 "if you don't care about it." 

1755 ), 

1756 obj=cls, 

1757 id="models.W043", 

1758 ) 

1759 ) 

1760 fields = [ 

1761 field for index in cls._meta.indexes for field, _ in index.fields_orders 

1762 ] 

1763 fields += [include for index in cls._meta.indexes for include in index.include] 

1764 fields += references 

1765 errors.extend(cls._check_local_fields(fields, "indexes")) 

1766 return errors 

1767 

1768 @classmethod 

1769 def _check_local_fields(cls, fields, option): 

1770 from plain import models 

1771 

1772 # In order to avoid hitting the relation tree prematurely, we use our 

1773 # own fields_map instead of using get_field() 

1774 forward_fields_map = {} 

1775 for field in cls._meta._get_fields(reverse=False): 

1776 forward_fields_map[field.name] = field 

1777 if hasattr(field, "attname"): 

1778 forward_fields_map[field.attname] = field 

1779 

1780 errors = [] 

1781 for field_name in fields: 

1782 try: 

1783 field = forward_fields_map[field_name] 

1784 except KeyError: 

1785 errors.append( 

1786 preflight.Error( 

1787 f"'{option}' refers to the nonexistent field '{field_name}'.", 

1788 obj=cls, 

1789 id="models.E012", 

1790 ) 

1791 ) 

1792 else: 

1793 if isinstance(field.remote_field, models.ManyToManyRel): 

1794 errors.append( 

1795 preflight.Error( 

1796 "'{}' refers to a ManyToManyField '{}', but " 

1797 "ManyToManyFields are not permitted in '{}'.".format( 

1798 option, 

1799 field_name, 

1800 option, 

1801 ), 

1802 obj=cls, 

1803 id="models.E013", 

1804 ) 

1805 ) 

1806 elif field not in cls._meta.local_fields: 

1807 errors.append( 

1808 preflight.Error( 

1809 "'{}' refers to field '{}' which is not local to model " 

1810 "'{}'.".format(option, field_name, cls._meta.object_name), 

1811 hint="This issue may be caused by multi-table inheritance.", 

1812 obj=cls, 

1813 id="models.E016", 

1814 ) 

1815 ) 

1816 return errors 

1817 

1818 @classmethod 

1819 def _check_ordering(cls): 

1820 """ 

1821 Check "ordering" option -- is it a list of strings and do all fields 

1822 exist? 

1823 """ 

1824 if cls._meta._ordering_clash: 

1825 return [ 

1826 preflight.Error( 

1827 "'ordering' and 'order_with_respect_to' cannot be used together.", 

1828 obj=cls, 

1829 id="models.E021", 

1830 ), 

1831 ] 

1832 

1833 if cls._meta.order_with_respect_to or not cls._meta.ordering: 

1834 return [] 

1835 

1836 if not isinstance(cls._meta.ordering, list | tuple): 

1837 return [ 

1838 preflight.Error( 

1839 "'ordering' must be a tuple or list (even if you want to order by " 

1840 "only one field).", 

1841 obj=cls, 

1842 id="models.E014", 

1843 ) 

1844 ] 

1845 

1846 errors = [] 

1847 fields = cls._meta.ordering 

1848 

1849 # Skip expressions and '?' fields. 

1850 fields = (f for f in fields if isinstance(f, str) and f != "?") 

1851 

1852 # Convert "-field" to "field". 

1853 fields = (f.removeprefix("-") for f in fields) 

1854 

1855 # Separate related fields and non-related fields. 

1856 _fields = [] 

1857 related_fields = [] 

1858 for f in fields: 

1859 if LOOKUP_SEP in f: 

1860 related_fields.append(f) 

1861 else: 

1862 _fields.append(f) 

1863 fields = _fields 

1864 

1865 # Check related fields. 

1866 for field in related_fields: 

1867 _cls = cls 

1868 fld = None 

1869 for part in field.split(LOOKUP_SEP): 

1870 try: 

1871 # pk is an alias that won't be found by opts.get_field. 

1872 if part == "pk": 

1873 fld = _cls._meta.pk 

1874 else: 

1875 fld = _cls._meta.get_field(part) 

1876 if fld.is_relation: 

1877 _cls = fld.path_infos[-1].to_opts.model 

1878 else: 

1879 _cls = None 

1880 except (FieldDoesNotExist, AttributeError): 

1881 if fld is None or ( 

1882 fld.get_transform(part) is None and fld.get_lookup(part) is None 

1883 ): 

1884 errors.append( 

1885 preflight.Error( 

1886 "'ordering' refers to the nonexistent field, " 

1887 "related field, or lookup '%s'." % field, 

1888 obj=cls, 

1889 id="models.E015", 

1890 ) 

1891 ) 

1892 

1893 # Skip ordering on pk. This is always a valid order_by field 

1894 # but is an alias and therefore won't be found by opts.get_field. 

1895 fields = {f for f in fields if f != "pk"} 

1896 

1897 # Check for invalid or nonexistent fields in ordering. 

1898 invalid_fields = [] 

1899 

1900 # Any field name that is not present in field_names does not exist. 

1901 # Also, ordering by m2m fields is not allowed. 

1902 opts = cls._meta 

1903 valid_fields = set( 

1904 chain.from_iterable( 

1905 (f.name, f.attname) 

1906 if not (f.auto_created and not f.concrete) 

1907 else (f.field.related_query_name(),) 

1908 for f in chain(opts.fields, opts.related_objects) 

1909 ) 

1910 ) 

1911 

1912 invalid_fields.extend(fields - valid_fields) 

1913 

1914 for invalid_field in invalid_fields: 

1915 errors.append( 

1916 preflight.Error( 

1917 "'ordering' refers to the nonexistent field, related " 

1918 "field, or lookup '%s'." % invalid_field, 

1919 obj=cls, 

1920 id="models.E015", 

1921 ) 

1922 ) 

1923 return errors 

1924 

1925 @classmethod 

1926 def _check_long_column_names(cls, databases): 

1927 """ 

1928 Check that any auto-generated column names are shorter than the limits 

1929 for each database in which the model will be created. 

1930 """ 

1931 if not databases: 

1932 return [] 

1933 errors = [] 

1934 allowed_len = None 

1935 db_alias = None 

1936 

1937 # Find the minimum max allowed length among all specified db_aliases. 

1938 for db in databases: 

1939 # skip databases where the model won't be created 

1940 if not router.allow_migrate_model(db, cls): 

1941 continue 

1942 connection = connections[db] 

1943 max_name_length = connection.ops.max_name_length() 

1944 if max_name_length is None or connection.features.truncates_names: 

1945 continue 

1946 else: 

1947 if allowed_len is None: 

1948 allowed_len = max_name_length 

1949 db_alias = db 

1950 elif max_name_length < allowed_len: 

1951 allowed_len = max_name_length 

1952 db_alias = db 

1953 

1954 if allowed_len is None: 

1955 return errors 

1956 

1957 for f in cls._meta.local_fields: 

1958 _, column_name = f.get_attname_column() 

1959 

1960 # Check if auto-generated name for the field is too long 

1961 # for the database. 

1962 if ( 

1963 f.db_column is None 

1964 and column_name is not None 

1965 and len(column_name) > allowed_len 

1966 ): 

1967 errors.append( 

1968 preflight.Error( 

1969 'Autogenerated column name too long for field "{}". ' 

1970 'Maximum length is "{}" for database "{}".'.format( 

1971 column_name, allowed_len, db_alias 

1972 ), 

1973 hint="Set the column name manually using 'db_column'.", 

1974 obj=cls, 

1975 id="models.E018", 

1976 ) 

1977 ) 

1978 

1979 for f in cls._meta.local_many_to_many: 

1980 # Skip nonexistent models. 

1981 if isinstance(f.remote_field.through, str): 

1982 continue 

1983 

1984 # Check if auto-generated name for the M2M field is too long 

1985 # for the database. 

1986 for m2m in f.remote_field.through._meta.local_fields: 

1987 _, rel_name = m2m.get_attname_column() 

1988 if ( 

1989 m2m.db_column is None 

1990 and rel_name is not None 

1991 and len(rel_name) > allowed_len 

1992 ): 

1993 errors.append( 

1994 preflight.Error( 

1995 "Autogenerated column name too long for M2M field " 

1996 '"{}". Maximum length is "{}" for database "{}".'.format( 

1997 rel_name, allowed_len, db_alias 

1998 ), 

1999 hint=( 

2000 "Use 'through' to create a separate model for " 

2001 "M2M and then set column_name using 'db_column'." 

2002 ), 

2003 obj=cls, 

2004 id="models.E019", 

2005 ) 

2006 ) 

2007 

2008 return errors 

2009 

2010 @classmethod 

2011 def _get_expr_references(cls, expr): 

2012 if isinstance(expr, Q): 

2013 for child in expr.children: 

2014 if isinstance(child, tuple): 

2015 lookup, value = child 

2016 yield tuple(lookup.split(LOOKUP_SEP)) 

2017 yield from cls._get_expr_references(value) 

2018 else: 

2019 yield from cls._get_expr_references(child) 

2020 elif isinstance(expr, F): 

2021 yield tuple(expr.name.split(LOOKUP_SEP)) 

2022 elif hasattr(expr, "get_source_expressions"): 

2023 for src_expr in expr.get_source_expressions(): 

2024 yield from cls._get_expr_references(src_expr) 

2025 

2026 @classmethod 

2027 def _check_constraints(cls, databases): 

2028 errors = [] 

2029 for db in databases: 

2030 if not router.allow_migrate_model(db, cls): 

2031 continue 

2032 connection = connections[db] 

2033 if not ( 

2034 connection.features.supports_table_check_constraints 

2035 or "supports_table_check_constraints" in cls._meta.required_db_features 

2036 ) and any( 

2037 isinstance(constraint, CheckConstraint) 

2038 for constraint in cls._meta.constraints 

2039 ): 

2040 errors.append( 

2041 preflight.Warning( 

2042 "%s does not support check constraints." 

2043 % connection.display_name, 

2044 hint=( 

2045 "A constraint won't be created. Silence this " 

2046 "warning if you don't care about it." 

2047 ), 

2048 obj=cls, 

2049 id="models.W027", 

2050 ) 

2051 ) 

2052 if not ( 

2053 connection.features.supports_partial_indexes 

2054 or "supports_partial_indexes" in cls._meta.required_db_features 

2055 ) and any( 

2056 isinstance(constraint, UniqueConstraint) 

2057 and constraint.condition is not None 

2058 for constraint in cls._meta.constraints 

2059 ): 

2060 errors.append( 

2061 preflight.Warning( 

2062 "%s does not support unique constraints with " 

2063 "conditions." % connection.display_name, 

2064 hint=( 

2065 "A constraint won't be created. Silence this " 

2066 "warning if you don't care about it." 

2067 ), 

2068 obj=cls, 

2069 id="models.W036", 

2070 ) 

2071 ) 

2072 if not ( 

2073 connection.features.supports_deferrable_unique_constraints 

2074 or "supports_deferrable_unique_constraints" 

2075 in cls._meta.required_db_features 

2076 ) and any( 

2077 isinstance(constraint, UniqueConstraint) 

2078 and constraint.deferrable is not None 

2079 for constraint in cls._meta.constraints 

2080 ): 

2081 errors.append( 

2082 preflight.Warning( 

2083 "%s does not support deferrable unique constraints." 

2084 % connection.display_name, 

2085 hint=( 

2086 "A constraint won't be created. Silence this " 

2087 "warning if you don't care about it." 

2088 ), 

2089 obj=cls, 

2090 id="models.W038", 

2091 ) 

2092 ) 

2093 if not ( 

2094 connection.features.supports_covering_indexes 

2095 or "supports_covering_indexes" in cls._meta.required_db_features 

2096 ) and any( 

2097 isinstance(constraint, UniqueConstraint) and constraint.include 

2098 for constraint in cls._meta.constraints 

2099 ): 

2100 errors.append( 

2101 preflight.Warning( 

2102 "%s does not support unique constraints with non-key " 

2103 "columns." % connection.display_name, 

2104 hint=( 

2105 "A constraint won't be created. Silence this " 

2106 "warning if you don't care about it." 

2107 ), 

2108 obj=cls, 

2109 id="models.W039", 

2110 ) 

2111 ) 

2112 if not ( 

2113 connection.features.supports_expression_indexes 

2114 or "supports_expression_indexes" in cls._meta.required_db_features 

2115 ) and any( 

2116 isinstance(constraint, UniqueConstraint) 

2117 and constraint.contains_expressions 

2118 for constraint in cls._meta.constraints 

2119 ): 

2120 errors.append( 

2121 preflight.Warning( 

2122 "%s does not support unique constraints on " 

2123 "expressions." % connection.display_name, 

2124 hint=( 

2125 "A constraint won't be created. Silence this " 

2126 "warning if you don't care about it." 

2127 ), 

2128 obj=cls, 

2129 id="models.W044", 

2130 ) 

2131 ) 

2132 fields = set( 

2133 chain.from_iterable( 

2134 (*constraint.fields, *constraint.include) 

2135 for constraint in cls._meta.constraints 

2136 if isinstance(constraint, UniqueConstraint) 

2137 ) 

2138 ) 

2139 references = set() 

2140 for constraint in cls._meta.constraints: 

2141 if isinstance(constraint, UniqueConstraint): 

2142 if ( 

2143 connection.features.supports_partial_indexes 

2144 or "supports_partial_indexes" 

2145 not in cls._meta.required_db_features 

2146 ) and isinstance(constraint.condition, Q): 

2147 references.update( 

2148 cls._get_expr_references(constraint.condition) 

2149 ) 

2150 if ( 

2151 connection.features.supports_expression_indexes 

2152 or "supports_expression_indexes" 

2153 not in cls._meta.required_db_features 

2154 ) and constraint.contains_expressions: 

2155 for expression in constraint.expressions: 

2156 references.update(cls._get_expr_references(expression)) 

2157 elif isinstance(constraint, CheckConstraint): 

2158 if ( 

2159 connection.features.supports_table_check_constraints 

2160 or "supports_table_check_constraints" 

2161 not in cls._meta.required_db_features 

2162 ): 

2163 if isinstance(constraint.check, Q): 

2164 references.update( 

2165 cls._get_expr_references(constraint.check) 

2166 ) 

2167 if any( 

2168 isinstance(expr, RawSQL) 

2169 for expr in constraint.check.flatten() 

2170 ): 

2171 errors.append( 

2172 preflight.Warning( 

2173 f"Check constraint {constraint.name!r} contains " 

2174 f"RawSQL() expression and won't be validated " 

2175 f"during the model full_clean().", 

2176 hint=( 

2177 "Silence this warning if you don't care about " 

2178 "it." 

2179 ), 

2180 obj=cls, 

2181 id="models.W045", 

2182 ), 

2183 ) 

2184 for field_name, *lookups in references: 

2185 # pk is an alias that won't be found by opts.get_field. 

2186 if field_name != "pk": 

2187 fields.add(field_name) 

2188 if not lookups: 

2189 # If it has no lookups it cannot result in a JOIN. 

2190 continue 

2191 try: 

2192 if field_name == "pk": 

2193 field = cls._meta.pk 

2194 else: 

2195 field = cls._meta.get_field(field_name) 

2196 if not field.is_relation or field.many_to_many or field.one_to_many: 

2197 continue 

2198 except FieldDoesNotExist: 

2199 continue 

2200 # JOIN must happen at the first lookup. 

2201 first_lookup = lookups[0] 

2202 if ( 

2203 hasattr(field, "get_transform") 

2204 and hasattr(field, "get_lookup") 

2205 and field.get_transform(first_lookup) is None 

2206 and field.get_lookup(first_lookup) is None 

2207 ): 

2208 errors.append( 

2209 preflight.Error( 

2210 "'constraints' refers to the joined field '%s'." 

2211 % LOOKUP_SEP.join([field_name] + lookups), 

2212 obj=cls, 

2213 id="models.E041", 

2214 ) 

2215 ) 

2216 errors.extend(cls._check_local_fields(fields, "constraints")) 

2217 return errors 

2218 

2219 

2220############################################ 

2221# HELPER FUNCTIONS (CURRIED MODEL METHODS) # 

2222############################################ 

2223 

2224# ORDERING METHODS ######################### 

2225 

2226 

2227def method_set_order(self, ordered_obj, id_list, using=None): 

2228 order_wrt = ordered_obj._meta.order_with_respect_to 

2229 filter_args = order_wrt.get_forward_related_filter(self) 

2230 ordered_obj.objects.db_manager(using).filter(**filter_args).bulk_update( 

2231 [ordered_obj(pk=pk, _order=order) for order, pk in enumerate(id_list)], 

2232 ["_order"], 

2233 ) 

2234 

2235 

2236def method_get_order(self, ordered_obj): 

2237 order_wrt = ordered_obj._meta.order_with_respect_to 

2238 filter_args = order_wrt.get_forward_related_filter(self) 

2239 pk_name = ordered_obj._meta.pk.name 

2240 return ordered_obj.objects.filter(**filter_args).values_list(pk_name, flat=True) 

2241 

2242 

2243def make_foreign_order_accessors(model, related_model): 

2244 setattr( 

2245 related_model, 

2246 "get_%s_order" % model.__name__.lower(), 

2247 partialmethod(method_get_order, model), 

2248 ) 

2249 setattr( 

2250 related_model, 

2251 "set_%s_order" % model.__name__.lower(), 

2252 partialmethod(method_set_order, model), 

2253 ) 

2254 

2255 

2256######## 

2257# MISC # 

2258######## 

2259 

2260 

2261def model_unpickle(model_id): 

2262 """Used to unpickle Model subclasses with deferred fields.""" 

2263 if isinstance(model_id, tuple): 

2264 model = packages.get_model(*model_id) 

2265 else: 

2266 # Backwards compat - the model was cached directly in earlier versions. 

2267 model = model_id 

2268 return model.__new__(model) 

2269 

2270 

2271model_unpickle.__safe_for_unpickle__ = True