Skip to content

Commit 0584186

Browse files
committed
Support nonstandard pk fields. Closes #25.
1 parent bde45c8 commit 0584186

File tree

3 files changed

+127
-16
lines changed

3 files changed

+127
-16
lines changed

bulk_sync/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def get_key(obj, prep_values=False):
104104
# This is a new object, so create it.
105105
new_objs.append(new_obj)
106106
else:
107-
new_obj.id = old_obj.id
107+
new_obj.pk = old_obj.pk
108108
existing_objs.append(new_obj)
109109

110110
if not skip_creates:
@@ -167,7 +167,7 @@ def get_key(obj):
167167
# This is a new object, so create it.
168168
new_objs.append(new_obj)
169169
else:
170-
new_obj.id = old_obj.id
170+
new_obj.pk = old_obj.pk
171171

172172
cmp_result = compare_objs(old_obj, new_obj, ignore_fields)
173173
if cmp_result:

tests/models.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,14 @@ class Employee(models.Model):
1414

1515
def __str__(self):
1616
return "Employee: {} age {} company {}".format(self.name, self.age, self.company_id)
17+
18+
class EmployeeDifferentPk(models.Model):
19+
employee_id = models.AutoField(primary_key=True)
20+
21+
age = models.IntegerField()
22+
name = models.CharField(max_length=140, blank=True, null=True)
23+
24+
company = models.ForeignKey(Company, models.CASCADE)
25+
26+
def __str__(self):
27+
return "EmployeeDiffPk: {} age {} company {}".format(self.name, self.age, self.company_id)

tests/tests.py

Lines changed: 114 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from bulk_sync import bulk_compare
88
from bulk_sync import bulk_sync
9-
from .models import Company, Employee
9+
from .models import Company, Employee, EmployeeDifferentPk
1010

1111

1212
class BulkSyncTests(TestCase):
@@ -70,6 +70,61 @@ def test_all_features_at_once(self):
7070
self.assertEqual(50, new_e5.age)
7171
self.assertEqual(c1, new_e5.company)
7272

73+
def test_all_features_at_once_nonstandard_pk(self):
74+
c1 = Company.objects.create(name="Foo Products, Ltd.")
75+
c2 = Company.objects.create(name="Bar Microcontrollers, Inc.")
76+
77+
e1 = EmployeeDifferentPk.objects.create(name="Scott", age=40, company=c1)
78+
e2 = EmployeeDifferentPk.objects.create(name="Isaac", age=9, company=c1)
79+
e3 = EmployeeDifferentPk.objects.create(name="Zoe", age=9, company=c1)
80+
e4 = EmployeeDifferentPk.objects.create(name="Bob", age=25, company=c2)
81+
82+
# We should update Scott's and Isaac's age, delete Zoe, add Newguy and
83+
# add a second Bob (since he's not in company c1, which we filtered on.)
84+
new_objs = [
85+
EmployeeDifferentPk(name="Scott", age=41, company=c1),
86+
EmployeeDifferentPk(name="Isaac", age=9, company=c1),
87+
EmployeeDifferentPk(name="Newguy", age=10, company=c1),
88+
EmployeeDifferentPk(name="Bob", age=50, company=c1),
89+
]
90+
91+
ret = bulk_sync(new_models=new_objs, filters=Q(company_id=c1.id), key_fields=("name",))
92+
93+
self.assertEqual(2, ret["stats"]["updated"])
94+
self.assertEqual(2, ret["stats"]["created"])
95+
self.assertEqual(1, ret["stats"]["deleted"])
96+
97+
self.assertEqual(4, EmployeeDifferentPk.objects.filter(company=c1).count())
98+
self.assertEqual(1, EmployeeDifferentPk.objects.filter(company=c2).count())
99+
100+
new_e1 = EmployeeDifferentPk.objects.get(employee_id=e1.employee_id)
101+
self.assertEqual("Scott", new_e1.name)
102+
self.assertEqual(41, new_e1.age)
103+
self.assertEqual(c1, new_e1.company)
104+
105+
new_e2 = EmployeeDifferentPk.objects.get(employee_id=e2.employee_id)
106+
self.assertEqual("Isaac", new_e2.name)
107+
self.assertEqual(9, new_e2.age)
108+
self.assertEqual(c1, new_e2.company)
109+
110+
with self.assertRaises(EmployeeDifferentPk.DoesNotExist):
111+
EmployeeDifferentPk.objects.get(employee_id=e3.employee_id)
112+
113+
new_e4 = EmployeeDifferentPk.objects.get(employee_id=e4.employee_id)
114+
self.assertEqual("Bob", new_e4.name)
115+
self.assertEqual(25, new_e4.age)
116+
self.assertEqual(c2, new_e4.company)
117+
118+
new_e3 = EmployeeDifferentPk.objects.get(name="Newguy")
119+
self.assertEqual("Newguy", new_e3.name)
120+
self.assertEqual(10, new_e3.age)
121+
self.assertEqual(c1, new_e3.company)
122+
123+
new_e5 = EmployeeDifferentPk.objects.get(name="Bob", company=c1)
124+
self.assertEqual("Bob", new_e5.name)
125+
self.assertEqual(50, new_e5.age)
126+
self.assertEqual(c1, new_e5.company)
127+
73128
def test_provided_pk_is_retained_but_raises_if_mismatch_with_keyfield(self):
74129
c1 = Company.objects.create(name="Foo Products, Ltd.")
75130
e1 = Employee.objects.create(name="Scott", age=40, company=c1)
@@ -245,26 +300,47 @@ def test_new_objs_with_unprepped_field_values_are_processed_correctly(self):
245300
class BulkCompareTests(TestCase):
246301
""" Test `bulk_compare` method """
247302

