Skip to content

Commit

Permalink
refactor 📦 improve deleting related models
Browse files Browse the repository at this point in the history
  • Loading branch information
samar-hassan committed Feb 8, 2024
1 parent b225ba8 commit 3b118dd
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 40 deletions.
8 changes: 1 addition & 7 deletions oscar_odin/mappings/catalogue.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,14 +393,9 @@ def product_queryset_to_resources(
def products_to_model(
products: List[resources.catalogue.Product],
product_mapper=ProductToModel,
identifier_mapping=MODEL_IDENTIFIERS_MAPPING,
delete_related=False,
) -> Tuple[List[ProductModel], Dict]:
context = ProductModelMapperContext(
ProductModel,
identifier_mapping=identifier_mapping,
delete_related=delete_related,
)
context = ProductModelMapperContext(ProductModel, delete_related=delete_related)

result = product_mapper.apply(products, context=context)

Expand All @@ -426,7 +421,6 @@ def products_to_db(
instances, context = products_to_model(
products,
product_mapper=product_mapper,
identifier_mapping=identifier_mapping,
delete_related=delete_related,
)

Expand Down
50 changes: 17 additions & 33 deletions oscar_odin/mappings/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
def separate_instances_to_create_and_update(Model, instances, identifier_mapping):
instances_to_create = []
instances_to_update = []
identifiying_keys = []

identifiers = identifier_mapping.get(Model, {})

Expand All @@ -29,6 +30,7 @@ def separate_instances_to_create_and_update(Model, instances, identifier_mapping
get_key_values = attrgetter(*identifiers)
for instance in instances:
key = get_key_values(instance)
identifiying_keys.append(key)

if not isinstance(key, tuple):
key = (key,)
Expand All @@ -42,9 +44,9 @@ def separate_instances_to_create_and_update(Model, instances, identifier_mapping
else:
instances_to_create.append(instance)

return instances_to_create, instances_to_update
return instances_to_create, instances_to_update, identifiying_keys
else:
return instances, []
return instances, [], []


class ModelMapperContext(dict):
Expand All @@ -57,14 +59,7 @@ class ModelMapperContext(dict):
Model = None
errors = None

def __init__(
self,
Model,
*args,
identifier_mapping=MODEL_IDENTIFIERS_MAPPING,
delete_related=False,
**kwargs
):
def __init__(self, Model, *args, delete_related=False, **kwargs):
super().__init__(*args, **kwargs)
self.foreign_key_items = defaultdict(list)
self.many_to_many_items = defaultdict(list)
Expand All @@ -74,7 +69,6 @@ def __init__(
self.identifier_mapping = defaultdict(tuple)
self.attribute_data = []
self.errors = []
self.identifier_mapping = identifier_mapping
self.delete_related = delete_related
self.Model = Model

Expand Down Expand Up @@ -121,6 +115,7 @@ def get_fields_to_update(self, Model):
def get_create_and_update_relations(self, related_instance_items):
to_create = defaultdict(list)
to_update = defaultdict(list)
identities = defaultdict(list)

for relation in related_instance_items.keys():
all_instances = []
Expand All @@ -130,14 +125,16 @@ def get_create_and_update_relations(self, related_instance_items):
(
instances_to_create,
instances_to_update,
identifying_keys,
) = separate_instances_to_create_and_update(
relation.related_model, all_instances, self.identifier_mapping
)

to_create[relation].extend(instances_to_create)
to_update[relation].extend(instances_to_update)
identities[relation].extend(identifying_keys)

return (to_create, to_update)
return (to_create, to_update, identities)

@property
def get_all_m2m_relations(self):
Expand All @@ -156,6 +153,7 @@ def get_fk_relations(self):
(
instances_to_create,
instances_to_update,
_
) = separate_instances_to_create_and_update(
relation.related_model, instances, self.identifier_mapping
)
Expand Down Expand Up @@ -189,6 +187,7 @@ def bulk_update_or_create_instances(self, instances):
(
instances_to_create,
instances_to_update,
_
) = separate_instances_to_create_and_update(
self.Model, instances, self.identifier_mapping
)
Expand All @@ -214,50 +213,35 @@ def bulk_update_or_create_instances(self, instances):
self.Model.objects.bulk_update(validated_instances_to_update, fields=fields)

def bulk_update_or_create_one_to_many(self):
instance_identifiers = dict()
for relation, product, instances in self.get_all_o2m_instances:
for instance in instances:
setattr(instance, relation.field.name, product)

instances_to_create, instances_to_update = self.get_o2m_relations
instances_to_create, instances_to_update, identities = self.get_o2m_relations

for relation, instances in instances_to_create.items():
validated_instances_to_create = self.validate_instances(instances)
instance_identifiers[relation] = dict()
for identifier in self.identifier_mapping[relation.related_model]:
instance_identifiers[relation][identifier] = [
getattr(instance, identifier)
for instance in validated_instances_to_create
]
relation.related_model.objects.bulk_create(validated_instances_to_create)

for relation, instances in instances_to_update.items():
fields = self.get_fields_to_update(relation.related_model)
if fields is not None:
relation.related_model.objects.bulk_update(instances, fields=fields)
validated_instances_to_update = self.validate_instances(instances)
for identifier in self.identifier_mapping[relation.related_model]:
instance_identifiers[relation][identifier].extend(
getattr(instance, identifier)
for instance in validated_instances_to_update
)
relation.related_model.objects.bulk_update(
validated_instances_to_update, fields=fields
)

if self.delete_related:
for relation, identifier_values in instance_identifiers.items():
for relation, keys in identities.items():
conditions = Q()
keys = list(identifier_values.keys())
for i in range(len(identifier_values[keys[0]])):
filter_condition = {}
for key in keys:
filter_condition[key] = identifier_values[key][i]
conditions |= Q(**filter_condition)
identifiers = self.identifier_mapping[relation.related_model]
for key in keys:
conditions |= Q(**dict(list(zip(identifiers, key))))
relation.related_model.objects.exclude(conditions).delete()

def bulk_update_or_create_many_to_many(self):
m2m_to_create, m2m_to_update = self.get_all_m2m_relations
m2m_to_create, m2m_to_update, _ = self.get_all_m2m_relations

# Create many to many's
for relation, instances in m2m_to_create.items():
Expand Down

0 comments on commit 3b118dd

Please sign in to comment.