plain.models
Model your data and store it in a database.
# app/users/models.py
from plain import models
from plain.passwords.models import PasswordField
class User(models.Model):
email = models.EmailField(unique=True)
password = PasswordField()
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.email
Create, update, and delete instances of your models:
from .models import User
# Create a new user
user = User.objects.create(
email="[email protected]",
password="password",
)
# Update a user
user.email = "[email protected]"
user.save()
# Delete a user
user.delete()
# Query for users
staff_users = User.objects.filter(is_staff=True)
Installation
# app/settings.py
INSTALLED_PACKAGES = [
...
"plain.models",
]
To connect to a database, you can provide a DATABASE_URL
environment variable.
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
Or you can manually define the DATABASES
setting.
# app/settings.py
DATABASES = {
"default": {
"ENGINE": "plain.models.backends.postgresql",
"NAME": "dbname",
"USER": "user",
"PASSWORD": "password",
"HOST": "localhost",
"PORT": "5432",
}
}
Multiple backends are supported, including Postgres, MySQL, and SQLite.
Querying
Migrations
Fields
Validation
Indexes and constraints
Managers
Forms
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