error on 1:1 clash

This commit is contained in:
James Turk 2015-05-28 16:28:21 -04:00
parent 8d4bab0563
commit 750061ebd6
2 changed files with 28 additions and 7 deletions

View File

@ -1,5 +1,20 @@
from django.core.exceptions import ObjectDoesNotExist
def merge(from_obj, to_obj):
class MergeException(Exception):
pass
class OneToOneConflict(MergeException):
pass
ERROR = 0
KEEP = 1
UPDATE = 2
def merge(from_obj, to_obj, one_to_one_conflict=ERROR):
if not isinstance(from_obj, type(to_obj)): if not isinstance(from_obj, type(to_obj)):
raise ValueError("both objects must be of the same type") raise ValueError("both objects must be of the same type")
@ -17,17 +32,17 @@ def merge(from_obj, to_obj):
try: try:
field = getattr(from_obj, accessor_name) field = getattr(from_obj, accessor_name)
try: try:
getattr(to_obj, accessor_name) to_obj_field = getattr(to_obj, accessor_name)
except Exception as e: raise OneToOneConflict("both fields have an attribute set for {}".format(accessor_name))
except ObjectDoesNotExist:
# doesn't exist, safe to overwrite # doesn't exist, safe to overwrite
setattr(field, varname, to_obj) setattr(field, varname, to_obj)
field.save() field.save()
except Exception as e: except ObjectDoesNotExist:
# from_obj one to one isn't set, skip # from_obj one to one isn't set, skip
pass pass
else: else:
import pdb; pdb.set_trace() raise NotImplementedError('unexpected relation type, please file a bug')
raise Exception('unknown code path')
for related in from_obj._meta.get_all_related_many_to_many_objects(): for related in from_obj._meta.get_all_related_many_to_many_objects():
accessor_name = related.get_accessor_name() accessor_name = related.get_accessor_name()

View File

@ -1,6 +1,6 @@
from django.test import TestCase from django.test import TestCase
from .models import Person, Number, SSN, Group from .models import Person, Number, SSN, Group
from fkreplace import merge from fkreplace import merge, OneToOneConflict
class MergeTests(TestCase): class MergeTests(TestCase):
def setUp(self): def setUp(self):
@ -44,6 +44,12 @@ class MergeTests(TestCase):
assert SSN.objects.count() == 1 assert SSN.objects.count() == 1
# TODO: test one2one when there's a conflict # TODO: test one2one when there's a conflict
def test_one2one_conflict(self):
SSN.objects.create(person=self.a, number='1')
SSN.objects.create(person=self.b, number='1')
with self.assertRaises(OneToOneConflict):
merge(self.a, self.b)
def test_many2many_simple(self): def test_many2many_simple(self):
self.g.people.add(self.a) self.g.people.add(self.a)