Как фильтровать отношения "один ко многим" с помощью 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)