我想要一个具有各自任务的用户列表,并过滤任务开始日期。
# 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',
)
Viewsets :
# 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)
调用此网址时:
/ API /用户/ listCalendar / start__gte = 2015-07-02&安培; start__lt = 2015年8月10日
过滤器被忽略,我无法找到使其工作的方法。
我有直觉认为问题出在ViewSet中的Mission.objects.all()
,应该是这样的:Mission.objects.filter(*But what here?*)
非常感谢任何帮助!
有一些进步!但仍然没有工作......正如你建议Mark Galloway我试着调用以下网址:
/ API /用户/ listCalendar / missions__start__gte = 2015-07-02&安培; missions__start__lt = 2015年8月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个过滤字段视为在单独的表中。结果是我的结果是重复的。
答案 0 :(得分:3)
这里有三件事
首先,您the DjangoFilterBackend
中遗漏了filter_backends
list。这是告诉Django REST框架查看filter_class
并将相关过滤应用于请求的内容,如果没有它,您的filter_class
将被忽略(如您所见)。
class UserViewset(viewsets.ModelViewSet):
filter_backends = (filters.OrderingFilter, filters.DjangoFilterBackend, )
filter_class = UserFilter
serializer_class = UserSerializer
其次,您希望能够使用start
和end
查询参数,但是告诉django-filter查看missions__start
中的Meta.fields
字段}。您可以通过使用别名
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(如上所示)或在.distinct()
过滤器调用的末尾添加filter_queryset
来解决此问题。
答案 1 :(得分:2)
我建议你反过来这样做,然后处理 其余的客户方。即。
首先发送过滤任务的请求,引用其用户的ID
然后发送对引用用户的请求,即“#id__in = 1,2,3”
...或,如果您只有少量用户:向所有用户发送请求
话虽这么说,我想如果你愿意,你也可以通过自己的方式 通过扩展filter_queryset
将过滤器应用于任务请注意,如果您不想过滤嵌套任务,您可以简单地完成 从类中删除filter_queryset方法。
class MissionFilter(django_filters.FilterSet):
class Meta:
model = Mission
fields = {
'start': ['gte', 'lt'],
'end': ['gte', 'lt'],
}
class UserFilter(django_filters.FilterSet):
class Meta:
model = MyUser
fields = {
'start': ['gte', 'lt'],
'end': ['gte', 'lt'],
}
class UserViewset(viewsets.ModelViewSet):
filter_backends = (filters.OrderingFilter, filters.DjangoFilterBackend,)
filter_class = UserFilter
serializer_class = UserSerializer
def get_queryset(self):
# Get the original queryset:
qs = super(UserViewset, self).get_queryset()
# * Annotate:
# * start = the start date of the first mission
# * end = the end date of the last mission
# * Make sure, we don't get duplicate values by adding .distinct()
return qs.annotate(start=models.Min('missions__start'),
end=models.Max('missions__end')).distinct()
def filter_queryset(self, queryset):
# Get the original queryset:
qs = super(UserViewset, self).filter_queryset(queryset)
# Apply same filters to missions:
mqs = MissionFilter(self.request.query_params,
queryset=Missions.objects.all()).qs
# Notice: Since we "start", and "end" in the User queryset,
# we can apply the same filters to both querysets
return qs.prefetch_related(Prefetch('missions', queryset=mqs))
这样您就可以使用您已经使用的相同查询参数。
class MissionFilter(django_filters.FilterSet):
class Meta:
model = Mission
fields = {
'start': ['gte', 'lt'],
'end': ['gte', 'lt'],
}
class UserFilter(django_filters.FilterSet):
class Meta:
model = MyUser
fields = {
'missions__start': ['gte', 'lt'],
'missions__end': ['gte', 'lt'],
}
class UserViewset(viewsets.ModelViewSet):
filter_backends = (filters.OrderingFilter, filters.DjangoFilterBackend,)
filter_class = UserFilter
serializer_class = UserSerializer
queryset = MyUser.objects.all().distinct()
def filter_queryset(self, queryset):
# Get the original queryset:
qs = super(UserViewset, self).filter_queryset(queryset)
# Create a copy of the query_params:
query_params = self.request.GET.copy()
# Check if filtering of nested missions is requested:
if query_params.pop('filter_missions', None) == None:
return qs
# Find and collect missions filters with 'missions__' removed:
params = {k.split('__', 1)[1]: v
for k, v in query_params.items() if k.startswith('missions__')}
# Create a Mission queryset with filters applied:
mqs = MissionFilter(params, queryset=Missions.objects).qs.distinct()
return qs.prefetch_related(Prefetch('missions', queryset=mqs))
我还没有测试过这些,所以得到一些反馈会很酷。
答案 2 :(得分:0)
您的filter_class被忽略,因为您没有在filter_backends中声明DjangoFilterBackend。
class UserViewset(viewsets.ModelViewSet):
filter_backends = (filters.OrderingFilter, filters.DjangoFilterBackend)
filter_class = UserFilter
既然你有一个OrderingFilter但没有排序字段,也许你放错了后端?
答案 3 :(得分:-1)
我猜你的任务是Mission.objects.filter(id = self.request.user),你将获得当前用户的所有任务