Skip to content

Commit 189c1be

Browse files
committed
Require an explicit delete_missing spec key to delete anything
1 parent 4e09769 commit 189c1be

File tree

4 files changed

+37
-15
lines changed

4 files changed

+37
-15
lines changed

README.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,15 @@ Model specs consist of the following fields:
109109
objects to remove after loading.
110110
- ``"force_insert"``: If present and truish, objects are inserted using new
111111
primary keys into the database instead of (potentially) overwriting
112-
pre-existing objects. This flag also makes the loader **not** delete objects
113-
it doesn't know about.
112+
pre-existing objects.
113+
- ``"delete_missing"``: This flag makes the loader delete all objects matching
114+
``"filter"`` which do not exist in the dump.
114115

115116
The dumps can be loaded back into the database by running::
116117

117118
./manage.py f3loaddata -v2 tmp/dump.json tmp/districts.json
118119

119120
Each dump is processed in an individual transaction. The data is first loaded
120121
into the database; at the end, data *matching* the filters but whose primary
121-
key wasn't contained in the dump is deleted from the database.
122+
key wasn't contained in the dump is deleted from the database (if
123+
``"delete_missing": True``).

feincms3_data/data.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class InvalidSpec(Exception):
3030
pass
3131

3232

33-
_valid_keys = {"model", "filter", "force_insert"}
33+
_valid_keys = {"model", "filter", "force_insert", "delete_missing"}
3434

3535

3636
def _validate_spec(spec):
@@ -114,7 +114,7 @@ def load_dump(data, *, progress=silence, ignorenonexistent=False):
114114
progress(f"Saved {len(objs)} {spec['model']} objects")
115115

116116
for spec in data["specs"]:
117-
if spec.get("force_insert"):
117+
if not spec.get("delete_missing"):
118118
continue
119119

120120
queryset = _model_queryset(spec)

tests/testapp/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
class Parent(models.Model):
55
name = models.CharField(default="name", max_length=20)
66

7+
class Meta:
8+
ordering = ["id"]
9+
710

811
class Child(models.Model):
912
name = models.CharField(default="name", max_length=20)
1013

1114
class Meta:
1215
abstract = True
16+
ordering = ["id"]
1317

1418

1519
class Child1(Child):

tests/testapp/test_data.py

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
def parent_child1_set():
2020
return [
2121
(p.name, [c.name for c in p.child1_set.all()])
22-
for p in Parent.objects.order_by("id").prefetch_related("child1_set")
22+
for p in Parent.objects.prefetch_related("child1_set")
2323
]
2424

2525

@@ -53,14 +53,14 @@ def test_specs_for_derived_models(self):
5353
self.assertNotIn({"model": "testapp.child"}, specs)
5454

5555
def test_specs_for_app_models(self):
56-
specs = list(specs_for_app_models("testapp"))
56+
specs = list(specs_for_app_models("testapp", {"delete_missing": True}))
5757

5858
self.assertCountEqual(
5959
specs,
6060
[
61-
{"model": "testapp.parent"},
62-
{"model": "testapp.child1"},
63-
{"model": "testapp.child2"},
61+
{"model": "testapp.parent", "delete_missing": True},
62+
{"model": "testapp.child1", "delete_missing": True},
63+
{"model": "testapp.child2", "delete_missing": True},
6464
],
6565
)
6666

@@ -126,7 +126,7 @@ def test_force_insert_simple(self):
126126

127127
def test_force_insert_partial_graph(self):
128128
p1 = Parent.objects.create(name="blub-1")
129-
p1.child1_set.create(name="blub-1-1")
129+
c1 = p1.child1_set.create(name="blub-1-1")
130130

131131
p2 = Parent.objects.create(name="blub-2")
132132
p2.child1_set.create(name="blub-2-1")
@@ -143,7 +143,11 @@ def test_force_insert_partial_graph(self):
143143
),
144144
*specs_for_derived_models(
145145
Child,
146-
{"filter": {"parent__in": [p1.pk]}, "force_insert": True},
146+
{
147+
"filter": {"parent__in": [p1.pk]},
148+
"force_insert": True,
149+
"delete_missing": True,
150+
},
147151
),
148152
]
149153

@@ -152,9 +156,12 @@ def test_force_insert_partial_graph(self):
152156

153157
self.assertEqual(
154158
parent_child1_set(),
155-
[("blub-1", ["blub-1-1", "blub-1-1"]), ("blub-2", ["blub-2-1"])],
159+
[("blub-1", ["blub-1-1"]), ("blub-2", ["blub-2-1"])],
156160
)
157161

162+
c1_new = p1.child1_set.get()
163+
self.assertNotEqual(c1.pk, c1_new.pk)
164+
158165
def test_force_insert_full_graph(self):
159166
Parent.objects.create(name="other")
160167

@@ -169,15 +176,24 @@ def test_force_insert_full_graph(self):
169176
specs = [
170177
*specs_for_models(
171178
[Parent],
172-
{"filter": {"pk__in": [p1.pk]}, "force_insert": True},
179+
{
180+
"filter": {"pk__in": [p1.pk]},
181+
"force_insert": True,
182+
"delete_missing": False, # Do not remove old items
183+
},
173184
),
174185
*specs_for_derived_models(
175186
Child,
176-
{"filter": {"parent__in": [p1.pk]}, "force_insert": True},
187+
{
188+
"filter": {"parent__in": [p1.pk]},
189+
"force_insert": True,
190+
"delete_missing": False, # Do not remove old items
191+
},
177192
),
178193
]
179194

180195
dump = json.loads(dump_specs(specs))
196+
# from pprint import pprint; print(); pprint(dump)
181197
load_dump(dump)
182198

183199
self.assertEqual(

0 commit comments

Comments
 (0)