В Django Rest Framework как сделать так, чтобы представление на основе функции откатывало все сделанные изменения, если что-то не получилось
У меня есть api endpoint, в который пользователь отправляет ключевую пару file_field: File в типе содержимого multipart. Функция должна обновить каждый документ и создать историю об изменении. Затем она должна завершить сессию, которую пользователь использовал для этого изменения. Если документ не может быть обновлен или историческая не может быть создана все операции и изменения должны откатиться назад, как архивировать это. Вот мой текущий вид базы функций:
@transaction.atomic
@api_view(['POST'])
@parser_classes([JSONParser, MultiPartParser])
@permission_classes([HasSpecialSessionPermission])
def update_documents(request):
user = request.user
special_session = SpecialSessionConfiguration.objects.filter(user=user, completed=False).first()
lot = DefaultLotModel.objects.filter(user=user, call__active=True).first()
for key, uploaded_file in request.FILES.items():
try:
validate_file_size(uploaded_file)
if key != 'financial_form' and key != 'power_point':
validate_file_extension(uploaded_file)
except ValidationError as e:
return Response({'message': str(e)}, status=status.HTTP_400_BAD_REQUEST)
if special_session.special_session_fields.filter(
field_name=get_field_number(SPECIAL_SESSION_FIELD, key)).exists():
if hasattr(lot, key):
current_file = getattr(lot, key)
if current_file:
setattr(lot, key, uploaded_file)
LotDocumentHistory.objects.create(
lot=lot,
old_file=current_file,
field_name=key,
)
setattr(lot, key, uploaded_file)
lot.save()
else:
for child_field in ['first_lots', 'second_lots', 'third_lots']:
child_lot = getattr(lot, child_field, None)
if child_lot and hasattr(child_lot, key):
current_file = getattr(child_lot, key)
if current_file:
LotDocumentHistory.objects.create(
lot=lot,
old_file=current_file,
field_name=key,
)
setattr(child_lot, key, uploaded_file)
child_lot.save()
elif special_session.extra_files:
try:
data = {'name': key, 'file': uploaded_file, 'lot': lot.pk}
serializer = ExtraFileSerializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
except ValidationError as ve:
error_dict = ve.get_full_details()
response_data = {
ERROR_TYPE: VALIDATION_ERROR,
ERRORS: error_dict,
MESSAGE: get_validation_error_message(error_dict)
}
return Response(data=response_data, status=status.HTTP_400_BAD_REQUEST)
special_session.completed = True
special_session.save()
return Response(data={'lot_id': lot.pk}, status=status.HTTP_200_OK)
Если одно из обновлений и сохранений завершилось неудачно, все операции должны вернуться назад