简体   繁体   中英

DJango rest framework - API list using filter field from related models

Hi I'm new to Django and the Django rest framework so my terminology may be off.

I'm trying to build an API that gives back a list of items from a model but filtered based on fields in another related model.

I'll provide my current view and serializer classes and models

class service(models.Model):
    name = models.CharField(max_length=50)
    vendor = models.CharField(max_length=50)
    version = models.CharField(max_length=10)
    registration_status = models.BooleanField(default=False)

class service_network(models.Model):

    service = models.OneToOneField(
        service,
        related_name='network',
        on_delete=models.CASCADE,
        primary_key=True,
    )
    forwarded_port = models.CharField(max_length=50)

class ServiceNetworkSerializer(serializers.ModelSerializer):
    class Meta:
        model = service_network
        fields = '__all__'

class ServiceSerializer(serializers.ModelSerializer):
    network = ServiceNetworkSerializer()

    class Meta:
        model = service
        fields = [
            'id',
            'name',
            'vendor',
            'version',
            'registration_status',
            'network',
        ]
class ServiceAPI(ModelViewSet):
    queryset = service.objects.all()
    serializer_class = ServiceSerializer
    filterset_fields = '__all__'

Currently I can get back lists using a URL query string

{{baseUrl}}/engine/service?registration_status=true

What I want to do is something like this

{{baseUrl}}/engine/service/network?forwarded_port=8080

Which I would expect to give back a list of services where the related.network field "forwarded_port" is equal to 8080.

Is there another way to query this API? Maybe using a POST with a body containing the query? If there something in the DOCS that I can read, I've tried to look through filtering and querysets but I wasn't able to find anything that would do this out of the box

I'm also new to stackoverflow and I've tried to keep my question short with as much relevant information so if there anything missing I'd be happy to edit my question

I was able to solve this using the following queryset override

    def get_queryset(self):
    if len(self.request.GET) > 0:
        query_set = {}
        for query in self.request.GET:
            query_set[query] = self.request.GET.get(query)
        return service.objects.filter(**query_set)
    else:
        return service.objects.all()

What this does is lets you filter fields without explicitly specifying what they are, in cases when you have many fields that need filtering. I also have to say as I'm not experienced with Django, I'm not sure what kind of errors this may bring up but its a hack that's worked for me. If I find this is really bad I'll come back and remove this.

Try this:

{{baseUrl}}/engine/service?network__forwarded_port=8080

Probably it works.

Doc: https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships-1

EDIT:

If the above answer doesn't work, you can change the ServiceApi class and filter by yourself:

class ServiceAPI(ModelViewSet):
    def get_queryset(self):
        if self.request.GET.get(network__forwarded_port)
            return service.objects.filter(network__forwarded_port = self.request.GET.get(network__forwarded_port))
        else:
            return service.objects.all()
    serializer_class = ServiceSerializer
    filterset_fields = '__all__'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM