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?
CodePudding user response:
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/
CodePudding user response:
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)
CodePudding user response:
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)