0

I'm new to django and I'm trying to find a solution on how to post an object with array of object inside my database.

So far, here's my sample model.

class Fruit(models.Model):
    name = models.CharField(max_length=100)


class FruitReviews(models.Model):
    reviews = models.CharField(max_length=100)
    fruit = models.ForeignKey(Fruit, on_delete=models.CASCADE)

Here's my serializer.

class FruitSerializer(serializers.ModelSerializer):
    class Meta:
        model = Fruit
        fields = '__all__'

class FruitReviewSerializer(serializers.ModelSerializer):
    class Meta:
        model = FruitReviews
        fields = '__all__'

And Here's my viewset that I'm trying but unfortunately, it doesn't work.

@api_view(['POST'])
def createFruit(request):
    serializer = FruitSerializer(data=request.data)
    serializer2 = FruitReviewSerializer(data=request.data.fruitReviews, many = True)
    if serializer.is_valid() and serializer2.is_valid():
        serializer.save()
        serializer2.save()
        return Response(status=status.HTTP_200_OK)

For the URL, I'm using something like this:

from apiapp import views

urlpatterns = [
    path('fruit-api/', views.createFruit),
]

Basically, for instance, from the client side I want to post something like this

{
    "name": "Apple",
    "fruitReviews": [{
        "reviews": "Very yummy"
    }, 
    {
        "reviews": "Healthy"
    },
    {
        "reviews": "Fresh"
    }]
}

I want it to be posted to the fruit table and fruit reviews properly with their relationships as one-to-many intact. Any help please?

12
  • That means you want to save apple in fruit table and reviews in fruitReview table in this POST? Commented Oct 6, 2022 at 3:57
  • That's right @ilyasbbu is it possible in django? I'm completely new to it Commented Oct 6, 2022 at 4:02
  • I'm not confident to my def createFruit because I'm not sure if it's possible. Commented Oct 6, 2022 at 4:03
  • It is possible in a way i know but that doesnt check for serializer validations! Commented Oct 6, 2022 at 4:03
  • And as you run this code do u get any errror messages or simply didn't work? Commented Oct 6, 2022 at 4:05

3 Answers 3

1

By default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create create() and/or update() methods in order to explicitly specify how the child relationships should be saved:

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Track
        fields = ['order', 'title', 'duration']

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True)

    class Meta:
        model = Album
        fields = ['album_name', 'artist', 'tracks']

    def create(self, validated_data):
        tracks_data = validated_data.pop('tracks')
        album = Album.objects.create(**validated_data)
        for track_data in tracks_data:
            Track.objects.create(album=album, **track_data)
        return album

and data should be like:

data = {
    'album_name': 'The Grey Album',
    'artist': 'Danger Mouse',
    'tracks': [
        {'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
        {'order': 2, 'title': 'What More Can I Say', 'duration': 264},
        {'order': 3, 'title': 'Encore', 'duration': 159},
    ],
}

reference: https://www.django-rest-framework.org/api-guide/relations/

Sign up to request clarification or add additional context in comments.

2 Comments

Hello, what's the usage of that? I'm trying to use that but when I'm calling the if serializer.is_valid() serializer.save(), I'm getting the error that my child validated.pop('history')` is error.
Hello, this the best practice to deal with one-to-many nested serializer, you can use it in this way better than what you do, I put Django Rest Framework reference to check how they suggest
0

I hope it will work without changing your serializers.

@api_view(['POST'])
@transaction.atomic
def create_fruit(request):
    fruit_reviews_data = request.data['fruitReviews']
    if 'fruitReviews' in request.data.keys():
        request.data.pop('fruitReviews')

    fruit_serializer = FruitSerializer(data=request.data)

    fruit_obj = None
    if fruit_serializer.is_valid(raise_exception=True):
        fruit_obj = Fruit.objects.create(**request.data)

    for fruit_review_data in fruit_reviews_data:
        fruit_review_data['fruit_id'] = fruit_obj.id
        fruit_review_serializer =FruitReviewSerializer(data=fruit_review_data)
        if fruit_review_serializer.is_valid(raise_exception=True):
            fruit_review_serializer.save()
         
    return Response(status=status.HTTP_200_OK)

1 Comment

shows error django.db.utils.IntegrityError: NOT NULL constraint failed: mainapp_fruitreviews.fruit_id
0

First you need to change your serializer for FruitReviewSerializer as:

  class FruitReviewSerializer(serializers.ModelSerializer):
      class Meta:
          model = FruitReviews
          fields = ['reviews']

Then in views.py:

  @api_view(['POST'])
  def createFruit(request):
      serializer = FruitSerializer(data=request.data)
      serializer2 = FruitReviewSerializer(data=request.data['fruitReviews'], many = True)
      if serializer.is_valid() and serializer2.is_valid():
          fruit = Fruit.objects.filter(name = request.data['name']).exists()
          if not fruit:
              serializer.save()
          fruit = Fruit.objects.get(name = request.data['name'])
          for i in request.data['fruitReviews']:
              review = FruitReviews(
                  fruit = fruit,
                  reviews = i['reviews']
              )
              review.save()
          return Response(status=status.HTTP_200_OK)
      else:
          return Response(status=400)

1 Comment

Thank you, I upvote this answer because it's also helpful but I accepted the answer Hashem because it's connected to the restframework. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.