如何根据嵌套查询参数过滤 Django Rest Framework 结果
How to filter Django Rest Framework Result based on Nested Query Parameters
我有一个检索所有数据的查询,但我想通过添加查询参数对另一个 url 进行另一个查询,以便定位我的数据搜索。例如,当我请求以下 url:
http://localhost:8000/api/calendars
我有这个结果:
[
{
"id": 1,
"plant_step_id": [
{
"id": 3,
"plant_id": {
"id": 1,
"name": "Agropyre"
},
"step_title": "Sowing"
}
],
"start": [
1
],
"end": [
3
]
},
{
"id": 2,
"plant_step_id": [
{
"id": 6,
"plant_id": {
"id": 6,
"name": "Aubergine"
},
"step_title": "Planting"
}
],
"start": [
6
],
"end": [
7
]
}
]
我想通过请求 url:
http://localhost:8000/api/plant/life/calendars?plant_id=1&step_title=Sowing
我想要有关我在 url 中请求的数据。
我试图在视图中实现这一点,但没有成功。
这是模型:
from django.db import models
from multiselectfield import MultiSelectField
MONTHS = (
(1, 'January'),
(2, 'February'),
(3, 'March'),
(4, 'April'),
(5, 'May'),
(6, 'June'),
(7, 'July'),
(8, 'August'),
(9, 'September'),
(10, 'October'),
(11, 'November'),
(12, 'December')
)
class PlantLifeCalendar(models.Model):
plant_step_id = models.ManyToManyField('perma_plant_steps.PlantStep')
start = MultiSelectField(choices=MONTHS, max_choices=3, max_length=6)
end = MultiSelectField(choices=MONTHS, max_choices=3, max_length=6)
这是序列化程序:
class PlantSerializer(serializers.ModelSerializer):
class Meta:
model = Plant
fields = ('id', 'name',)
class PlantStepSerializer(serializers.ModelSerializer):
plant_id = PlantSerializer()
class Meta:
model = PlantStep
fields = ('id', 'plant_id', 'step_title')
class ReadPlantLifeCalendarSerializer(serializers.ModelSerializer):
plant_step_id = PlantStepSerializer(read_only=True, many=True)
start = fields.MultipleChoiceField(choices=MONTHS)
end = fields.MultipleChoiceField(choices=MONTHS)
class Meta:
model = PlantLifeCalendar
fields = '__all__'
read_only_fields = [fields]
class WritePlantLifeCalendarSerializer(serializers.ModelSerializer):
class Meta:
model = PlantLifeCalendar
fields = '__all__'
视图如下:
class PlantLifeCalendarViewSet(viewsets.ModelViewSet):
# permission_classes = (IsAuthenticated,)
permission_classes = (AllowAnonymous,)
queryset = PlantLifeCalendar.objects.prefetch_related('plant_step_id').all()
def create(self, request, *args, **kwargs):
serializer = WritePlantLifeCalendarSerializer(data=request.data, many=isinstance(request.data, list))
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get_serializer_class(self):
if self.action in ("list", "retrieve"):
return ReadPlantLifeCalendarSerializer
return WritePlantLifeCalendarSerializer
class PlantLifeCalendarLinkAPIView(ListAPIView):
permission_classes = (AllowAnonymous,)
serializer_class = ReadPlantLifeCalendarSerializer
def get_queryset(self):
try:
plant_id = int(self.request.GET.get('plant_id'))
except (ValueError, TypeError):
plant_id = None
step_title = self.request.GET.get('step_title')
params = {}
if plant_id:
params['plant_id'] = plant_id
if step_title:
params['step_title'] = step_title
if params:
return PlantLifeCalendar.objects.filter(**params)
return PlantLifeCalendar.objects.all()
为了使您的示例工作,您需要将 plant_step_id
替换为 plant_step_id__plant_id
,将 step_title
替换为 plant_step_id__step_title
,因为这些嵌套属性属于 PlantStep 而不是 PlantLifeCalendar .
然而,更简单的方法是使用 Django Rest 框架过滤指南。
首先安装pip install django-filter
.
...
from django_filters.rest_framework import DjangoFilterBackend
...
class PlantLifeCalendarLinkAPIView(ListAPIView):
permission_classes = (AllowAnonymous,)
serializer_class = ReadPlantLifeCalendarSerializer
queryset = PlantLifeCalendar.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ['plant_step_id__plant_id', 'plant_step_id__step_title']
这意味着您需要在查询参数中使用 plant_step_id__plant_id
和 plant_step_id__step_title
才能获得所需的结果。
DRF 的条目:https://www.django-rest-framework.org/api-guide/filtering/
我有一个检索所有数据的查询,但我想通过添加查询参数对另一个 url 进行另一个查询,以便定位我的数据搜索。例如,当我请求以下 url:
http://localhost:8000/api/calendars
我有这个结果:
[
{
"id": 1,
"plant_step_id": [
{
"id": 3,
"plant_id": {
"id": 1,
"name": "Agropyre"
},
"step_title": "Sowing"
}
],
"start": [
1
],
"end": [
3
]
},
{
"id": 2,
"plant_step_id": [
{
"id": 6,
"plant_id": {
"id": 6,
"name": "Aubergine"
},
"step_title": "Planting"
}
],
"start": [
6
],
"end": [
7
]
}
]
我想通过请求 url:
http://localhost:8000/api/plant/life/calendars?plant_id=1&step_title=Sowing
我想要有关我在 url 中请求的数据。
我试图在视图中实现这一点,但没有成功。
这是模型:
from django.db import models
from multiselectfield import MultiSelectField
MONTHS = (
(1, 'January'),
(2, 'February'),
(3, 'March'),
(4, 'April'),
(5, 'May'),
(6, 'June'),
(7, 'July'),
(8, 'August'),
(9, 'September'),
(10, 'October'),
(11, 'November'),
(12, 'December')
)
class PlantLifeCalendar(models.Model):
plant_step_id = models.ManyToManyField('perma_plant_steps.PlantStep')
start = MultiSelectField(choices=MONTHS, max_choices=3, max_length=6)
end = MultiSelectField(choices=MONTHS, max_choices=3, max_length=6)
这是序列化程序:
class PlantSerializer(serializers.ModelSerializer):
class Meta:
model = Plant
fields = ('id', 'name',)
class PlantStepSerializer(serializers.ModelSerializer):
plant_id = PlantSerializer()
class Meta:
model = PlantStep
fields = ('id', 'plant_id', 'step_title')
class ReadPlantLifeCalendarSerializer(serializers.ModelSerializer):
plant_step_id = PlantStepSerializer(read_only=True, many=True)
start = fields.MultipleChoiceField(choices=MONTHS)
end = fields.MultipleChoiceField(choices=MONTHS)
class Meta:
model = PlantLifeCalendar
fields = '__all__'
read_only_fields = [fields]
class WritePlantLifeCalendarSerializer(serializers.ModelSerializer):
class Meta:
model = PlantLifeCalendar
fields = '__all__'
视图如下:
class PlantLifeCalendarViewSet(viewsets.ModelViewSet):
# permission_classes = (IsAuthenticated,)
permission_classes = (AllowAnonymous,)
queryset = PlantLifeCalendar.objects.prefetch_related('plant_step_id').all()
def create(self, request, *args, **kwargs):
serializer = WritePlantLifeCalendarSerializer(data=request.data, many=isinstance(request.data, list))
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def get_serializer_class(self):
if self.action in ("list", "retrieve"):
return ReadPlantLifeCalendarSerializer
return WritePlantLifeCalendarSerializer
class PlantLifeCalendarLinkAPIView(ListAPIView):
permission_classes = (AllowAnonymous,)
serializer_class = ReadPlantLifeCalendarSerializer
def get_queryset(self):
try:
plant_id = int(self.request.GET.get('plant_id'))
except (ValueError, TypeError):
plant_id = None
step_title = self.request.GET.get('step_title')
params = {}
if plant_id:
params['plant_id'] = plant_id
if step_title:
params['step_title'] = step_title
if params:
return PlantLifeCalendar.objects.filter(**params)
return PlantLifeCalendar.objects.all()
为了使您的示例工作,您需要将 plant_step_id
替换为 plant_step_id__plant_id
,将 step_title
替换为 plant_step_id__step_title
,因为这些嵌套属性属于 PlantStep 而不是 PlantLifeCalendar .
然而,更简单的方法是使用 Django Rest 框架过滤指南。
首先安装pip install django-filter
.
...
from django_filters.rest_framework import DjangoFilterBackend
...
class PlantLifeCalendarLinkAPIView(ListAPIView):
permission_classes = (AllowAnonymous,)
serializer_class = ReadPlantLifeCalendarSerializer
queryset = PlantLifeCalendar.objects.all()
filter_backends = [DjangoFilterBackend]
filterset_fields = ['plant_step_id__plant_id', 'plant_step_id__step_title']
这意味着您需要在查询参数中使用 plant_step_id__plant_id
和 plant_step_id__step_title
才能获得所需的结果。
DRF 的条目:https://www.django-rest-framework.org/api-guide/filtering/