Code

Ticket #3438: models-init.patch

File models-init.patch, 5.5 KB (added by (removed), 7 years ago)

django.db.models.base.Model.init refactoring

  • django/db/models/base.py

    old new  
    1313from django.utils.datastructures import SortedDict 
    1414from django.utils.functional import curry 
    1515from django.conf import settings 
     16from itertools import izip 
    1617import types 
    1718import sys 
    1819import os 
     
    9091 
    9192    def __init__(self, *args, **kwargs): 
    9293        dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) 
    93         for f in self._meta.fields: 
    94             if isinstance(f.rel, ManyToOneRel): 
    95                 try: 
    96                     # Assume object instance was passed in. 
    97                     rel_obj = kwargs.pop(f.name) 
    98                 except KeyError: 
     94        # there is a rather weird disparity here; if kwargs, it's set, then args overrides it. 
     95        # should be one or the other, don't duplicate the work 
     96        # the reason for the kwargs check is that standard iterator passes in by args, literally, 
     97        # the row- with this check, instantiation for iteration is 33% faster. 
     98        args_len = len(args) 
     99        if args_len > len(self._meta.fields): 
     100            # daft, but matches old exception sans the err msg. 
     101            raise IndexError("number of args exceeds number of fields") 
     102 
     103        fields_iter = iter(self._meta.fields) 
     104        if not kwargs: 
     105            # ordering of the izip calls matter- izip throws StopIteration when an iter throws it 
     106            # meaning, if the first iter throws it, the second is *not* consumed from 
     107            # we rely on this, thus don't change the order without changing the logic. 
     108            for val, field in izip(args, fields_iter): 
     109                setattr(self, field.attname, val) 
     110        else: 
     111            # slower... 
     112            for val, field in izip(args, fields_iter): 
     113                setattr(self, field.attname, val) 
     114                kwargs.pop(field.name, None) 
     115                # maintain compatibility with existing calls, daft as it is. 
     116                if isinstance(field.rel, ManyToOneRel): 
     117                    kwargs.pop(field.attname, None) 
     118         
     119        # now we're left with the unprocessed fields that *must* come from keywords, or default. 
     120         
     121        for field in fields_iter: 
     122            if kwargs: 
     123                if isinstance(field.rel, ManyToOneRel): 
    99124                    try: 
    100                         # Object instance wasn't passed in -- must be an ID. 
    101                         val = kwargs.pop(f.attname) 
     125                        # Assume object instance was passed in. 
     126                        rel_obj = kwargs.pop(field.name) 
    102127                    except KeyError: 
    103                         val = f.get_default() 
    104                 else: 
    105                     # Object instance was passed in. 
    106                     # Special case: You can pass in "None" for related objects if it's allowed. 
    107                     if rel_obj is None and f.null: 
    108                         val = None 
    109                     else: 
    110128                        try: 
    111                             val = getattr(rel_obj, f.rel.get_related_field().attname) 
    112                         except AttributeError: 
    113                             raise TypeError, "Invalid value: %r should be a %s instance, not a %s" % (f.name, f.rel.to, type(rel_obj)) 
    114                 setattr(self, f.attname, val) 
     129                            # Object instance wasn't passed in -- must be an ID. 
     130                            val = kwargs.pop(field.attname) 
     131                        except KeyError: 
     132                            val = field.get_default() 
     133                    else: 
     134                        # Object instance was passed in. 
     135                        # Special case: You can pass in "None" for related objects if it's allowed. 
     136                        if rel_obj is None and field.null: 
     137                            val = None 
     138                        else: 
     139                            try: 
     140                                val = getattr(rel_obj, field.rel.get_related_field().attname) 
     141                            except AttributeError: 
     142                                raise TypeError("Invalid value: %r should be a %s instance, not a %s" %  
     143                                    (field.name, field.rel.to, type(rel_obj))) 
     144                else: 
     145                    val = kwargs.pop(field.attname, field.get_default()) 
    115146            else: 
    116                 val = kwargs.pop(f.attname, f.get_default()) 
    117                 setattr(self, f.attname, val) 
    118         for prop in kwargs.keys(): 
    119             try: 
    120                 if isinstance(getattr(self.__class__, prop), property): 
    121                     setattr(self, prop, kwargs.pop(prop)) 
    122             except AttributeError: 
    123                 pass 
     147                val = field.get_default() 
     148            setattr(self, field.attname, val) 
     149 
    124150        if kwargs: 
    125             raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] 
    126         for i, arg in enumerate(args): 
    127             setattr(self, self._meta.fields[i].attname, arg) 
     151            for prop in kwargs.keys(): 
     152                try: 
     153                    if isinstance(getattr(self.__class__, prop), property): 
     154                        setattr(self, prop, kwargs.pop(prop)) 
     155                except AttributeError: 
     156                    pass 
     157            if kwargs: 
     158                raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] 
    128159        dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self) 
    129160 
    130161    def add_to_class(cls, name, value):