[PYTHON] List method for nested resources in Django REST framework

I was told by an API that uses the Django REST framework that "return a list of nested resources", so I objected to "the standard design of the REST API is ...", but I haven't done it so I made it. A note of the time.

environment

Python 3.8.2 Django 3.0.5 djangorestframework 3.11.0

model

Parent ├ Child1 └ Child2 ↑ In the case of a model with such a relationship

models.py


from django.db import models

class Parent(models.Model):
    """
Parent model
    """
    parent_column = models.CharField(
        max_length=10, verbose_name='Parent model column')

    def __self__(self):
        return self.parent_column

class Child1(models.Model):
    """
Child model 1
    """
    # related_Match name with serializer field name
    parent = models.ForeignKey(Parent, on_delete=models.CASCADE, related_name='child1s')
    child1_column = models.CharField(
        max_length=10, verbose_name='Column of child model 1')

    def __self__(self):
        return self.Child1_column

class Child2(models.Model):
    """
Child model 2
    """
    # related_Match name with serializer field name
    parent = models.ForeignKey(Parent, on_delete=models.CASCADE, related_name='child2s')
    child2_column = models.CharField(
        max_length=10, verbose_name='Column of child model 2')

    def __self__(self):
        return self.Child2_column

Serializer

With the same configuration as the model

models.py


from rest_framework import serializers
from .models import Parent, Child1, Child2

class Child1Serializer(serializers.ModelSerializer):
    """
Children's serializer1
    """
    class Meta:
        model = Child1
        fields = [
            'id',
            'child1_column',
        ]

class Child2Serializer(serializers.ModelSerializer):
    """
Children's serializer2
    """
    class Meta:
        model = Child2
        fields = [
            'id',
            'child2_column',
        ]

class ParentSerializer(serializers.ModelSerializer):
    """
Parent serializer
    """
    #Define child serializer as parent field
    #This field name and model related_Match name
    child1s = Child1Serializer(many=True, read_only=True)
    child2s = Child2Serializer(many=True, read_only=True)

    class Meta:
        model = Parent
        fields = [
            'id',
            'parent_column',
            'child1s',
            'child2s',
        ]

View

It seems better to define QuerySet with get_queryset () so that it will be easier to mess with later.

views.py


from rest_framework import generics
from rest_framework.pagination import PageNumberPagination

from .models import Parent
from .serializer import ParentSerializer

class NestedListView(generics.ListAPIView):
    """
List method for nested resources
I want to use only list, so generics.Use ListAPIView
    """
    pagination_class = PageNumberPagination
    serializer_class = ParentSerializer
    #Query-Convert parameters to filter search criteria dict
    CONDITION_KEYS = {
        'parent_column': 'parent_column__contains',
        'child1_column': 'child1s__child1_column__contains',
        'child2_column': 'child2s__child2_column__contains',
        }

    def get_queryset(self):
        """
You may end up writing a complicated QuerySet later, so
Define it in a place where you can go.
        """
        #Search condition dict
        condition_dict = {}
        for key, val in self.request.query_params.items():
            # query_If there is a search condition item in the key of params, convert it to the key for filter
            if key in self.CONDITION_KEYS:
                condition_dict[self.CONDITION_KEYS[key]] = val

        queryset = Parent.objects.filter(**condition_dict).order_by('id').prefetch_related().distinct()

        return queryset

    def list(self, request, *args, **kwargs):
        """
Override list method
        """
        #Apply pagination to queryset
        page_qs = self.paginate_queryset(self.get_queryset())
        #Get serialize
        serializer = self.get_serializer(page_qs, many=True)
        #Return with pagination
        return self.get_paginated_response(serializer.data)

API execution result

Like this NestedListAPI.png

It was easy.

Source

https://github.com/ping2shi2/DRF-sample

References

-DRF Official Documentation

I think I saw something else, but I forgot ...

Recommended Posts

List method for nested resources in Django REST framework
Logical deletion in Django, DRF (Django REST Framework)
Implement JWT login functionality in Django REST framework
Implementing authentication in Django REST Framework with djoser
Django REST framework basics
Django Rest Framework Tips
Learning notes for the migrations feature in the Django framework (3)
Learning notes for the migrations feature in the Django framework (1)
Implement hierarchical URLs with drf-nested-routers in Django REST framework
Django REST framework stumbling block
Django REST framework with Vue.js
Login with django rest framework
How to write custom validations in the Django REST Framework
List method argument information for classes and modules in Python
Implementation of JWT authentication functionality in Django REST Framework using djoser
[Django] Use MessagePack with Django REST framework
Implementation of custom user model authentication in Django REST Framework with djoser
How to deal with garbled characters in json of Django REST Framework
Create RESTful APIs with Django Rest Framework
Understand the benefits of the Django Rest Framework
ng-admin + Django REST framework ready-to-create administration tool
CRUD GET with Nuxt & Django REST Framework ②
Change the list in a for statement
Same-Site attribute setting for cookies in Django
CRUD POST with Nuxt & Django REST Framework
Description method for reusing variables in shellscript
CRUD GET with Nuxt & Django REST Framework ①
Get query parameters for GET requests in Django
Django REST Framework + Clean Architecture Design Consideration
How to get people to try out django rest framework features in one file
CRUD PUT, DELETE with Nuxt & Django REST Framework
Django REST framework A little useful to know.
How to create a Rest Api in Django
Do an ambiguous search for mysql in Django