Fixed #3438: improved the speed of Model.__init__ (about 1/3 faster, it appears). Thanks (a lot!) to Brian Harring.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@4597 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
abf79841fe
commit
90acc8ff7e
|
@ -13,6 +13,7 @@ from django.dispatch import dispatcher
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
from django.utils.functional import curry
|
from django.utils.functional import curry
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from itertools import izip
|
||||||
import types
|
import types
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
@ -90,31 +91,63 @@ class Model(object):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
|
dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
|
||||||
for f in self._meta.fields:
|
# there is a rather weird disparity here; if kwargs, it's set, then args overrides it.
|
||||||
if isinstance(f.rel, ManyToOneRel):
|
# should be one or the other, don't duplicate the work
|
||||||
|
# the reason for the kwargs check is that standard iterator passes in by args, literally,
|
||||||
|
# the row- with this check, instantiation for iteration is 33% faster.
|
||||||
|
args_len = len(args)
|
||||||
|
if args_len > len(self._meta.fields):
|
||||||
|
# daft, but matches old exception sans the err msg.
|
||||||
|
raise IndexError("number of args exceeds number of fields")
|
||||||
|
|
||||||
|
fields_iter = iter(self._meta.fields)
|
||||||
|
if not kwargs:
|
||||||
|
# ordering of the izip calls matter- izip throws StopIteration when an iter throws it
|
||||||
|
# meaning, if the first iter throws it, the second is *not* consumed from
|
||||||
|
# we rely on this, thus don't change the order without changing the logic.
|
||||||
|
for val, field in izip(args, fields_iter):
|
||||||
|
setattr(self, field.attname, val)
|
||||||
|
else:
|
||||||
|
# slower...
|
||||||
|
for val, field in izip(args, fields_iter):
|
||||||
|
setattr(self, field.attname, val)
|
||||||
|
kwargs.pop(field.name, None)
|
||||||
|
# maintain compatibility with existing calls, daft as it is.
|
||||||
|
if isinstance(field.rel, ManyToOneRel):
|
||||||
|
kwargs.pop(field.attname, None)
|
||||||
|
|
||||||
|
# now we're left with the unprocessed fields that *must* come from keywords, or default.
|
||||||
|
|
||||||
|
for field in fields_iter:
|
||||||
|
if kwargs:
|
||||||
|
if isinstance(field.rel, ManyToOneRel):
|
||||||
try:
|
try:
|
||||||
# Assume object instance was passed in.
|
# Assume object instance was passed in.
|
||||||
rel_obj = kwargs.pop(f.name)
|
rel_obj = kwargs.pop(field.name)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
try:
|
try:
|
||||||
# Object instance wasn't passed in -- must be an ID.
|
# Object instance wasn't passed in -- must be an ID.
|
||||||
val = kwargs.pop(f.attname)
|
val = kwargs.pop(field.attname)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
val = f.get_default()
|
val = field.get_default()
|
||||||
else:
|
else:
|
||||||
# Object instance was passed in.
|
# Object instance was passed in.
|
||||||
# Special case: You can pass in "None" for related objects if it's allowed.
|
# Special case: You can pass in "None" for related objects if it's allowed.
|
||||||
if rel_obj is None and f.null:
|
if rel_obj is None and field.null:
|
||||||
val = None
|
val = None
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
val = getattr(rel_obj, f.rel.get_related_field().attname)
|
val = getattr(rel_obj, field.rel.get_related_field().attname)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise TypeError, "Invalid value: %r should be a %s instance, not a %s" % (f.name, f.rel.to, type(rel_obj))
|
raise TypeError("Invalid value: %r should be a %s instance, not a %s" %
|
||||||
setattr(self, f.attname, val)
|
(field.name, field.rel.to, type(rel_obj)))
|
||||||
else:
|
else:
|
||||||
val = kwargs.pop(f.attname, f.get_default())
|
val = kwargs.pop(field.attname, field.get_default())
|
||||||
setattr(self, f.attname, val)
|
else:
|
||||||
|
val = field.get_default()
|
||||||
|
setattr(self, field.attname, val)
|
||||||
|
|
||||||
|
if kwargs:
|
||||||
for prop in kwargs.keys():
|
for prop in kwargs.keys():
|
||||||
try:
|
try:
|
||||||
if isinstance(getattr(self.__class__, prop), property):
|
if isinstance(getattr(self.__class__, prop), property):
|
||||||
|
@ -123,8 +156,6 @@ class Model(object):
|
||||||
pass
|
pass
|
||||||
if kwargs:
|
if kwargs:
|
||||||
raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]
|
raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]
|
||||||
for i, arg in enumerate(args):
|
|
||||||
setattr(self, self._meta.fields[i].attname, arg)
|
|
||||||
dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self)
|
dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self)
|
||||||
|
|
||||||
def add_to_class(cls, name, value):
|
def add_to_class(cls, name, value):
|
||||||
|
|
Loading…
Reference in New Issue