Skip to content

Commit

Permalink
feat: allow customizing UpsertMixin to fetch the duplicated record
Browse files Browse the repository at this point in the history
  • Loading branch information
joaodaher committed Jun 17, 2024
1 parent a80bc17 commit bbaf407
Show file tree
Hide file tree
Showing 3 changed files with 252 additions and 242 deletions.
27 changes: 19 additions & 8 deletions drf_kit/views/viewsets.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging

from django.db import IntegrityError
from django.db.models import Model
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.exceptions import MethodNotAllowed
Expand Down Expand Up @@ -202,17 +203,27 @@ class UpsertMixin(MultiSerializerMixin):
def create(self, request, *args, **kwargs):
try:
return super().create(request, *args, **kwargs)
except IntegrityError as exc:
if not DuplicatedRecord.verify(integrity_error=exc):
except (IntegrityError, ConflictException) as exc:
instance = self.get_duplicated_record(
model_klass=self.get_queryset().model, body=request.data, exception=exc
)
if not instance:
raise
error = DuplicatedRecord(model_klass=self.get_queryset().model, body=request.data, integrity_error=exc)
instance = self.get_queryset().get(error.get_filter())
except ConflictException as exc:
if len(exc.with_models) != 1: # Upsert can only handle conflict with 1 model
raise
instance = exc.with_models[0]
return self.upsert(instance=instance, data=request.data, *args, **kwargs)

def get_duplicated_record(self, model_klass: type[Model], body: dict, exception: Exception) -> Model | None:
if isinstance(exception, IntegrityError):
if DuplicatedRecord.verify(integrity_error=exception):
error = DuplicatedRecord(model_klass=model_klass, body=body, integrity_error=exception)
else:
return None
return self.get_queryset().get(error.get_filter())
if isinstance(exception, ConflictException):
if len(exception.with_models) != 1: # Upsert can only handle conflict with 1 model
return None
return exception.with_models[0]
return None

def upsert(self, instance, data, *args, **kwargs):
partial = True
serializer = self.get_serializer(instance, data=data, partial=partial)
Expand Down
Loading

0 comments on commit bbaf407

Please sign in to comment.