Is there a way to create a endpoint that creates multiple objects? what I've been doing instead is taking in request data and creating the objects one at a time and if one fails then delete the previously created entities, this seems really really hacky and there has to be a better way to create multiple objects. So essentially all Post
need to be associated with a Goal
so when a request comes it it'll be accompanied with post related data and goal related data in request.data
. So it should create the Goal
first then the Post
associated with it. Is there a way to do this in one go? My assumption is creating a custom serializer to handle this, but not sure how to eloquently handle the case of when if Post
fails to create I should delete Goal
.
model.py
class Goal(AbstractBaseModel):
creator_uuid = models.ForeignKey(
User, on_delete=models.SET_NULL, null=True, related_name="goal_creator_uuid")
goal_category = models.ForeignKey(GoalCategory, on_delete=models.CASCADE)
description = models.CharField(max_length=150, validators=[MinLengthValidator(5)])
class Post(AbstractBaseModel):
creator_uuid = models.ForeignKey(
User, on_delete=models.CASCADE, related_name="post_creator_uuid")
goal_uuid = models.ForeignKey(Goal, on_delete=models.CASCADE)
body = post_body
view.py
def post(request):
"""
POST endpoint for current user creating a goal update post
"""
goal_serializer = GoalSerializer(data=request.data)
if goal_serializer.is_valid():
goal_obj = goal_serializer.save()
else:
# return 400 Response
request.data['goal_uuid'] = str(goal_obj.uud)
post_serializer = PostSerializer(data=request.data)
if post_serializer.is_valid():
post_serializer.save()
else:
goal_obj.delete()
# return 400 Response
# return 200 Response
CodePudding user response:
You can wrap those serializers in an atomic block with a try...except
like this:
from rest_framework.exceptions import ValidationError
def post(request):
try:
with transaction.atomic():
goal_serializer = GoalSerializer(data=request.data)
goal_serializer.is_valid(raise_exception=True)
goal_obj = goal_serializer.save()
request.data['goal_uuid'] = str(goal_obj.uud)
post_serializer = PostSerializer(data=request.data)
post_serializer.is_valid(raise_exception=True)
post_serializer.save()
except ValidationError as e:
# return 400 Response with e as details
# return 200 Response
When the serializer validation fails (or if any exception gets raised), it will automatically rollback everything within the atomic
block. You can then catch the ValidationError
and build a response you need.