4👍
✅
You need to handle the nested serializers creation in the serializers create
method;
4👍
If you’re not hung up on creating intermediate and other table records in one HTTP request. Otherwise you’ve got to handle nested representations.
models.py
:
from django.db import models
import django.urls
import urllib
class Product(models.Model):
name = models.CharField(max_length=255)
def get_absolute_url(self):
return django.urls.reverse('app:product', args=(self.pk,))
def __str__(self):
return self.name
class Size(models.Model):
products = models.ManyToManyField(Product, through=ProductVariant,
related_name='sizes', related_query_name='size')
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class ProductVariant(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE,
related_name='productvariants', related_query_name='productvariant')
size = models.ForeignKey('Size', on_delete=models.CASCADE,
related_name='productvariants', related_query_name='productvariant')
class Meta:
unique_together = ('product', 'size')
def __str__(self):
return str(self.product) + ': ' + str(self.size)
api.py
:
from rest_framework import routers, serializers, viewsets
from app import models
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = models.Product
fields = ('id', 'name')
read_only_fields = ('id',)
class ProductViewSet(viewsets.ModelViewSet):
queryset = models.Product.objects.all()
serializer_class = ProductSerializer
class SizeSerializer(serializers.ModelSerializer):
class Meta:
model = models.Size
fields = ('id', 'name')
read_only_fields = ('id',)
class SizeViewSet(viewsets.ModelViewSet):
queryset = models.Size.objects.all()
serializer_class = SizeSerializer
class ProductVariantSerializer(serializers.ModelSerializer):
product = serializers.PrimaryKeyRelatedField(
queryset=models.Product.objects.all())
size = serializers.PrimaryKeyRelatedField(
queryset=models.Size.objects.all())
class Meta:
model = models.ProductVariant
fields = ('id', 'product', 'size')
read_only_fields = ('id',)
class ProductVariantViewSet(viewsets.ModelViewSet):
queryset = models.ProductVariant.objects.all()
serializer_class = ProductVariantSerializer
router = routers.DefaultRouter()
router.register(r'products', ProductViewSet)
router.register(r'sizes', SizeViewSet)
router.register(r'productvariants', ProductVariantViewSet)
api_urlpatterns = ([
url('', include(router.urls)),
], 'api')
urlpatterns += [
url(r'^api/', include(api_urlpatterns)),
]
After that you can
POST /api/products/ {name: ...}
POST /api/sizes/ {name: ...}
POST /api/productvariants/ {product: productId, size: sizeId}
0👍
Hi I will be showing many to many for update and create. The context is the event can have many dances and dances can have many event.
The request will be as followed.
{
"competition": 2,
"title": "the title",
"dances":[ {"id":1},{"id":2}],
"description": "the desc"
}
The Create Function will be as followed.
def create(self, validated_data):
try:
dance_ids = []
for dance in self.initial_data['dances']:
if 'id' not in dance:
raise serializers.ValidationError({'detail': 'key error'})
dance_ids.append(dance['id'])
new_event = models.Event.objects.create(**validated_data)
if dance_ids:
for dance_id in dance_ids:
new_event.dances.add(dance_id)
new_event.save()
return new_event
except Exception as e:
raise serializers.ValidationError({'detail': e})
The Update Function will be as followed.
def update(self, instance, validated_data):
# Delete all records of genres.
try:
for current_genre in instance.dances.all():
instance.dances.remove(current_genre)
# Repopulate genres into instance.
for dance in self.initial_data['dances']:
if 'id' not in dance:
raise serializers.ValidationError({'detail': 'key error'})
dance_obj = models.Dance.objects.get(pk=dance['id'])
instance.dances.add(dance_obj)
event_updated = super().update(instance, validated_data)
return event_updated
except Exception as e:
raise serializers.ValidationError({'detail': e})
If you want to just do "dances":[1,2] instead, just make some amendments to the
for dance in self.initial_data['dances']:
if 'id' not in dance:
raise serializers.ValidationError({'detail': 'key error'})
dance_ids.append(dance['id'])
part.
Source:stackexchange.com