I'm currently developing a Web App that uses an API as the backend for a University Project.
And I've read that DRF is the fastest and easiest way to develop and deploy an API, I already followed through their entire official
documentation and I don't seem to understand how I could the following in their ViewSet and Serializer.
Here's one endpoint of my API called airports.
Returns json/csv list of links to the available airports in the USA.
URL
/airports
Method:
GET
Success Response:
[
{
"airport": {
"code": "PHL",
"name": "Philadelphia, PA: Philadelphia International",
"id": 123,
"url": "/airports/123"
},
{
"airport": {
"code": "AHR",
"name": "American Hour Rapid",
"id": 125,
"url": "/airports/125"
}
.
.
.
]
Returns all links to the carriers operating at a specific airport, a link to the related statistics on a specific month and year and also a link to the airport routes. If in case neither the year or the month are specified, the default will be the one with the most recent date.
/airports/:id
GET
URL Params
Required:
id=[integer]
Success Response:
{
"airport": {
"code": "PHL",
"name": "Philadelphia, PA: Philadelphia International",
"id": 123,
"url": "/airports/123"
},
"routes_link": "/airports/123/routes",
"carriers": [
{
"id": 124,
"url": "/carriers/124?airport_id=123",
"statistics_url":"/airports/1carrier=124&statistics='flights'"
},
.
.
.
]
}
I was able to do /airports properly listing all of the available airports in the database but when using the ViewSet I don't know how to "customize" the response when trying to retrieve information about only one airport specified by the id and in the application the routes are going to be generated dynamically and I was planning to add to the response body and not another field in the model.
Models:
class Carrier(models.Model):
code = models.CharField(max_length=10)
name = models.TextField()
#airports = models.ManyToManyField(Airport)
def __str__(self):
return self.name
class Airport(models.Model):
code = models.CharField(max_length=10)
name = models.TextField()
carriers = models.ManyToManyField(Carrier, related_name='airports')
def __str__(self):
return self.name
Serializers:
class AirportSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Airport
fields = ('id', 'name', 'code', 'url')
class CarrierSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Carrier
fields = ('id', 'name', 'code', 'url')
View:
class AirportList(viewsets.ModelViewSet):
queryset = models.Airport.objects.all()
serializer_class = AirportSerializer
# @Override something here?
Anyone has a tip on how I could approach this using DRF or any kind of learning material I could use?
If you want to modified retrieve
functionality of ModelViewset you can overwrite its retrieve
method and do what ever you want. mixin's
link
class AirportList(viewsets.ModelViewSet):
queryset = models.Airport.objects.all()
serializer_class = AirportSerializer
def retrieve(self, request, *args, **kwargs):
# do your customization here
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
I think best way to look after any new thing is their codebase. For ModelViewset you should start from views
link and explore what are the functionality it provide and how i can customize them.
as @Shakil mentioned above you need to overwrite retrieve
method, but to make a custom response you need to include self.get_object()
in a Try Except
block, as without it if get_object
fails it would fallback to the default response and won't have the chance to custom it.
So you can use something like that...
First the custom response class (for failing cases for example)
class ErrorResponse(Response):
def __init__(self, *args, **kwargs):
super(ErrorResponse,self).__init__(*args, **kwargs)
self.status_code = 404
self.data = {
'success': False,
'message': args[0].get('message')
}
and the retrieve
method
def retrieve(self, request, *args, **kwargs):
try:
instance = self.get_object()
except Exception as e:
return ErrorResponse({'message':str(e)})
else:
#any additional logic
serializer = self.get_serializer(instance)
return Response({'data': serializer.data})
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