Let's say I have three models as:
class User(AppModel):
name = models.CharField(max_length=255)
class Business(AppModel):
owner = models.ForeignKey("User", related_name="businesses", on_delete=models.CASCADE)
legal_name = models.CharField(max_length=255)
class Invoice(AppModel):
business = models.ForeignKey("Business", related_name="invoices", on_delete=models.CASCADE)
amount = models.integerField()
As you can see, a user
can have multiple businesses
and a business
can have multiple invoices
.
My serializers.py:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields= ('name')
class BusinessSerializer(serializers.ModelSerializer):
owner = UserSerializer(many=False)
class Meta:
model = Business
fields= ('owner','legal_name')
class InvoiceSerializer(serializers.ModelSerializer):
business= BusinessSerializer(many=False)
class Meta:
model = Invoice
fields= ('business','amount')
views.py:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
class BusinessViewSet(viewsets.ModelViewSet):
queryset = Business.objects.all()
serializer_class = BusinessSerializer
class InvoiceViewSet(viewsets.ModelViewSet):
queryset = Invoice.objects.all()
serializer_class = InvoiceSerializer
urls.py:
router = DefaultRouter()
router.register('user', UserViewSet, base_name='users')
router.register('business', BusinessViewSet, base_name='businesses')
router.register('invoice', InvoiceViewSet, base_name='invoices')
urlpatterns = router.urls
http://example.com/api/user
returns all users. Not a problem.
But the functionality I'm looking for is:
http://example.com/api/business/
returns
[ { "legal_name": "1business", "owner": 1, }, { "legal_name": "2business", "owner": 1, },]
http://example.com/api/business/1/
returns
{ "legal_name": "1business", "owner": 1, }
The above is ok. But I also need:
http://example.com/api/business/1/invoices/
should return
[ { "business": 1, "amount": 100, }, { "business": 1, "amount": 999, },]
As well I should be able to create update delete those invoices there.
Any Help? I'm new to django rest framework. The above classes are just a sample. Ignore errors.
Add additional viewset action
in your BusinessViewSet
as
class BusinessViewSet(viewsets.ModelViewSet):
queryset = Business.objects.all()
serializer_class = BusinessSerializer
and change your urls.py
as,
urlpatterns = [
] + router.urls
You should use django decorators which are @list_route
and @detail_route
for your viewset. But be careful with your DRF version. Because those decorators merged together as @action
in DRF 3.8+. Here is the announcement .
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import status
class BusinessViewSet(viewsets.ModelViewSet):
queryset = Business.objects.all()
serializer_class = BusinessSerializer
@action(detail=True, methods=["GET"], url_path="invoices")
def invoices(self, request, pk=None):
"""
Your codes comes here to return related result.
pk variable contains the param value from url.
if you do not specify the url_path properties then action will accept the function's name as url path.
"""
entity = Invoice.objects.filter(business=pk)
serializer = self.get_serializer(entity, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
Then, you will be able to call this endpoints from;
http://example.com/api/business/{{PK}}/invoices/
http://example.com/api/business/1/invoices/
http://example.com/api/business/3/invoices/
http://example.com/api/business/23/invoices/
Here you can find more details about @actions
from documentation .
PS: Don't forget to control empty entity results in your codes. You should return correct response with correct status codes.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.