mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Optimized Model instantiation a bit.
* Avoid some unnecessary attribute lookups, e.g. access signals directly rather than from module * Alias some repeat accesses inside the method to use the slightly faster local lookups * Use tuple to iterate remaining kwargs as it's faster to construct * Cache Field.get_default() to avoid running through all the logic on every call * Use a cached list of the properties on the model class to avoid repeat isinstance() calls
This commit is contained in:
		| @@ -16,7 +16,6 @@ from django.db import ( | |||||||
|     DEFAULT_DB_ALIAS, DJANGO_VERSION_PICKLE_KEY, DatabaseError, connection, |     DEFAULT_DB_ALIAS, DJANGO_VERSION_PICKLE_KEY, DatabaseError, connection, | ||||||
|     connections, router, transaction, |     connections, router, transaction, | ||||||
| ) | ) | ||||||
| from django.db.models import signals |  | ||||||
| from django.db.models.constants import LOOKUP_SEP | from django.db.models.constants import LOOKUP_SEP | ||||||
| from django.db.models.deletion import CASCADE, Collector | from django.db.models.deletion import CASCADE, Collector | ||||||
| from django.db.models.fields.related import ( | from django.db.models.fields.related import ( | ||||||
| @@ -25,6 +24,9 @@ from django.db.models.fields.related import ( | |||||||
| from django.db.models.manager import Manager | from django.db.models.manager import Manager | ||||||
| from django.db.models.options import Options | from django.db.models.options import Options | ||||||
| from django.db.models.query import Q | from django.db.models.query import Q | ||||||
|  | from django.db.models.signals import ( | ||||||
|  |     class_prepared, post_init, post_save, pre_init, pre_save, | ||||||
|  | ) | ||||||
| from django.db.models.utils import make_model_tuple | from django.db.models.utils import make_model_tuple | ||||||
| from django.utils import six | from django.utils import six | ||||||
| from django.utils.deprecation import RemovedInDjango20Warning | from django.utils.deprecation import RemovedInDjango20Warning | ||||||
| @@ -366,7 +368,7 @@ class ModelBase(type): | |||||||
|             manager.auto_created = True |             manager.auto_created = True | ||||||
|             cls.add_to_class('objects', manager) |             cls.add_to_class('objects', manager) | ||||||
|  |  | ||||||
|         signals.class_prepared.send(sender=cls) |         class_prepared.send(sender=cls) | ||||||
|  |  | ||||||
|     def _requires_legacy_default_manager(cls):  # RemovedInDjango20Warning |     def _requires_legacy_default_manager(cls):  # RemovedInDjango20Warning | ||||||
|         opts = cls._meta |         opts = cls._meta | ||||||
| @@ -465,7 +467,13 @@ class ModelState(object): | |||||||
| class Model(six.with_metaclass(ModelBase)): | class Model(six.with_metaclass(ModelBase)): | ||||||
|  |  | ||||||
|     def __init__(self, *args, **kwargs): |     def __init__(self, *args, **kwargs): | ||||||
|         signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs) |         # Alias some things as locals to avoid repeat global lookups | ||||||
|  |         cls = self.__class__ | ||||||
|  |         opts = self._meta | ||||||
|  |         _setattr = setattr | ||||||
|  |         _DEFERRED = DEFERRED | ||||||
|  |  | ||||||
|  |         pre_init.send(sender=cls, args=args, kwargs=kwargs) | ||||||
|  |  | ||||||
|         # Set up the storage for instance state |         # Set up the storage for instance state | ||||||
|         self._state = ModelState() |         self._state = ModelState() | ||||||
| @@ -474,27 +482,27 @@ class Model(six.with_metaclass(ModelBase)): | |||||||
|         # overrides it. It should be one or the other; don't duplicate the work |         # overrides it. It should be one or the other; don't duplicate the work | ||||||
|         # The reason for the kwargs check is that standard iterator passes in by |         # The reason for the kwargs check is that standard iterator passes in by | ||||||
|         # args, and instantiation for iteration is 33% faster. |         # args, and instantiation for iteration is 33% faster. | ||||||
|         if len(args) > len(self._meta.concrete_fields): |         if len(args) > len(opts.concrete_fields): | ||||||
|             # Daft, but matches old exception sans the err msg. |             # Daft, but matches old exception sans the err msg. | ||||||
|             raise IndexError("Number of args exceeds number of fields") |             raise IndexError("Number of args exceeds number of fields") | ||||||
|  |  | ||||||
|         if not kwargs: |         if not kwargs: | ||||||
|             fields_iter = iter(self._meta.concrete_fields) |             fields_iter = iter(opts.concrete_fields) | ||||||
|             # The ordering of the zip calls matter - zip throws StopIteration |             # The ordering of the zip calls matter - zip throws StopIteration | ||||||
|             # when an iter throws it. So if the first iter throws it, the second |             # when an iter throws it. So if the first iter throws it, the second | ||||||
|             # is *not* consumed. We rely on this, so don't change the order |             # is *not* consumed. We rely on this, so don't change the order | ||||||
|             # without changing the logic. |             # without changing the logic. | ||||||
|             for val, field in zip(args, fields_iter): |             for val, field in zip(args, fields_iter): | ||||||
|                 if val is DEFERRED: |                 if val is _DEFERRED: | ||||||
|                     continue |                     continue | ||||||
|                 setattr(self, field.attname, val) |                 _setattr(self, field.attname, val) | ||||||
|         else: |         else: | ||||||
|             # Slower, kwargs-ready version. |             # Slower, kwargs-ready version. | ||||||
|             fields_iter = iter(self._meta.fields) |             fields_iter = iter(opts.fields) | ||||||
|             for val, field in zip(args, fields_iter): |             for val, field in zip(args, fields_iter): | ||||||
|                 if val is DEFERRED: |                 if val is _DEFERRED: | ||||||
|                     continue |                     continue | ||||||
|                 setattr(self, field.attname, val) |                 _setattr(self, field.attname, val) | ||||||
|                 kwargs.pop(field.name, None) |                 kwargs.pop(field.name, None) | ||||||
|  |  | ||||||
|         # Now we're left with the unprocessed fields that *must* come from |         # Now we're left with the unprocessed fields that *must* come from | ||||||
| @@ -539,28 +547,28 @@ class Model(six.with_metaclass(ModelBase)): | |||||||
|                 # field.name instead of field.attname (e.g. "user" instead of |                 # field.name instead of field.attname (e.g. "user" instead of | ||||||
|                 # "user_id") so that the object gets properly cached (and type |                 # "user_id") so that the object gets properly cached (and type | ||||||
|                 # checked) by the RelatedObjectDescriptor. |                 # checked) by the RelatedObjectDescriptor. | ||||||
|                 if rel_obj is not DEFERRED: |                 if rel_obj is not _DEFERRED: | ||||||
|                     setattr(self, field.name, rel_obj) |                     _setattr(self, field.name, rel_obj) | ||||||
|             else: |             else: | ||||||
|                 if val is not DEFERRED: |                 if val is not _DEFERRED: | ||||||
|                     setattr(self, field.attname, val) |                     _setattr(self, field.attname, val) | ||||||
|  |  | ||||||
|         if kwargs: |         if kwargs: | ||||||
|             for prop in list(kwargs): |             property_names = opts._property_names | ||||||
|  |             for prop in tuple(kwargs): | ||||||
|                 try: |                 try: | ||||||
|                     # Any remaining kwargs must correspond to properties or |                     # Any remaining kwargs must correspond to properties or | ||||||
|                     # virtual fields. |                     # virtual fields. | ||||||
|                     if (isinstance(getattr(self.__class__, prop), property) or |                     if prop in property_names or opts.get_field(prop): | ||||||
|                             self._meta.get_field(prop)): |                         if kwargs[prop] is not _DEFERRED: | ||||||
|                         if kwargs[prop] is not DEFERRED: |                             _setattr(self, prop, kwargs[prop]) | ||||||
|                             setattr(self, prop, kwargs[prop]) |  | ||||||
|                         del kwargs[prop] |                         del kwargs[prop] | ||||||
|                 except (AttributeError, FieldDoesNotExist): |                 except (AttributeError, FieldDoesNotExist): | ||||||
|                     pass |                     pass | ||||||
|             if kwargs: |             if kwargs: | ||||||
|                 raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0]) |                 raise TypeError("'%s' is an invalid keyword argument for this function" % list(kwargs)[0]) | ||||||
|         super(Model, self).__init__() |         super(Model, self).__init__() | ||||||
|         signals.post_init.send(sender=self.__class__, instance=self) |         post_init.send(sender=cls, instance=self) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def from_db(cls, db, field_names, values): |     def from_db(cls, db, field_names, values): | ||||||
| @@ -816,8 +824,10 @@ class Model(six.with_metaclass(ModelBase)): | |||||||
|             cls = cls._meta.concrete_model |             cls = cls._meta.concrete_model | ||||||
|         meta = cls._meta |         meta = cls._meta | ||||||
|         if not meta.auto_created: |         if not meta.auto_created: | ||||||
|             signals.pre_save.send(sender=origin, instance=self, raw=raw, using=using, |             pre_save.send( | ||||||
|                                   update_fields=update_fields) |                 sender=origin, instance=self, raw=raw, using=using, | ||||||
|  |                 update_fields=update_fields, | ||||||
|  |             ) | ||||||
|         with transaction.atomic(using=using, savepoint=False): |         with transaction.atomic(using=using, savepoint=False): | ||||||
|             if not raw: |             if not raw: | ||||||
|                 self._save_parents(cls, using, update_fields) |                 self._save_parents(cls, using, update_fields) | ||||||
| @@ -829,8 +839,10 @@ class Model(six.with_metaclass(ModelBase)): | |||||||
|  |  | ||||||
|         # Signal that the save is complete |         # Signal that the save is complete | ||||||
|         if not meta.auto_created: |         if not meta.auto_created: | ||||||
|             signals.post_save.send(sender=origin, instance=self, created=(not updated), |             post_save.send( | ||||||
|                                    update_fields=update_fields, raw=raw, using=using) |                 sender=origin, instance=self, created=(not updated), | ||||||
|  |                 update_fields=update_fields, raw=raw, using=using, | ||||||
|  |             ) | ||||||
|  |  | ||||||
|     save_base.alters_data = True |     save_base.alters_data = True | ||||||
|  |  | ||||||
|   | |||||||
| @@ -92,6 +92,10 @@ def _empty(of_cls): | |||||||
|     return new |     return new | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def return_None(): | ||||||
|  |     return None | ||||||
|  |  | ||||||
|  |  | ||||||
| @total_ordering | @total_ordering | ||||||
| @python_2_unicode_compatible | @python_2_unicode_compatible | ||||||
| class Field(RegisterLookupMixin): | class Field(RegisterLookupMixin): | ||||||
| @@ -771,13 +775,18 @@ class Field(RegisterLookupMixin): | |||||||
|         """ |         """ | ||||||
|         Returns the default value for this field. |         Returns the default value for this field. | ||||||
|         """ |         """ | ||||||
|  |         return self._get_default() | ||||||
|  |  | ||||||
|  |     @cached_property | ||||||
|  |     def _get_default(self): | ||||||
|         if self.has_default(): |         if self.has_default(): | ||||||
|             if callable(self.default): |             if callable(self.default): | ||||||
|                 return self.default() |  | ||||||
|                 return self.default |                 return self.default | ||||||
|  |             return lambda: self.default | ||||||
|  |  | ||||||
|         if not self.empty_strings_allowed or self.null and not connection.features.interprets_empty_strings_as_nulls: |         if not self.empty_strings_allowed or self.null and not connection.features.interprets_empty_strings_as_nulls: | ||||||
|             return None |             return return_None | ||||||
|         return "" |         return six.text_type  # returns empty string | ||||||
|  |  | ||||||
|     def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH, limit_choices_to=None): |     def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH, limit_choices_to=None): | ||||||
|         """Returns choices with a default blank choices included, for use |         """Returns choices with a default blank choices included, for use | ||||||
|   | |||||||
| @@ -883,3 +883,14 @@ class Options(object): | |||||||
|     @has_auto_field.setter |     @has_auto_field.setter | ||||||
|     def has_auto_field(self, value): |     def has_auto_field(self, value): | ||||||
|         pass |         pass | ||||||
|  |  | ||||||
|  |     @cached_property | ||||||
|  |     def _property_names(self): | ||||||
|  |         """ | ||||||
|  |         Return a set of the names of the properties defined on the model. | ||||||
|  |         Internal helper for model initialization. | ||||||
|  |         """ | ||||||
|  |         return frozenset({ | ||||||
|  |             attr for attr in | ||||||
|  |             dir(self.model) if isinstance(getattr(self.model, attr), property) | ||||||
|  |         }) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user