
我想要一个具有各自任务的用户列表,并按任务开始日期过滤.
# Pseudo json
User 1
- mission 1
- mission 2
User 2
- mission 1
- mission 2
- mission 3
我的数据结构:
楷模:
class Mission(models.Model):
start = models.DateTimeField()
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="missions")
序列化器:
# Mission
class MissionSerializer(serializers.ModelSerializer):
class Meta:
model = Mission
fields = (
'start',
'end',
)
# User
class UserSerializer(serializers.ModelSerializer):
missions = MissionSerializer(many=True)
class Meta:
model = MyUser
fields = (
'username',
'missions',
)
视图集:
# Filter
class UserFilter(django_filters.FilterSet):
class Meta:
model = MyUser
fields = {
'missions__start': ['gte','lt']
}
# Viewset
class UserViewset(viewsets.ModelViewSet):
filter_backends = (filters.OrderingFilter, filters.DjangoFilterBackend,)
filter_class = UserFilter
serializer_class = UserSerializer
@list_route(methods=['get'])
def listCalendar(self, request):
prefetched_missions = Prefetch('missions', queryset=Mission.objects.all())
objects_list = MyUser.objects.prefetch_related( prefetched_missions )
objects_list = self.filter_queryset(objects_list)
serializer = UserSerializer(objects_list, many=True)
return Response(serializer.data)
我的问题:
调用此URL时:
/api/users/listCalendar/?start__gte=2015-06-29&start__lt=2015-08-10
该过滤器被忽略,我想不出一种使它起作用的方法.
我的直觉是问题在于ViewSet中的Mission.objects.all()应该类似于:Mission.objects.filter(*但是这里是什么?*)
任何帮助将不胜感激!
编辑1:
有一些进步!但是仍然无法正常工作…正如您建议的Mark Galloway一样,我尝试调用以下网址:
/api/users/listCalendar/?missions__start__gte=2015-06-29&missions__start__lt=2015-08-10
但这是要执行的查询:
SELECT "app_myuser"."id", "app_myuser"."username"
FROM "app_myuser"
INNER JOIN "app_mission" ON ( "app_myuser"."id" = "app_mission"."user_id" )
INNER JOIN "app_mission" T4 ON ( "app_myuser"."id" = T4."user_id" )
WHERE ("app_mission"."start" >= '2015-07-06T00:00:00+00:00'::timestamptz
AND T4."start" < '2015-07-12T00:00:00+00:00'::timestamptz)
ORDER BY "app_myuser"."username" ASC;
如您所见,这里有2个INNER JOIN而不是1.由于某些原因,它会将2个过滤后的字段当作在单独的表中.结果是我的结果被复制了.
首先,您的filter_backends list中缺少the DjangoFilterBackend.这就是告诉Django REST框架查看filter_class并将相关过滤应用于请求的原因,否则,您的filter_class将被忽略(如您所见).
class UserViewset(viewsets.ModelViewSet):
filter_backends = (filters.OrderingFilter, filters.DjangoFilterBackend, )
filter_class = UserFilter
serializer_class = UserSerializer
其次,您期望能够使用开始和结束查询参数,但是告诉django-filter查看Meta.fields中的missions__start字段.您可以通过使用别名手动定义FilterSet上的字段来解决此问题
class UserFilter(django_filters.FilterSet):
start_gte = django_filter.DateTimeFilter(name='missions__start', lookup_type='gte', distinct=True)
start_lte = django_filter.DateTimeFilter(name='missions__start', lookup_type='lte', distinct=True)
end_gte = django_filter.DateTimeFilter(name='missions__end', lookup_type='gte', distinct=True)
end_lte = django_filter.DateTimeFilter(missions__name='end', lookup_type='lte', distinct=True)
class Meta:
model = MyUser
fields = ('start_gte', 'start_lte', 'end_gte', 'end_lte', )
或者通过仅引用查询参数将获得完整值(missions__start_gte而不是start_gte).
第三,由于INNER JOIN查询如何跨多个表工作,因此在执行影响单个用户下的多个任务的过滤器时,您将收到重复的值.您可以通过在过滤器中使用the distinct argument(如上所示)或在filter_queryset中的过滤器调用末尾添加.distinct()来解决此问题.
转载注明原文:python-Django Rest Framework-过滤器嵌套一对多 - 乐贴网