def _memoize_reset(reference, instance, **kwargs): "Resets the specified instance relative to ``reference``" # popped so it does not get included in the config for the signal memo = kwargs.pop('memo', None) # for every call, keep track of the reference and the object (fork). # this is used for recursive calls to related objects. this ensures # relationships that follow back up the tree are caught and are merely # referenced rather than traversed again. if memo is None: memo = utils.Memo() elif memo.has(reference): return memo.get(reference) if not isinstance(instance, reference.__class__): raise TypeError('The instance supplied must be of the same type as the reference') instance._commits = utils.Commits(reference) memo.add(reference, instance) # default configuration config = { 'fields': None, 'exclude': ['pk'], 'deep': False, 'commit': True, } # update with user-defined config.update(kwargs) # pre-signal signals.pre_reset.send(sender=reference.__class__, reference=reference, instance=instance, config=config, **kwargs) fields = config['fields'] exclude = config['exclude'] deep = config['deep'] commit = config['commit'] # no fields are defined, so get the default ones for shallow or deep if not fields: fields = utils._default_model_fields(reference, exclude=exclude, deep=deep) kwargs.update({'deep': deep}) # iterate over each field and fork it!. nested calls will not commit, # until the recursion has finished for accessor in fields: _reset_field(reference, instance, accessor, **kwargs) # post-signal signals.post_reset.send(sender=reference.__class__, reference=reference, instance=instance, **kwargs) if commit: commit_model_object(instance) return instance
def test_deep_default_fields(self): author = Author() post = Post() blog = Blog() tag = Tag() self.assertEqual(utils._default_model_fields(author, deep=True), set(['first_name', 'last_name', 'posts', 'blog'])) self.assertEqual(utils._default_model_fields(post, deep=True), set(['blog', 'authors', 'tags', 'title'])) self.assertEqual(utils._default_model_fields(blog, deep=True), set(['name', 'author', 'post_set'])) self.assertEqual(utils._default_model_fields(tag, deep=True), set(['name', 'post_set']))
def test_shallow_default_fields(self): author = Author() post = Post() blog = Blog() tag = Tag() self.assertEqual(utils._default_model_fields(author), set(['first_name', 'last_name', 'posts'])) self.assertEqual(utils._default_model_fields(post), set(['blog', 'authors', 'tags', 'title'])) self.assertEqual(utils._default_model_fields(blog), set(['name', 'author'])) self.assertEqual(utils._default_model_fields(tag), set(['name', 'post_set']))
def _diff(reference, instance, fields=None, exclude=('pk',), deep=False, **kwargs): if not fields: fields = utils._default_model_fields(reference, exclude, deep=deep) diff = {} for accessor in fields: diff.update(_diff_field(reference, instance, accessor, deep=deep, **kwargs)) return diff
def _diff(reference, instance, fields=None, exclude=('pk', ), deep=False, **kwargs): if not fields: fields = utils._default_model_fields(reference, exclude, deep=deep) diff = {} for accessor in fields: diff.update( _diff_field(reference, instance, accessor, deep=deep, **kwargs)) return diff
def _memoize_fork(reference, **kwargs): "Resets the specified instance relative to ``reference``" # popped so it does not get included in the config for the signal memo = kwargs.pop('memo', None) # for every call, keep track of the reference and the instance being # acted on. this is used for recursive calls to related objects. this # ensures relationships that follow back up the tree are caught and are # merely referenced rather than traversed again. if memo is None: memo = utils.Memo() elif memo.has(reference): return memo.get(reference) # initialize and memoize new instance instance = reference.__class__() instance._commits = utils.Commits(reference) memo.add(reference, instance) # default configuration config = { 'fields': None, 'exclude': ['pk'], 'deep': False, 'commit': True, } # pop off and set any config params for signals for key in config.iterkeys(): if kwargs.has_key(key): config[key] = kwargs.pop(key) # pre-signal signals.pre_fork.send(sender=reference.__class__, reference=reference, instance=instance, config=config, **kwargs) fields = config['fields'] exclude = config['exclude'] deep = config['deep'] commit = config['commit'] # no fields are defined, so get the default ones for shallow or deep if not fields: fields = utils._default_model_fields(reference, exclude=exclude, deep=deep) # add arguments for downstream use kwargs.update({'deep': deep}) # iterate over each field and fork it!. nested calls will not commit, # until the recursion has finished for accessor in fields: _fork_field(reference, instance, accessor, memo=memo, **kwargs) # post-signal signals.post_fork.send(sender=reference.__class__, reference=reference, instance=instance, **kwargs) # as of now, this will only every be from a top-level call if commit: commit_model_object(instance, **kwargs) return instance