def _fork_field(reference, instance, accessor, **kwargs): """Creates a copy of the reference value for the defined ``accessor`` (field). For deep forks, each related object is related objects must be created first prior to being recursed. """ value, field, direct, m2m = utils._get_field_value(reference, accessor) if value is None: return # recursive calls cannot be saved until everything has been traversed.. kwargs['commit'] = False if isinstance(field, models.OneToOneField): return _fork_one2one(instance, value, field, direct, accessor, **kwargs) if isinstance(field, models.ForeignKey): return _fork_foreignkey(instance, value, field, direct, accessor, **kwargs) if isinstance(field, models.ManyToManyField): return _fork_many2many(instance, value, field, direct, accessor, **kwargs) # non-relational field, perform a deepcopy to ensure no mutable nonsense setattr(instance, accessor, deepcopy(value))
def _reset_foreignkey(instance, refvalue, field, direct, accessor, deep, **kwargs): value = utils._get_field_value(instance, accessor)[0] if refvalue and value and deep: _memoize_reset(refvalue, value, deep=deep, **kwargs) # for shallow or when value is None, use the reference value elif not value: value = refvalue instance._commits.defer(accessor, value, direct=direct)
def _diff_field(reference, instance, accessor, deep, **kwargs): "Returns the field's value of ``instance`` if different form ``reference``." val1, field, direct, m2m = utils._get_field_value(reference, accessor) val2 = utils._get_field_value(instance, accessor)[0] # get the diff for m2m or reverse foreign keys if m2m or not direct and not isinstance(field, models.OneToOneField): if _diff_queryset(reference, val1, val2) is not None: return {accessor: list(val2)} # direct foreign keys and one-to-one elif deep and (isinstance(field, models.ForeignKey) or isinstance(field, models.OneToOneField)): if val1 and val2: diff = diff_model_object(val1, val2, **kwargs) if diff: return {accessor: diff} elif val1 != val2: return {accessor: val2} return {}
def test_deep_signal(self): # before signal is connected.. complete deep fork fork = self.author.fork(commit=False, deep=True) post0 = utils._get_field_value(fork, 'posts')[0][0] self.assertEqual(post0.title, 'Django Tip: Descriptors') blog0 = utils._get_field_value(post0, 'blog')[0] self.assertTrue(isinstance(blog0, Blog)) # connect the post signal to limit the fields.. signals.pre_fork.connect(post_config, sender=Post) fork = self.author.fork(commit=False, deep=True) post0 = utils._get_field_value(fork, 'posts')[0][0] self.assertEqual(post0.title, 'Django Tip: Descriptors') blog0 = utils._get_field_value(post0, 'blog')[0] # odd usage of _get_field_value, but it works.. self.assertEqual(blog0, None) signals.pre_fork.disconnect(post_config, sender=Post)
def test_deep_signal(self): # before signal is connected.. complete deep fork fork = self.author.fork(commit=False, deep=True) post0 = utils._get_field_value(fork, 'posts')[0][0] self.assertEqual(post0.title, 'Django Tip: Descriptors') blog0 = utils._get_field_value(post0, 'blog')[0] self.assertTrue(isinstance(blog0, Blog)) # connect the post signal to limit the fields.. signals.pre_fork.connect(post_config, sender=Post) fork = self.author.fork(commit=False, deep=True) post0 = utils._get_field_value(fork, 'posts')[0][0] self.assertEqual(post0.title, 'Django Tip: Descriptors') blog0 = utils._get_field_value(post0, 'blog')[0] # odd usage of _get_field_value, but it works.. self.assertEqual(blog0, None) signals.pre_fork.disconnect(post_config)
def test_field_value(self): self.assertEqual(utils._get_field_value(self.author, 'first_name')[0], 'Byron') # returns a queryset, compare the querysets author_posts = utils._get_field_value(self.author, 'posts')[0] self.assertEqual(diff._diff_queryset(self.author, author_posts, Post.objects.all()), None) # one-to-ones are simple, the instance if returned directly self.assertEqual(utils._get_field_value(self.author, 'blog')[0], self.blog) # direct foreign key, same as one-to-one self.assertEqual(utils._get_field_value(self.post, 'blog')[0], self.blog) # direct many-to-many, behaves the same as reverse foreign keys post_authors = utils._get_field_value(self.post, 'authors')[0] self.assertEqual(diff._diff_queryset(self.post, post_authors, Author.objects.all()), None) # direct many-to-many, behaves the same as reverse foreign keys post_tags = utils._get_field_value(self.post, 'tags')[0] self.assertEqual(diff._diff_queryset(self.post, post_tags, Tag.objects.all()), None) self.assertEqual(utils._get_field_value(self.blog, 'author')[0], self.author) blog_posts = utils._get_field_value(self.blog, 'post_set')[0] self.assertEqual(diff._diff_queryset(self.blog, blog_posts, Post.objects.all()), None) tag_posts = utils._get_field_value(self.tag, 'post_set')[0] self.assertEqual(diff._diff_queryset(self.blog, tag_posts, Post.objects.all()), None)
def test_field_value(self): self.assertEqual( utils._get_field_value(self.author, 'first_name')[0], 'Byron') # returns a queryset, compare the querysets author_posts = utils._get_field_value(self.author, 'posts')[0] self.assertEqual( diff._diff_queryset(self.author, author_posts, Post.objects.all()), None) # one-to-ones are simple, the instance if returned directly self.assertEqual( utils._get_field_value(self.author, 'blog')[0], self.blog) # direct foreign key, same as one-to-one self.assertEqual( utils._get_field_value(self.post, 'blog')[0], self.blog) # direct many-to-many, behaves the same as reverse foreign keys post_authors = utils._get_field_value(self.post, 'authors')[0] self.assertEqual( diff._diff_queryset(self.post, post_authors, Author.objects.all()), None) # direct many-to-many, behaves the same as reverse foreign keys post_tags = utils._get_field_value(self.post, 'tags')[0] self.assertEqual( diff._diff_queryset(self.post, post_tags, Tag.objects.all()), None) self.assertEqual( utils._get_field_value(self.blog, 'author')[0], self.author) blog_posts = utils._get_field_value(self.blog, 'post_set')[0] self.assertEqual( diff._diff_queryset(self.blog, blog_posts, Post.objects.all()), None) tag_posts = utils._get_field_value(self.tag, 'post_set')[0] self.assertEqual( diff._diff_queryset(self.blog, tag_posts, Post.objects.all()), None)
def _reset_field(reference, instance, accessor, **kwargs): """Creates a copy of the reference value for the defined ``accessor`` (field). For deep forks, each related object is related objects must be created first prior to being recursed. """ value, field, direct, m2m = utils._get_field_value(reference, accessor) # explicitly block reverse and m2m relationships.. if not direct or m2m: return kwargs['commit'] = False if isinstance(field, models.OneToOneField): return _reset_one2one(instance, value, field, direct, accessor, **kwargs) if isinstance(field, models.ForeignKey): return _reset_foreignkey(instance, value, field, direct, accessor, **kwargs) # non-relational field, perform a deepcopy to ensure no mutable nonsense setattr(instance, accessor, deepcopy(value))
def _reset_one2one(instance, refvalue, field, direct, accessor, deep, **kwargs): value = utils._get_field_value(instance, accessor)[0] if refvalue and value and deep: _memoize_reset(refvalue, value, deep=deep, **kwargs) instance._commits.defer(accessor, value, direct=direct)