def test_deferred_fields(self): pre_save_changed.connect(func, sender=DeferredModel) obj = DeferredModel() post_init.send(instance=obj, sender=DeferredModel) assert list(obj._fieldsignals_originals.values()) == [{'a': 1}]
def test_post_save_unchanged(self): with must_be_called(False) as func: post_save_changed.connect(func, sender=FakeModel) obj = FakeModel() post_init.send(instance=obj, sender=FakeModel) # This *doesn't* call post_save_changed, because we haven't changed anything. post_save.send(instance=obj, sender=FakeModel)
def test_post_save_changed(self): with must_be_called(True) as func: post_save_changed.connect(func, sender=FakeModel) obj = FakeModel() post_init.send(instance=obj, sender=FakeModel) obj.a_key = 'another value' post_save.send(instance=obj, sender=FakeModel)
def test_pre_save_with_fields_changed(self): with must_be_called(True) as func: pre_save_changed.connect(func, sender=FakeModel, fields=('a_key',)) obj = FakeModel() post_init.send(instance=obj, sender=FakeModel) obj.a_key = 'change a field that we care about' pre_save.send(instance=obj, sender=FakeModel)
def test_pre_save_with_fields_unchanged(self): with must_be_called(False) as func: pre_save_changed.connect(func, sender=FakeModel, fields=('a_key',)) obj = FakeModel() post_init.send(instance=obj, sender=FakeModel) obj.another = 'dont care about this field' pre_save.send(instance=obj, sender=FakeModel)
def test_pre_save_with_fields_unchanged(self): with must_be_called(False) as func: pre_save_changed.connect(func, sender=FakeModel, fields=('a_key', )) obj = FakeModel() post_init.send(instance=obj, sender=FakeModel) obj.another = 'dont care about this field' pre_save.send(instance=obj, sender=FakeModel)
def test_pre_save_with_fields_changed(self): with must_be_called(True) as func: pre_save_changed.connect(func, sender=FakeModel, fields=('a_key', )) obj = FakeModel() post_init.send(instance=obj, sender=FakeModel) obj.a_key = 'change a field that we care about' pre_save.send(instance=obj, sender=FakeModel)
def test_pre_save_changed(self): with must_be_called(True) as func: pre_save_changed.connect(func, sender=FakeModel) obj = FakeModel() # post_init sets list of initial values post_init.send(instance=obj, sender=FakeModel) obj.a_key = 'another value' pre_save.send(instance=obj, sender=FakeModel)
def test_post_save_changed(self): with must_be_called(True) as func: post_save_changed.connect(func, sender=FakeModel) obj = FakeModel() post_init.send(instance=obj, sender=FakeModel) obj.a_key = "another value" post_save.send(instance=obj, sender=FakeModel) assert func.kwargs["changed_fields"] == { "a_key": ("a value", "another value") }
def test_pre_save_with_fields_changed(self): with must_be_called(True) as func: pre_save_changed.connect(func, sender=FakeModel, fields=("a_key", )) obj = FakeModel() post_init.send(instance=obj, sender=FakeModel) obj.a_key = "change a field that we care about" pre_save.send(instance=obj, sender=FakeModel) assert func.kwargs["changed_fields"] == { "a_key": ("a value", "change a field that we care about") }
def __init__(self, *args, **kwargs): cls = self.__class__ opts = self._meta _setattr = setattr self._dn = None pre_init.send(sender=cls, args=args, kwargs=kwargs) if len(args) > len(opts.fields): # Daft, but matches old exception sans the err msg. raise IndexError("Number of args exceeds number of fields") if not kwargs: fields_iter = iter(opts.fields) for val, field in zip(args, fields_iter): _setattr(self, field.name, val) else: # Slower, kwargs-ready version. fields_iter = iter(opts.fields) for val, field in zip(args, fields_iter): _setattr(self, field.name, val) kwargs.pop(field.name, None) # Now we're left with the unprocessed fields that *must* come from # keywords, or default. for field in fields_iter: if kwargs: try: val = kwargs.pop(field.name) except KeyError: # This is done with an exception rather than the # default argument on pop because we don't want # get_default() to be evaluated, and then not used. # Refs #12057. val = field.get_default() else: val = field.get_default() _setattr(self, field.name, val) if kwargs and '_dn' in kwargs: _setattr(self, '_dn', kwargs['_dn']) kwargs.pop('_dn') if kwargs: for kwarg in kwargs: raise TypeError("'%s' is an invalid keyword argument for this function" % kwarg) super().__init__() post_init.send(sender=cls, instance=self)
def __init__(self, **kwargs): self.pk = getattr(self, 'pk', None) self._models.append(self) for key, value in kwargs.iteritems(): setattr(self, key, value) def save_side_effect(): if self.pk is None: self.pk = random.randint(1000, 10000) post_init.send(sender=self.__class__, instance=self) self.save = Mock(name='save', side_effect=save_side_effect) self.delete = Mock(name='delete')
def test_compare_after_to_python(self): """ Field values (e.g. datetimes) are equal even if set via string. Ensures that to_python() is called prior to comparison between old & new values. """ with must_be_called(False) as func: pre_save_changed.connect(func, sender=FakeModel, fields=('a_datetime',)) obj = FakeModel() obj.a_datetime = '2017-01-01T00:00:00.000000Z' post_init.send(instance=obj, sender=FakeModel) # This is identical to the above, even though the type is different, # so don't call the signal obj.a_datetime = datetime.datetime(2017, 1, 1, 0, 0, 0, 0, utc) pre_save.send(instance=obj, sender=FakeModel)
def test_compare_after_to_python(self): """ Field values (e.g. datetimes) are equal even if set via string. Ensures that to_python() is called prior to comparison between old & new values. """ with must_be_called(False) as func: pre_save_changed.connect(func, sender=FakeModel, fields=('a_datetime', )) obj = FakeModel() obj.a_datetime = '2017-01-01T00:00:00.000000Z' post_init.send(instance=obj, sender=FakeModel) # This is identical to the above, even though the type is different, # so don't call the signal obj.a_datetime = datetime.datetime(2017, 1, 1, 0, 0, 0, 0, utc) pre_save.send(instance=obj, sender=FakeModel)
def __init__(self, *args, **kwargs): cls = self.__class__ pre_init.send(sender=cls, args=args, kwargs=kwargs) super().__init__(*args, **kwargs) post_init.send(sender=cls, instance=self)
def __init__(self, *args, **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 self._state = ModelState() # There is a rather weird disparity here; if kwargs, it's set, then args # 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 # args, and instantiation for iteration is 33% faster. if len(args) > len(opts.concrete_fields): # Daft, but matches old exception sans the err msg. raise IndexError("Number of args exceeds number of fields") if not kwargs: fields_iter = iter(opts.concrete_fields) # The ordering of the zip calls matter - zip throws StopIteration # 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 # without changing the logic. for val, field in zip(args, fields_iter): if val is _DEFERRED: continue _setattr(self, field.attname, val) else: # Slower, kwargs-ready version. fields_iter = iter(opts.fields) for val, field in zip(args, fields_iter): if val is _DEFERRED: continue _setattr(self, field.attname, val) kwargs.pop(field.name, None) # Now we're left with the unprocessed fields that *must* come from # keywords, or default. for field in fields_iter: is_related_object = False # Virtual field if field.attname not in kwargs and field.column is None: continue if kwargs: if isinstance(field.remote_field, ForeignObjectRel): try: # Assume object instance was passed in. rel_obj = kwargs.pop(field.name) is_related_object = True except KeyError: try: # Object instance wasn't passed in -- must be an ID. val = kwargs.pop(field.attname) except KeyError: val = field.get_default() else: # Object instance was passed in. Special case: You can # pass in "None" for related objects if it's allowed. if rel_obj is None and field.null: val = None else: try: val = kwargs.pop(field.attname) except KeyError: # This is done with an exception rather than the # default argument on pop because we don't want # get_default() to be evaluated, and then not used. # Refs #12057. val = field.get_default() else: val = field.get_default() if is_related_object: # If we are passed a related instance, set it using the # field.name instead of field.attname (e.g. "user" instead of # "user_id") so that the object gets properly cached (and type # checked) by the RelatedObjectDescriptor. if rel_obj is not _DEFERRED: _setattr(self, field.name, rel_obj) else: if val is not _DEFERRED: _setattr(self, field.attname, val) if kwargs: property_names = opts._property_names for prop in tuple(kwargs): try: # Any remaining kwargs must correspond to properties or # virtual fields. if prop in property_names or opts.get_field(prop): if kwargs[prop] is not _DEFERRED: _setattr(self, prop, kwargs[prop]) del kwargs[prop] except (AttributeError, FieldDoesNotExist): pass if kwargs: for key, value in kwargs.items(): if hasattr(self, key): raise TypeError( "'%s' is an invalid keyword argument for this function" % key) setattr(self, key, value) super(Model, self).__init__() post_init.send(sender=cls, instance=self)