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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With