Home > OS >  Django - Create multiple different objects with relations in single Django endpoint
Django - Create multiple different objects with relations in single Django endpoint

Time:10-15

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.

  • Related