Как фильтровать отношения "один ко многим" с помощью django rest api?

У меня есть отношения типа "один-ко-многим":

class Category(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(max_length=100)   
    images = models.ImageField(upload_to="photos/categories")
    category = models.ForeignKey("Category", on_delete=models.CASCADE, related_name='part_of', blank=True, null=True)
    date_create = models.DateTimeField(auto_now_add=True)
    date_update = models.DateTimeField(auto_now=True)
    description = models.TextField(max_length=1000, blank=True)
    legislation = models.TextField(max_length=1000, blank=True)
    review = models.TextField(max_length=   000, blank=True)
    eaza  = models.TextField(max_length=1000, blank=True)

    class Meta:
        verbose_name = "category"
        verbose_name_plural = "categories"

    def __str__(self):
        return self.name


class Animal(models.Model):
    name = models.CharField(max_length=100)
    slug = models.SlugField(max_length=100)  
    images = models.ImageField(upload_to="photos/categories")
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='animals')
    date_create = models.DateTimeField(auto_now_add=True)
    date_update = models.DateTimeField(auto_now=True)
    description = models.TextField(max_length=1000, blank=True)
    legislation = models.TextField(max_length=1000, blank=True)
    review = models.TextField(max_length=1000, blank=True)
    eaza  = models.TextField(max_length=1000, blank=True)

    class Meta:
        verbose_name = "animal"
        verbose_name_plural = "animals"

    def __str__(self):
        return self.name

и сериализатор:

class AnimalSerializer(serializers.ModelSerializer):
    class Meta:
        model = Animal
        fields = ['id','category_id','name', 'description']


class CategorySerializer(serializers.ModelSerializer):
    animals = AnimalSerializer(many=True)
    
    class Meta:
        model = Category
        fields = ['id','category_id','name', 'description', 'animals']

и urls:

from . import views
urlpatterns = [
    path('', CategoryViewSet.ApiOverview, name='home'),
    path('all/', views.view_items, name='view_items'),
    path('all/<int:id>/', views.detail_item ),
]

views.py:

@api_view(['GET'])
def view_items(request):
    
    queryset = Category.objects.all() 
    serializer = CategorySerializer(queryset, many=True)
    
    # checking for the parameters from the URL
    if request.query_params:
        items = Category.objects.filter(**request.query_params.dict())
        serializer = CategorySerializer(items , many=True)
    else:
        items= Category.objects.all() 
        serializer = CategorySerializer(items , many=True)
  
    # if there is something in items else raise error
    if items:       
        return Response(serializer.data)
    else:
        return Response(status=status.HTTP_404_NOT_FOUND)

Например, если я сделаю следующее: http://127.0.0.1:8000/djangoadmin/all/?name=cobra

[
    {
        "id": 28,
        "category_id": 22,
        "name": "cobra",
        "description": "cobra",
        "animals": [
            {
                "id": 4,
                "category_id": 28,
                "name": "indian",
                "description": "cobra"
            },
            {
                "id": 5,
                "category_id": 28,
                "name": "cape cobra",
                "description": "cape cobra"
            },
            {
                "id": 6,
                "category_id": 28,
                "name": "Chinese cobra",
                "description": "Chinese cobra"
            }
        ]
    }
]

Но, конечно, мне нужен только массив в животных:

{
                "id": 4,
                "category_id": 28,
                "name": "indian",
                "description": "cobra"
            },
            {
                "id": 5,
                "category_id": 28,
                "name": "cape cobra",
                "description": "cape cobra"
            },
            {
                "id": 6,
                "category_id": 28,
                "name": "Chinese cobra",
                "description": "Chinese cobra"
            }

Но, например, если я сделаю следующее: http://127.0.0.1:8000/djangoadmin/all/?category_id=28

Я получаю:

HTTP 404 Not Found

Вопрос: как вернуть только дочерние элементы?

Данные дочерних элементов и родительских элементов приходят из-за вашего сериализатора

@api_view(['GET'])
def view_items(request):
    
    queryset = Category.objects.all() 
    serializer = CategorySerializer(queryset, many=True)
    
    # checking for the parameters from the URL
    if request.query_params:
        items = Animal.objects.filter(**request.query_params.dict())
        serializer = AnimalSerializer(items , many=True)# note here i'm using AnimalSerializer to see only child items
    else:
        items= Category.objects.all() 
        serializer = CategorySerializer(items , many=True)
  
    # if there is something in items else raise error
    if items:       
        return Response(serializer.data)
    else:
        return Response(status=status.HTTP_404_NOT_FOUND)

Вы также можете сделать - фильтрует кверисет Category на основе параметров запроса, затем фильтрует кверисет Animal на основе category_id первого элемента в фильтрованном кверисете Category. Наконец, он сериализует отфильтрованный кверисет Animal и возвращает его в ответе.

@api_view(['GET'])
def view_items(request):
    
    queryset = Category.objects.all() 
    serializer = CategorySerializer(queryset, many=True)
    
    if request.query_params:
        items = Category.objects.filter(**request.query_params.dict())
        serializer = CategorySerializer(items , many=True)
    else:
        items = Category.objects.all() 
        serializer = CategorySerializer(items , many=True)
  
    if items:       
        # Filter the animals based on the category_id of the parent category
        animal_queryset = Animal.objects.filter(category_id=items[0].id)
        animal_serializer = AnimalSerializer(animal_queryset, many=True)
        return Response(animal_serializer.data)
    else:
        return Response(status=status.HTTP_404_NOT_FOUND)
Вернуться на верх