My models have users that can have multiple devices. When I do a GET request on users it returns only the fields specified in the user model, as it should. But I want the option to include in the JSON returned by the GET request the list of devices the user has. How can I do that? Secondly, is there a way I can sometimes get a user with the list of devices in the same JSON, and other times without it? Also, I am really new to Django, and I would appreciate a lot code examples to understand better, if possible.
These are my models:
class User(models.Model):
name = models.CharField(max_length=100)
birth_date = models.DateField()
address = models.CharField(max_length=200)
class Device(models.Model):
description = models.CharField(max_length=200)
location = models.CharField(max_length=200)
max_energy_consumption = models.FloatField()
avg_energy_consuumption = models.FloatField()
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
My serializers:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = Device
fields = '__all__'
And the following default ModelViewSets for CRUD api calls:
class UserViewSet(ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
class DeviceViewSet(ModelViewSet):
queryset = Device.objects.all()
serializer_class = DeviceSerializer
CodePudding user response:
There are some different ways easiest one would be add a property
in your User model and add that to your serializer
class User(models.Model):
name = models.CharField(max_length=100)
birth_date = models.DateField()
address = models.CharField(max_length=200)
@property
def devices(self):
return Device.objects.filter(user_id=self.id).values("location", "description").distinct()
class UserSerializer(serializers.ModelSerializer):
devices = serializers.ReadOnlyField()
class Meta:
model = User
fields = '__all__'
EDIT - for second part of your question:
I have experienced that writing '__all__'
in our serializers not the best thing to do when we do not need all the information all the time(performance issues). To address this obsticle making a seperate serializer would be again an easy solution. Whenever I am facing this kind of thing i query same endpoint but send a different qs that i dont use in other endpoint in your case lets say your user viewsets route is something like /api/user/
you can add a qs when you send your get request to your backend and add ?with_devices=true
.
Then you can use your second user serializer like this:
class UserViewSet(ModelViewSet):
queryset = User.objects.all()
def get_serializer_class(self):
if self.request.GET.get("with_devices", False):
return UserWithDeviceSerializer
return UserSerializer
where your serializers would be something like:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["name", "birth_date", ..so on]
class UserWithDeviceSerializer(serializers.ModelSerializer):
devices = serializers.ReadOnlyField()
class Meta:
model = User
fields = '__all__'
This would give you what you asked in the comment.