I'm working on a django project in which I need to build a rest API for some executions, I don't have much concerns about models as I only need to perform executions on the base of user's inputs/calls.
Here's my scenario:
The Major thing is the Deployment ( An App in my project )
On a get request user will get a list of all it's
deployments(objects).
A user will send a POST request to /deployments along with the complete
object as:
{
"deployment_name": "dep4",
"credentials": "cre4",
"project_name": "pro4",
"project_id": "004",
"cluster_name": "clus4",
"zone_region": "zon4",
"services": "Single",
"configuration": "conf4",
"routing": "route4" }
then I need to use this data, validate and perform some execution on the base of this data. For example, I will make deployments on a cloud platform with the help of this information by using third-party APIs.
I'm really confused by the documentation of DRF, especially about serializers.
Update: Currently, How I'm trying to do the POST:
From apiview.py
class DeploymentsList(APIView):
queryset = DeploymentOnUserModel.objects.all()
def post(self, request):
print(request.data)
DeploymentOnUserModel.objects.create(
deployment_name=request.data['deployment_name'],
credentials=request.data['credentials'],
project_name=request.data['project_name'],
project_id=request.data['project_id'],
cluster_name=request.data['cluster_name'],
zone_region=request.data['zone_region'],
services=request.data['services'],
configuration=request.data['configuration'],
routing=request.data['routing'],
)
return Response(request.data)
So, how can I validate the incoming data/request?
Here's my Deployment Model:
class DeploymentOnUserModel(models.Model):
deployment_name = models.CharField(max_length=256, )
credentials = models.TextField(blank=False)
project_name = models.CharField(max_length=150, blank=False)
project_id = models.CharField(max_length=150, blank=True)
cluster_name = models.CharField(max_length=256, blank=False)
zone_region = models.CharField(max_length=150, blank=False)
services = models.CharField(max_length=150, choices=services)
configuration = models.TextField()
routing = models.TextField()
def save(self, **kwargs):
if not self.id and self.services == 'Multiple' and not self.routing and not self.configuration:
raise ValidationError("You must have to provide routing for multiple services deployment.")
super().save(**kwargs)
From urls.py:
app_name = 'deployments'
urlpatterns = [
path('deployments/', apiview.DeploymentsList.as_view(), name='deployment_list'),
path('deployments/<int:pk>', apiview.DeploymentDetail.as_view(), name='deployment_detail')
]
Which approach and things from DRF I should use to implement my API.
You will probably want to implement DRFs ModelSerializer and ModelViewSet such that you can easily reuse the Django model you already have.
Your serializer could be like this (e.g. in serializers.py):
from rest_framework import serializers
from .models import DeploymentOnUser
class DeploymentOnUserModelSerializer(serializers.ModelSerializer):
class Meta:
model = DeploymentOnUser
fields = (deployment_name, credentials, )
You should add your own validation here, much like you would do with Django forms.
The viewset could be like this (e.g. in views.py):
from rest_framework import viewsets
from rest_framework.response import Response
from .models import DeploymentOnUserModel
from .serializers import DeploymentOnUserModelSerializer
class DeploymentOnUserViewSet(viewsets.ModelViewSet):
queryset = DeploymentOnUserModel.objects.all()
serializer_class = DeploymentOnUserModelSerializer
def create(self, request, *args, **kwargs):
"""overwrite this for extra actions"""
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
Depending on your situation, you might even need to overwrite create -- this just shows how you could do it.
The ModelViewSet and ModelSerializer remove much of the boilerplate code. However, if you haven't used DRF before, it doesn't hurt to first go through the tutorial
Don't forget to also register the viewset in urls.py:
from django.conf.urls import url, include
from rest_framework import routers
from .views import DeploymentOnUserViewSet
router = routers.DefaultRouter()
router.register('deployments', DeploymentOnUserViewSet)
urlpatterns = [
# other patterns also go here
url('', include(router.urls)),
]
You could then test your API by doing e.g. a POST call on /deployments/.
For unit testing, I mostly use this pattern:
from rest_framework.test import APIRequestFactory
# Create a POST request, at the root
request = APIRequestFactory().post('/')
response = DeploymentOnUserViewSet.as_view({'post': 'create'})(request)
assert response.status_code == 200
Related
I created a serializer and an API endpoint so I can retrieve some data from a Django DB in my React app but getting this error message:
AttributeError: 'ProgrammingChallengesView' object has no attribute 'get'
Here is my models.py:
#creating programming challenges
class ProgrammingChallenges(models.Model):
challenge_id = models.AutoField(primary_key=True)
challenge_name = models.CharField(max_length=200)
challenge_description = models.TextField()
challenge_expectations = models.TextField()
my serializer:
from accounts.models import ProgrammingChallenges
...
class ProgrammingChallengesView(serializers.ModelSerializer):
class Meta:
model = ProgrammingChallenges
fields = '__all__'
and my urls.py:
path('api/programming_challenges/', ProgrammingChallengesView, name='programming_challenges'),
Thanks to the comments; I clearly didn't understand that a serializer only transforms my data to make it available through an API. I still had to create a view for my API's endpoint.
I opted to create a ReadOnlyModelView because I only want to GET data from this endpoint.
Here is what I wrote in my views:
class ProgrammingChallengesView(ReadOnlyModelViewSet):
serializer_class = ProgrammingChallengesSerializer
queryset = ProgrammingChallenges.objects.all()
#action(detail=False)
def get_list(self, request):
pass
and in my urls.py:
path('api/programming_challenges/', ProgrammingChallengesView.as_view({'get':'list'}), name='programming_challenges'),
I think you shouldn't hurry read the docs again. You are trying to use serializers as views.
Models - are representation of db tables as class.
Serializer serializes the data to json.
View accepts the reqeust from client and returns a Response.
Code shoudld be:
models.py
class ProgrammingChallenge(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
expectations = models.TextField()
Your model name should be ProgrammingChallenge(singular) not ProgrammingChallenges(plural).
You should't add prefix challenge before all field names. Because we already know that the fields are in a Model called ProgrammingChallenge. And it is easy to access them like ProgrammingChallenge.name than ProgrammingChallenge.challenge_name
You don't have to add field id manually. Django model automatically adds id field as primary_key
serializer.py
from accounts.models import ProgrammingChallenge
...
class ProgrammingChallengeSerializer(serializers.ModelSerializer):
class Meta:
model = ProgrammingChallenge
fields = '__all__'
No problem in serialize.
Now, main problem is you don't have any view. You definetly read docs. You can use APIView, generic views or viewset. In this example i'm going to use ViewSet that handles CRUD operations built in.
viewsets.py
from rest_framework.viewsets import ModelViewSet
from .models import ProgrammingChallenge
from .serializers import ProgrammingChallengSerializer
class ProgrammingChallengViewSet(ModelViewSet):
queryset = ProgrammingChallenge.objects.all()
serializer_class = ProgrammingChallengeSerializer
urls.py
from rest_framework.routers import SimpleRouter
from .viewsets import ProgrammingChallenge
router = SimpleRouter()
router.register('challengr', ProgrammingChallengeViewSet)
urlpatterns = router.urls
Another advantage of using viewset, it also generate all endpoint for it's CRUD methods automatically via routes.
It should help you to start your first project.
AGAIN, READ THE DOCS!
#accounts.models.py:
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from words import models as word_models
# Create your models here.class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
last_visited_word = models.ForeignKey(word_models.Word, default=4760, on_delete = models.CASCADE)
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
#words/models.py
from django.db import models
from django.conf import settings
# Create your models here.
class Word(models.Model):
word = models.TextField(blank=True, null=True)
meaning = models.TextField(blank=True, null=True)
#accounts/serializers.py:
from rest_framework import serializers
from .models import UserProfile
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = '__all__'
#accounts/views.py:
#api_view(['POST'])
##authentication_classes([SessionAuthentication, BasicAuthentication])
#permission_classes([IsAuthenticated])
def userprofile_create_view(request, *args, **kwargs):
user_id = request.data.get('user')
try:
instance = UserProfile.objects.get(user_id=user_id)
except UserProfile.DoesNotExist:
instance=None
serializer = UserSerializer(instance, data=request.data)
if serializer.is_valid(raise_exception=True):
# create or update data
serializer.save()
return Response(serializer.data)
So Basically I have to update the last_visited_word of the user when the user visits that particular id. I am not able to do the "post" method to update last_visited_word. Api calling is done using axios. I am using React as my frontend. When I try to use the post request, it says a bad request. BTW react and django are connected as I am able to do a GET request successfully.
first of the question is kind of incomplete, but from what I can understand you need to configure your settings.py to allow post request from your react localhost. Also finding a way around Django and react can be quite tricky.
check if the api is working as expected. also in the django setting enable cors in middleware and whitelist the server on which the react is running.
This question is based on the one here. I am setting up a Django REST Framework for my web app and am trying to set up User accounts. Based on the REST documentation, they put all of their account code in their example in the main project directory and a separate application so did that as well. Here is what I have:
urls.py
from django.contrib import admin
from django.urls import include, path
from django.conf.urls import url
from rest_framework import routers
from . import views
router = routers.DefaultRouter()
router.register('users', views.UserViewSet)
urlpatterns = [
path('admin/', admin.site.urls),
url('', include(router.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]
serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True)
def create(self, validated_data):
user = User.objects.create(
username=validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
class Meta:
model = User
# Tuple of serialized model fields (see link [2])
fields = ( "id", "username", "password", )
views.py
from rest_framework import viewsets, permissions
from rest_framework.generics import CreateAPIView
from django.contrib.auth.models import User
from .serializers import UserSerializer
# Create your views here.
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated]
class CreateUserView(CreateAPIView):
model = User
permission_classes = [
permissions.AllowAny
]
serializer_class = UserSerializer
I have tried using the Boomerang REST Client in Chrome to POST data to this API, but it always returns a 403 Error saying "Invalid username/password." Specifically I am POSTing to http://127.0.0.1:8000/users/create/ with a Query String and 2 parameters: username and password. I also tried sending it as JSON and it returned the same. Any help would be appreciated.
It doesn't look like CreateUserView was registered in your urls.py. You should be able to register it and access it normally. I think this should work for you:
urlpatterns = [
...
url(r'^users/create/', views.CreateUserView.as_view()),
]
That said, I'd like to suggest adding an extra action for your UserViewSet instead:
# Create your views here.
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [permissions.IsAuthenticated
#action(methods=['post'], detail=False, permission_classes=[permissions.AllowAny])
def register(self, request, *args, **kwargs):
# This logic was taken from the `create` on `ModelViewSet`. Alter as needed.
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
Then you should be able to post via /users/register/. You can also specify your own url name and path on the decorator.
Maybe you are posting in the wrong url, try POST the same on http://127.0.0.1:8000/users/,
because ModelViewSet adds POST, PATCH, PUT, DELETE and GET methods automatically.
Also because you are asking for authentication (permission_classes = [permissions.IsAuthenticated]), you should send the headers for this in the request. There is a tutorial for this in the DRF site (https://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/)
based on django-rest-framework documents it's better to use viewset for create user api. therefor you need to send a POST request to http://127.0.0.1:8000/api-auth/users and no need to CreateUserView function.
But if you want to have a custom user create api do you need something like below:
class UserViewSet(viewsets.ModelViewSet):
"""
A viewset that provides the standard actions
"""
queryset = User.objects.all()
serializer_class = UserSerializer
#action(detail=True, methods=['post'], permission_classes=[permissions.AllowAny])
def create_user(self, request, pk=None):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
To have custom serializers in your ViewSet you can specify them in get_serializer_class function in your ViewSet like this:
class UserViewSet(viewsets.ModelViewSet):
# example viewset
def get_serializer_class(self):
if self.action == 'list':
return ListUserSerializer
elif self.action == 'create':
return CreateUserSerializer
elif self.action == 'update':
return UpdateUserSerializer
return DetailUserSerializer
I am trying to create a Restful Api for following methods to run jenkins jobs to run on saucelabs. I wanna queue jobs using restful API. I am using Django Restful Framework.
CreateMethod :
Accepts two fileds: ProjectName and URL
and returns a Token ID.
VerifyStatus:
Accepts Token ID and returns three fields. TokenID, running:True/False and
no_of_jobs: integervalue (0 if Not specified)
relseaseMethod:
Accepts release token call and returns true if success.
I am new to Restful API with, I am trying to run Jenkins job on sauce lab and queue them using a restful api on python Djano restframework. Guide me through.
Views.py
class RegisterTestMethodView(APIView):
authentication_classes = [SessionAuthentication, TokenAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated] #No access (not even read if not authorized)
def post(self, request, format=None):
serializer = RegisterTestMethodSerializers(data=request.data)
if serializer.is_valid():
serializer.save()
return Response({'tokenid':serializer.data['id']}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class CheckStatusView(APIView):
def get_object(self, pk):
try:
return Jobs.objects.get(pk=pk)
except Jobs.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
snippet = self.get_object(pk)
serializer = RegisterTestMethodSerializers(snippet)
return Response({"tokenid":serializer.data["id"], "Runtestnow" : False, "VMcount" : 0 })
class ReleaseTokenView(APIView):
def get_object(self, pk):
try:
return Jobs.objects.get(pk=pk)
except Jobs.DoesNotExist:
raise Http404
def delete(self, request, pk, format=None):
snippet = self.get_object(pk)
snippet.delete()
return Response(data={'Deleted':True}, status=status.HTTP_204_NO_CONTENT)
Serailizers.py
rom rest_framework import serializers
from .models import Jobs
from random import random
RegisterTestMethodSerializers(serializers.HyperlinkedModelSerializer):
class Meta:
model = Jobs
fields = ('id','name','url')
Models.py
from django.db import models
# Create your models here.
class Jobs(models.Model):
name = models.CharField(max_length=100)
url = models.URLField()
def __str__(self):
return self.name
Urls.py
from django.urls import path, include
from . import views
from .views import (RegisterTestMethodView,
RegisterTestMethodViewDetail,
CheckStatusView,
ReleaseTokenView
)
from rest_framework import routers
from rest_framework.authtoken.views import obtain_auth_token
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
urlpatterns = [
path('', include(router.urls)),
path('registertestmethod/',RegisterTestMethodView.as_view()),
path('registertestmethod/<int:pk>/',
RegisterTestMethodViewDetail.as_view()),
path('checkstatus/<int:pk>', CheckStatusView.as_view()),
path('releasetoken/<int:pk>', ReleaseTokenView.as_view()),
]
I have addded my Code here. I have other classes and function in my project as well.I tried to delete all of those. You might see extra import as a result of that. My code does following things.
POST --> http://localhost:8000/registertestmethod/
{
"name": "Name",
"url": "https://www.google.com"
}
returns
{
"tokenid": 32 #unique token ID return
}
This tokenid should be long I am using id as of now.
GET --> http://localhost:8000/checkstatus/32
is returning
{
"tokenid": 32, #unique tokenid refering to register info
"Runtestnow": false, #if job is running
"VMcount": 0 # number of VM used in sauce lab by the Jobs
}
DELETE --> http://localhost:8000/releasetoken/32 #should delete the jobs after done.
is deleting and returning
{
"Deleted": true
}
I want it to be dynamic and store info in database. Token should return everything on checkstatus.
You can use the ModelViewSet approach for this, this here is a very simple example for an API endpoint.
views.py
from rest_framework.viewsets import ModelViewSet
from api.serializers import SaucelabsSerializer
from rest_framework.response import Response
class SaucelabModelViewSet(ModelViewSet):
serializer_class = SaucelabSerializer
queryset = Sauselab.objects.all()
http_method_names = ['get', 'head', 'options', 'post']
def create(self, request):
pnam = request.data.get('project_name', None)
url = request.data.get('url', None)
if pnam and url:
# do something here
return Response({'success': 'Your success message'}, status=status.HTTP_200_OK)
else:
return Response({"error": "Your error message"}, status=status.HTTP_400_BAD_REQUEST)
serializers.py
from rest_framework.serializer import ModelSerializer
from appname.models import Saucelab
class SaucelabSerializer(ModelSerializer):
class Meta:
model = Saucelab
fields = '__all__'
appname/models.py
from django.db import models
class Saucelab(models.Model)
project_name = models.CharField(max_length=255)
url = models.URLField()
urls.py
from rest_framework.routers import DefaultRouter
from api import views
router = DefaultRouter()
router.register('your-endpoint-name', views.SaucelabModelViewSet, basename='your-url-name')
urlpatterns = []
urlpatterns += router.urls
This is a very basic example, where you create a model called saucelab which has the two fields you require, ie.project_name and url.
We create a app called api with two files inside it that aren't auto generated, serializers.py and urls.py. We create the most basic model serializer and ask it to serialize all fields of model Saucelab. Then we create a simple modelviewset which out of the box gives you a CRUD functionality. You can override the create method if you need to run some specific conditions otherwise dont override any methods and just make request to the endpoint with appropriate HTTP methods.
Here are a few links you can read
https://www.django-rest-framework.org/api-guide/viewsets/#modelviewset
https://www.django-rest-framework.org/api-guide/serializers/#modelserializer
To generate a random token
from django.utils.crypto import get_random_string
print(get_random_string(length=25))
output
u'rRXVe68NO7m3mHoBS488KdHaqQPD6Ofv'
I am using Django Rest Framework for developing web api for my project. As in my project i need to build nested api's endpoint like this:
/users/ - to get all users
/users/<user_pk> - to get details of a particular user
/users/<user_pk>/mails/ - to get all mails sent by a user
/users/<user_pk>/mails/<pk> - to get details of a mail sent by a user
So, i am using drf-nested-routers for ease of writing & maintaing these nested resources.
I want output of all my endpoints have hyperlink for getting details of each nested resource alongwith other details like this:
[
{
"url" : "http://localhost:8000/users/1",
"first_name" : "Name1",
"last_name": "Lastname"
"email" : "name1#xyz.com",
"mails": [
{
"url": "http://localhost:8000/users/1/mails/1",
"extra_data": "This is a extra data",
"mail":{
"url": "http://localhost:8000/mails/3"
"to" : "abc#xyz.com",
"from": "name1#xyz.com",
"subject": "This is a subject text",
"message": "This is a message text"
}
},
{
..........
}
..........
]
}
.........
]
To do this, i write my serializers by inherit HyperlinkedModelSerializer as per DRF docs, which automatically adds a url field in response during serialization.
But, by default DRF serializers does not support generation of url for nested resource like above mentioned or we can say more than single lookup field. To handle this situation, they recommended to create custom hyperlinked field.
I followed this doc, and write custom code for handling url generation of nested resource. My code snippets are as follows:
models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
# User model
class User(models.AbstractUser):
mails = models.ManyToManyField('Mail', through='UserMail',
through_fields=('user', 'mail'))
# Mail model
class Mail(models.Model):
to = models.EmailField()
from = models.EmailField()
subject = models.CharField()
message = models.CharField()
# User Mail model
class UserMail(models.Model):
user = models.ForeignKey('User')
mail = models.ForeignKey('Mail')
extra_data = models.CharField()
serializers.py
from rest_framework import serializers
from .models import User, Mail, UserMail
from .serializers_fields import UserMailHyperlink
# Mail Serializer
class MailSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Mail
fields = ('url', 'to', 'from', 'subject', 'message' )
# User Mail Serializer
class UserMailSerializer(serializers.HyperlinkedModelSerializer):
url = UserMailHyperlink()
mail = MailSerializer()
class Meta:
model = UserMail
fields = ('url', 'extra_data', 'mail')
# User Serializer
class UserSerializer(serializers.HyperlinkedModelSerializer):
mails = UserMailSerializer(source='usermail_set', many=True)
class Meta:
model = User
fields = ('url', 'first_name', 'last_name', 'email', 'mails')
serializers_fields.py
from rest_framework import serializers
from rest_framework.reverse import reverse
from .models import UserMail
class UserMailHyperlink(serializers.HyperlinkedRelatedField):
view_name = 'user-mail-detail'
queryset = UserMail.objects.all()
def get_url(self, obj, view_name, request, format):
url_kwargs = {
'user_pk' : obj.user.pk,
'pk' : obj.pk
}
return reverse(view_name, kwargs=url_kwargs, request=request,
format=format)
def get_object(self, view_name, view_args, view_kwargs):
lookup_kwargs = {
'user_pk': view_kwargs['user_pk'],
'pk': view_kwargs['pk']
}
return self.get_queryset().get(**lookup_kwargs)
views.py
from rest_framework import viewsets
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from .models import User, UserMail
from .serializers import UserSerializer, MailSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
class UserMailViewSet(viewsets.ViewSet):
queryset = UserMail.objects.all()
serializer_class = UserMailSerializer
def list(self, request, user_pk=None):
mails = self.queryset.filter(user=user_pk)
serializer = self.serializer_class(mails, many=True,
context={'request': request}
)
return Response(serializer.data)
def retrieve(self, request, pk=None, user_pk=None):
queryset = self.queryset.filter(pk=pk, user=user_pk)
mail = get_object_or_404(queryset, pk=pk)
serializer = self.serializer_class(mail,
context={'request': request}
)
return Response(serializer.data)
urls.py
from rest_framework.routers import DefaultRouter
from rest_framework_nested import routers
from django.conf.urls import include, url
import views
router = DefaultRouter()
router.register(r'users', views.UserViewSet, base_name='user')
user_router = routers.NestedSimpleRouter(router, r'users',
lookup='user'
)
user_router.register(r'mails', views.UserMailViewSet,
base_name='user-mail'
)
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^', include(user_router.urls)),
]
Now, after doing this when i run a project and ping /users/ api endpoint, i got this error:
AttributeError : 'UserMail' object has no attribute 'url'
I couldn't understand why this error came, because in UserMailSerializer i added url field as a attribute of this serializer, so when it has to serialize why it takes url field as a attribute of UserMail model.
Please help me out to get away from this problem.
P.S: Please don't suggest any refactoring in models. As, here i just disguised my project real idea with user & mail thing. So, take this as test case and suggest me a solution.
I just needed to do something similar lately. My solution ended up making a custom relations field. To save space, Ill simply (and shamelessly) will point to the source code. The most important part is adding lookup_fields and lookup_url_kwargs class attributes which are used internally to both lookup objects and construct the URIs:
class MultiplePKsHyperlinkedIdentityField(HyperlinkedIdentityField):
lookup_fields = ['pk']
def __init__(self, view_name=None, **kwargs):
self.lookup_fields = kwargs.pop('lookup_fields', self.lookup_fields)
self.lookup_url_kwargs = kwargs.pop('lookup_url_kwargs', self.lookup_fields)
...
That in turn allows the usage like:
class MySerializer(serializers.ModelSerializer):
url = MultiplePKsHyperlinkedIdentityField(
view_name='api:my-resource-detail',
lookup_fields=['form_id', 'pk'],
lookup_url_kwargs=['form_pk', 'pk']
)
Here is also how I use it source code.
Hopefully that can get you started.