Micromegas
Micromegas

Reputation: 1689

How to filter against URL with foreign key field in Django REST, overwriting get_queryset method correctly

I am trying to filter my queryset against an url with django REST but can't really get it to work.

I want to pass a string in the URL (a project name). According to this string, which is a foreign key, I want to filter my queryset (BuildingGroup).

I don't want to use query params but a url filter. I followed the docs but there is not so much on it on the site.

This is what I am trying:

class ListBuildingGroupProject(ListAPIView):
    serializer_class    = BuildingGroupSerializer
    filter_fields       = 'project'

    def get_queryset(self):

        project = self.kwargs['project']
        building_groups = BuildingGroup.objects.filter(project=project)
        result = building_groups.order_by('-creation_date')

        return result

The line building_groups = BuildingGroup.objects.filter(project=project) throws me a KeyError for project.

Here are my models. Note that BuildingGroup has one Project. A project can belong to many BuildingGroups. 

class BuildingGroup(models.Model):
    description           = models.CharField(max_length=500, null=True, blank=True)
    project               = models.ForeignKey(Project, on_delete=models.CASCADE)
    creation_date         = models.DateTimeField(auto_now=False)
   class Project(models.Model):
       project_name            = models.CharField(max_length=120, primary_key=True, unique=True)
       start_date              = models.DateTimeField(auto_now=False, null=True, blank=True)
       end_date                = models.DateTimeField(auto_now=False, null=True, blank=True)


and here my URL:

    path('project/<str:project_name>', ListBuildingGroupProject.as_view(), name='building-group-project'),

Help is so much appreciated! Thanks in advance!

Upvotes: 0

Views: 1319

Answers (2)

Julien Kieffer
Julien Kieffer

Reputation: 1145

You might want to have a look at this DRF documentation about this. It'll require to install Django Filters

You just need to declare in some rest_filters.py

from django_filters import rest_framework as filters
from .models import BuildingGroup
class BuildingGroupFilter(filters.FilterSet):
   class Meta:
       model = BuildingGroup
       fields = { 
           "project__name":["exact","icontains"],
           "project":["exact","in"]
       }

Then within your ViewSet declaration: [...] from .rest_filters import BuildingGroupFilter

class ListBuildingGroupProject(ListAPIView):
    serializer_class=BuildingGroupSerializer
    filterset_class = BuildingGroupFilter

You can now enjoy a restfull behavior with: {path_to_your_endpoint}?project__name__icontains="Hello World" or {path_to_your_endpoint}?project__=[Project Id List]

To checkout how things works, filters are available in the browsable API.

Upvotes: 1

Linovia
Linovia

Reputation: 20966

In your url, your argument is called project_name. This is what you should get from the kwargs. Beside, you want it to match the project.project_name:

def get_queryset(self):

    project_name = self.kwargs['project_name']
    building_groups = BuildingGroup.objects.filter(project__project_name=project_name)
    result = building_groups.order_by('-creation_date')

    return result

Upvotes: 1

Related Questions