Reputation: 391
I am using Django Rest Framework to create a REST Api. My serializers:
class ItemSerializer(serializers.ModelSerializer): #inherit from this class
owner = serializers.ReadOnlyField(source='user.id')
class Meta:
model = Item
fields = ('id','name', 'owner')
class UserSerializer(serializers.ModelSerializer):
items = serializers.PrimaryKeyRelatedField(many=True, queryset=Item.objects.all())
class Meta:
model = User
fields = ('id', 'username', 'items')
The only model:
class Item(models.Model):
name = models.CharField(max_length=10)
id = models.AutoField(primary_key=True)
owner = models.ForeignKey('auth.User', related_name='items', on_delete=models.CASCADE)
def __str__(self):
return self.name
Now if I GET
the users:
HTTP 200 OK Allow: GET, HEAD, OPTIONS Content-Type: application/json Vary: Accept [ { "id": 1, "username": "chuck", "items": [ 1, 2 ] } ]
I receive all the items that this user has (by the way I could I get the name instead of the primary keys of the items ?).
How would I go if I wanted to reverse that process and get all the owners of the objects ? Here's the response I have so far (the owners are missing) :
HTTP 200 OK Allow: GET, POST, HEAD, OPTIONS Content-Type: application/json Vary: Accept [ { "id": 1, "name": "Vest" }, { "id": 2, "name": "Pants" } ]`
I have tried to add owners = serializers.ReadOnlyField(source='owner')
as you can see in the code (commented parts), but I have the following error :
Object of type 'User' is not JSON serializable
Thank you for your help.
Upvotes: 1
Views: 1774
Reputation: 3364
If you want to receive name of the item instead of primary key, you could just change items
to StringRelatedField
and then __str__
from your Item
will be used.
items = serializers.StringRelatedField(many=True)
But even better solution would be Nested relationship. You simply change items
to serializer defining items, eg:
items = ItemSerializer(many=True, read_only=True)
Another solution would be that you remove owner
and define depth. This way all information about owners (users) will be serialized:
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
depth = 1
fields = ('id', 'name', 'owner')
and for items
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
depth = 1
fields = ('id', 'username', 'items')
Now for the reverse, list of items with owners, it's not possible with ModelSerializer
. You probably have to manually do that. Here is an example, where you don't need a serializer.
class ItemOwnerViewSet(viewsets.ViewSet):
def list(self, request):
data = []
queryset = Item.objects.values('name', 'owner__username')
for item in queryset:
temp = dict()
t = next((i for i in data if i['name'] == item['name']), None)
if t:
t['owners'].append(item['owner__username'])
else:
temp['name'] = item['name']
temp['owners'] = [item['owner__username']]
data.append(temp)
return Response(data)
Serializer for this viewset
would probably be something along these lines:
class ItemOwnerSerializer(serializers.Serializer):
name = serializers.CharField()
owners = serializers.ListField(child=serializers.CharField())
I haven't tested all this, but I guess it should work. I hope it helps.
Upvotes: 3
Reputation: 7757
You are almost there. In your ItemSerializer, Try
serializers.ReadOnlyField(source='owner.id')
or
owner = UserSerializer()
If you want to see all user information
Upvotes: 4