248-
@classmethod
249-
def setUpTestData(cls):
250-
cls.c1 = Company.objects.create(name="Foo Products, Ltd.")
251-
cls.c2 = Company.objects.create(name="Bar Microcontrollers, Inc.")
303+
# @classmethod
304+
# def setUpTestData(cls):
305+
def setupEmployees(self):
306+
self.c1 = Company.objects.create(name="Foo Products, Ltd.")
307+
self.c2 = Company.objects.create(name="Bar Microcontrollers, Inc.")
308+
309+
self.e1 = Employee.objects.create(name="Scott", age=40, company=self.c1)
310+
self.e2 = Employee.objects.create(name="Isaac", age=9, company=self.c1)
311+
self.e3 = Employee.objects.create(name="Zoe", age=9, company=self.c1)
312+
self.e4 = Employee.objects.create(name="Bob", age=25, company=self.c2)
313+
314+
# We should update Scott's and Isaac's age, delete Zoe, add Newguy and
315+
# add a second Bob (since he's not in company c1, which we filtered on.)
316+
self.new_objs = [
317+
Employee(name="Scott", age=41, company=self.c1),
318+
Employee(name="Isaac", age=9, company=self.c1),
319+
Employee(name="Newguy", age=10, company=self.c1),
320+
Employee(name="Bob", age=50, company=self.c1),
321+
]
322+
323+
def setupEmployeeDiffPk(self):
324+
self.c1 = Company.objects.create(name="Foo Products, Ltd.")
325+
self.c2 = Company.objects.create(name="Bar Microcontrollers, Inc.")
252326

253-
cls.e1 = Employee.objects.create(name="Scott", age=40, company=cls.c1)
254-
cls.e2 = Employee.objects.create(name="Isaac", age=9, company=cls.c1)
255-
cls.e3 = Employee.objects.create(name="Zoe", age=9, company=cls.c1)
256-
cls.e4 = Employee.objects.create(name="Bob", age=25, company=cls.c2)
327+
self.e1 = EmployeeDifferentPk.objects.create(name="Scott", age=40, company=self.c1)
328+
self.e2 = EmployeeDifferentPk.objects.create(name="Isaac", age=9, company=self.c1)
329+
self.e3 = EmployeeDifferentPk.objects.create(name="Zoe", age=9, company=self.c1)
330+
self.e4 = EmployeeDifferentPk.objects.create(name="Bob", age=25, company=self.c2)
257331

258332
# We should update Scott's and Isaac's age, delete Zoe, add Newguy and
259333
# add a second Bob (since he's not in company c1, which we filtered on.)
260-
cls.new_objs = [
261-
Employee(name="Scott", age=41, company=cls.c1),
262-
Employee(name="Isaac", age=9, company=cls.c1),
263-
Employee(name="Newguy", age=10, company=cls.c1),
264-
Employee(name="Bob", age=50, company=cls.c1),
334+
self.new_objs = [
335+
EmployeeDifferentPk(name="Scott", age=41, company=self.c1),
336+
EmployeeDifferentPk(name="Isaac", age=9, company=self.c1),
337+
EmployeeDifferentPk(name="Newguy", age=10, company=self.c1),
338+
EmployeeDifferentPk(name="Bob", age=50, company=self.c1),
265339
]
266340

267341
def test_bulk_compare(self):
342+
self.setupEmployees()
343+
268344
c1 = self.c1
269345
e3 = self.e3
270346
new_objs = self.new_objs
@@ -278,6 +354,8 @@ def test_bulk_compare(self):
278354
self.assertEqual([new_objs[1]], ret["unchanged"])
279355

280356
def test_bulk_compare_with_ignore_int_field(self):
357+
self.setupEmployees()
358+
281359
c1 = self.c1
282360
e3 = self.e3
283361
new_objs = self.new_objs
@@ -296,6 +374,8 @@ def test_bulk_compare_with_ignore_int_field(self):
296374
self.assertEqual([new_objs[0], new_objs[1]], ret["unchanged"])
297375

298376
def test_bulk_compare_with_ignore_relation_field(self):
377+
self.setupEmployees()
378+
299379
c1 = self.c1
300380
e3 = self.e3
301381
new_objs = self.new_objs
@@ -312,3 +392,23 @@ def test_bulk_compare_with_ignore_relation_field(self):
312392
self.assertEqual([new_objs[0]], ret["updated"])
313393
self.assertEqual({new_objs[0]: {"age": (40, 41)}}, ret["updated_details"])
314394
self.assertEqual([new_objs[1]], ret["unchanged"])
395+
396+
def test_nonstandard_pk(self):
397+
self.setupEmployeeDiffPk()
398+
399+
c1 = self.c1
400+
e3 = self.e3
401+
new_objs = self.new_objs
402+
403+
ret = bulk_compare(
404+
old_models=EmployeeDifferentPk.objects.filter(company=c1).order_by("name"),
405+
new_models=new_objs,
406+
key_fields=("name",),
407+
ignore_fields=("company_id",),
408+
)
409+
410+
self.assertEqual([new_objs[2], new_objs[3]], ret["added"])
411+
self.assertEqual([e3], list(ret["removed"]))
412+
self.assertEqual([new_objs[0]], ret["updated"])
413+
self.assertEqual({new_objs[0]: {"age": (40, 41)}}, ret["updated_details"])
414+
self.assertEqual([new_objs[1]], ret["unchanged"])

0 commit comments

Comments
 (0)