Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework allow lookup_field to have several options

I'm currently learning how to build an API for my company. I haven't been doing this for very long at all so I'm basically a junior developer at this point.

Following some tutorials, I got my API up and running on a very basic level using class based views.

We do scientific measuring with hardware, and it's based off of "runs", "run properties" and "chambers".

For the URL, I would like to allow lookups to be based on several different keywords. So if they go to "www.example.com/api/runs_list", the API will show all runs done and chambers for the user that is logged in.

I would like to allow search for a specific run, or by chamber. So if they want to go to a run started on 2017-11-02T18:20:24Z they can go to "www.example.com/api/2017-11-02T18:20:24Z" and get the JSON data related to that run.

Or if they go to "www.example.com/api/chamber_34-A" they will get all runs performed so far for that chamber.

I've looked at lookup_field and lookup_url_kwargs, but it seems to only allow for one option (I have it set to chamber for now).

Here is what I have:

urls.py

from django.conf.urls import url
from django.contrib import admin

from company.api.views import (
    RunPropertiesListAPIView,
    RunPropertiesDetailAPIView,
    RunsDetailAPIView,
    RunsListAPIView,
)

urlpatterns = [
    url(r'^runs_list/$', RunsListAPIView.as_view(), name='runs_list'),
    url(r'^properties_list/$', RunPropertiesListAPIView.as_view(), 
        name='properties_list'),
    url(r'^runs_list/(?P<chamber>\d+)/$', RunsDetailAPIView.as_view(), 
        name='runs_list_detail'),
    url(r'^properties_list/(?P<chamber>\d+)/$', 
        RunPropertiesDetailAPIView.as_view(), name='properties_list_detail'),
]

Here is serializers.py

from rest_framework.serializers import ModelSerializer

from company.company_import.models import (
    RunProperties,
    Runs,
)

class RunsSerializer(ModelSerializer):
        class Meta:
            model = Runs
            fields = [
                'id',
                'chamber',
                'start_time',
                'end_time',
                'step_time'
            ]

class RunPropertiesSerializer(ModelSerializer):
        class Meta:
            model = RunProperties
            fields = [
                'id',
                'runs',
                'property_name',
                'property_value'
            ]

And here is views.py

from rest_framework.generics import ListAPIView, RetrieveAPIView

from company.company_import.models import (
    RunProperties,
    Runs,
)

from company.company_import.api.serializers import (
    RunPropertiesSerializer,
    RunsSerializer,
)

class RunsListAPIView(ListAPIView):
    queryset = Runs.objects.all()
    serializer_class = RunsSerializer

class RunPropertiesListAPIView(ListAPIView):
    queryset = RunProperties.objects.all()
    serializer_class = RunPropertiesSerializer

class RunsDetailAPIView(RetrieveAPIView):
    queryset = Runs.objects.all()
    serializer_class = RunsSerializer
    lookup_field = 'chamber'
    lookup_url_kwarg = 'chamber'

class RunPropertiesDetailAPIView(RetrieveAPIView):
    queryset = RunProperties.objects.all()
    serializer_class = RunPropertiesSerializer

What I have tried:

On urls.py

(using a | to allow two options for RegEx)(didn't seem to work)

url(r'^runs_list/(?P<chamber>\d+)|(?P<start_time>\d+)/$', 
        RunsDetailAPIView.as_view(), 
        name='runs_list_detail'),

On views.py

(Using python "or" to see if allowed for different options, didn't work)

class RunsDetailAPIView(RetrieveAPIView):
    queryset = Runs.objects.all()
    serializer_class = RunsSerializer
    lookup_field = 'chamber' or 'start_time' (didn't work)
    lookup_url_kwarg = 'chamber' or 'start_time' (didn't work)

(Using a list of strings to see if it allowed for different options, didn't 
work)

queryset = Runs.objects.all()
    serializer_class = RunsSerializer
    lookups = ['chamber', 'start_time'] (didn't work)
    lookup_field = lookups (didn't work)
    lookup_url_kwarg = lookups (didn't work)

For now I've left it defaulted to just chambers, but I'd really like to get specific and varied search lookups enabled.

like image 530
Mormoran Avatar asked Oct 26 '25 07:10

Mormoran


1 Answers

Instead of trying to figure out what you're capturing in the URL itself, try capturing whatever kwarg is passed to the URL then figure out what to do with it in your view.

Your URL pattern could look like this:

url(r'^runs_list/(?P<search_term>\d+)/$', 
    RunsDetailAPIView.as_view(), 
    name='runs_list_detail'),

Then parse search_term in your view:

def get_object(self):
    search_term = self.kwargs['search_term']
    ...

For instance, you could use your search_term to make some Q statements: https://docs.djangoproject.com/en/1.11/topics/db/queries/#complex-lookups-with-q-objects

Runs.objects.filter(
    Q(chamber = search_term) | Q(start_time = search_term)
)

Depending on your use case, search fields, and environment, you might also consider making SearchVectors: https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/search/#searchvector

Or you could even simply filter your queryset with try/except blocks. The main point is to get the kwarg from your URL and work with it in your get_object function rather than trying to figure it all out within the URL itself.


All of the above works with base Django; no DRF required. Since you are working with Django Rest Framework, you might also be interested in the django-filters package:

http://www.django-rest-framework.org/api-guide/filtering/#djangofilterbackend

like image 111
souldeux Avatar answered Oct 28 '25 21:10

souldeux



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!