diff --git a/oscar_odin/mappings/context.py b/oscar_odin/mappings/context.py index f92adf3..3933d3f 100644 --- a/oscar_odin/mappings/context.py +++ b/oscar_odin/mappings/context.py @@ -274,9 +274,9 @@ 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): - for relation, product, instances in self.get_all_o2m_instances: + for relation, parent, instances in self.get_all_o2m_instances: for instance in instances: - setattr(instance, relation.field.name, product) + setattr(instance, relation.field.name, parent) instances_to_create, instances_to_update, identities = self.get_o2m_relations @@ -315,14 +315,12 @@ def bulk_update_or_create_one_to_many(self): if fields is not None: conditions = Q() identifiers = self.identifier_mapping[relation.related_model] - for key in keys: + for key in set(keys): if isinstance(key, (list, tuple)): conditions |= Q(**dict(list(zip(identifiers, key)))) else: conditions |= Q(**{f"{identifiers[0]}": key}) - field_name = relation.remote_field.attname.replace( - "_", "__" - ).replace("id", instance_identifier) + field_name = f"{relation.remote_field.name}__{instance_identifier}" # Delete all related one_to_many instances where product is in the # given list of resources and excluding any instances present in # those resources diff --git a/oscar_odin/mappings/resources.py b/oscar_odin/mappings/resources.py new file mode 100644 index 0000000..8af0216 --- /dev/null +++ b/oscar_odin/mappings/resources.py @@ -0,0 +1,44 @@ +from oscar_odin.mappings.context import ModelMapperContext +from oscar_odin.utils import validate_resources + + +def resources_to_db( + resources, + fields_to_update, + identifier_mapping, + model_mapper, + delete_related=False, + clean_instances=True, + skip_invalid_resources=False, + error_identifiers=None, +): + """Map mulitple resources to a model and store them in the database. + + The method will first bulk update or create the foreign keys + After that all the resources will be bulk saved. + At last all related models can will be saved and set on the record. + """ + error_identifiers = error_identifiers or identifier_mapping.get(model_mapper.to_obj) + valid_resources, resource_errors = validate_resources(resources, error_identifiers) + if not skip_invalid_resources and resource_errors: + return [], resource_errors + + context = ModelMapperContext( + model_mapper.to_obj, + delete_related=delete_related, + error_identifiers=error_identifiers, + ) + result = model_mapper.apply(valid_resources, context=context) + + try: + instances = list(result) + except TypeError: # it is not a list + instances = [result] + + saved_resources, errors = context.bulk_save( + instances, + fields_to_update, + identifier_mapping, + clean_instances, + ) + return saved_resources, resource_errors + errors