Skip to content

Commit

Permalink
Merge pull request #142 from ambitioninc/develop
Browse files Browse the repository at this point in the history
3.1.5
  • Loading branch information
jaredlewis authored Aug 7, 2024
2 parents 7eb9846 + bba62e0 commit 5379163
Show file tree
Hide file tree
Showing 3 changed files with 6 additions and 40 deletions.
4 changes: 4 additions & 0 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Release Notes
=============

v3.1.5
------
* Do not sort records when doing an upsert

v3.1.4
------
* revert psycopg3 code
Expand Down
40 changes: 1 addition & 39 deletions manager_utils/manager_utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import itertools
from typing import List

from django.db import connection, connections, models
from django.db import connection
from django.db.models import Manager, Model
from django.db.models.query import QuerySet
from django.dispatch import Signal
Expand Down Expand Up @@ -86,40 +86,6 @@ def _fetch_models_by_pk(queryset: QuerySet, models: List[Model]) -> List[Model]:
)


def _get_field_db_val(queryset, field, value, connection):
if hasattr(value, "resolve_expression"): # pragma: no cover
# Handle cases when the field is of type "Func" and other expressions.
# This is useful for libraries like django-rdkit that can't easily be tested
return value.resolve_expression(queryset.query, allow_joins=False, for_save=True)
else:
return field.get_db_prep_save(value, connection)


def _model_fields(model: models.Model) -> List[models.Field]:
"""Return the fields of a model, excluding generated and non-concrete ones."""
return [f for f in model._meta.fields if not getattr(f, "generated", False) and f.concrete]


def _sort_by_unique_fields(queryset, model_objs, unique_fields):
"""
Sort a list of models by their unique fields.
Sorting models in an upsert greatly reduces the chances of deadlock
when doing concurrent upserts
"""
model = queryset.model
connection = connections[queryset.db]
unique_fields = [field for field in _model_fields(model) if field.attname in unique_fields]

def sort_key(model_obj):
return tuple(
_get_field_db_val(queryset, field, getattr(model_obj, field.attname), connection)
for field in unique_fields
)

return sorted(model_objs, key=sort_key)


def bulk_upsert(
queryset, model_objs, unique_fields, update_fields=None, return_upserts=False, return_upserts_distinct=False,
sync=False, native=False
Expand Down Expand Up @@ -224,9 +190,6 @@ def bulk_upsert(
raise ValueError('Must provide unique_fields argument')
update_fields = update_fields or []

# Sore the models to prevent deadlocks
model_objs = _sort_by_unique_fields(queryset, model_objs, unique_fields)

if native:
if return_upserts_distinct:
raise NotImplementedError('return upserts distinct not supported with native postgres upsert')
Expand All @@ -238,7 +201,6 @@ def bulk_upsert(
queryset.filter(pk__in=orig_ids - frozenset([m.pk for m in return_value])).delete()

post_bulk_operation.send(sender=queryset.model, model=queryset.model)

return return_value

# Create a look up table for all of the objects in the queryset keyed on the unique_fields
Expand Down
2 changes: 1 addition & 1 deletion manager_utils/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '3.1.4'
__version__ = '3.1.5'

0 comments on commit 5379163

Please sign in to comment.