Home > Mobile >  How can I include in the JSON's GET request the list of foreign keys of a model in Django?
How can I include in the JSON's GET request the list of foreign keys of a model in Django?

Time:11-02

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.

  • Related