1
1
from collections import OrderedDict
2
2
import logging
3
3
from django .db import transaction
4
+ from django .core .exceptions import FieldDoesNotExist
4
5
5
6
logger = logging .getLogger (__name__ )
6
7
7
8
8
- def bulk_sync (new_models , key_fields , filters , batch_size = None , fields = None , skip_creates = False , skip_updates = False , skip_deletes = False ):
9
+ def bulk_sync (
10
+ new_models , key_fields , filters ,
11
+ batch_size = None , fields = None , exclude_fields = None ,
12
+ skip_creates = False , skip_updates = False , skip_deletes = False
13
+ ):
9
14
""" Combine bulk create, update, and delete. Make the DB match a set of in-memory objects.
10
15
11
16
`new_models`: Django ORM objects that are the desired state. They may or may not have `id` set.
@@ -14,7 +19,9 @@ def bulk_sync(new_models, key_fields, filters, batch_size=None, fields=None, ski
14
19
`filters`: Q() filters specifying the subset of the database to work in. Use `None` or `[]` if you want to sync against the entire table.
15
20
`batch_size`: passes through to Django `bulk_create.batch_size` and `bulk_update.batch_size`, and controls
16
21
how many objects are created/updated per SQL query.
17
- `fields`: (optional) list of fields to update. If not set, will sync all fields that are editable and not auto-created.
22
+ `fields`: (optional) list of fields to update. If not set, will sync all fields that are editable and not
23
+ auto-created.
24
+ `exclude_fields`: (optional) list of fields to exclude from updates.
18
25
`skip_creates`: If truthy, will not perform any object creations needed to fully sync. Defaults to not skip.
19
26
`skip_updates`: If truthy, will not perform any object updates needed to fully sync. Defaults to not skip.
20
27
`skip_deletes`: If truthy, will not perform any object deletions needed to fully sync. Defaults to not skip.
@@ -27,6 +34,19 @@ def bulk_sync(new_models, key_fields, filters, batch_size=None, fields=None, ski
27
34
for field in db_class ._meta .fields
28
35
if not field .primary_key and not field .auto_created and field .editable ]
29
36
37
+ if exclude_fields is not None :
38
+ model_fields = set (field .name for field in db_class ._meta .fields )
39
+ fields_to_update = set (fields )
40
+ fields_to_exclude = set (exclude_fields )
41
+
42
+ # Check that we're not attempting to exclude non-existant fields
43
+ if not fields_to_exclude <= model_fields :
44
+ raise FieldDoesNotExist (
45
+ f'model "{ db_class .__name__ } " has no field(s) { fields_to_exclude - model_fields } '
46
+ )
47
+
48
+ fields = list (fields_to_update - fields_to_exclude )
49
+
30
50
with transaction .atomic ():
31
51
objs = db_class .objects .all ()
32
52
if filters :
0 commit comments