如何使用与(动态)列表相比较的关系字段筛选QuerySet

时间:2015-07-21 10:02:45

标签: django django-models django-queryset django-orm

我有一个请求模型,它与RequestDetails有一对多的关系。我还有一个与auth.user具有一对一关系的RequestFilter。我想要做的是在通用ListView中显示所有请求,其中至少有一个RequestDetail具有RequestFilter设置启用的类别。我尝试以不同的方式实现这一目标,但最终仍然以"关系字段不支持嵌套查找"错误即可。这是我做的:

给定模型:

用户根据以下RequestFilter模型在设置菜单中指定他想要接收的请求(不是django user.request):

class RequestFilter(models.Model):
    user = models.OneToOneField(User)
    category1_enabled = models.BooleanField(...)
    category2_enabled = models.BooleanField(...)
    category3_enabled = models.BooleanField(...)
    ...
    def get_categories_enabled(self):
        returns a list of category names which are set to True e.g. ['category1', 'category3']

请求本身包含基本信息和参考代码:

class Requests(models.Model):
    request_id = models.IntegerField(unique=True, ...)
    reference = models.CharField(max_length=10)
    some_general_info = models.CharField(...)
    ... 

一个请求可以有许多RequestDetails(比如有许多产品的订单)

class RequestDetail(models.Model):
    request = models.ForeignKey(Requests, to_field='request_id', related_name='details')
    product_id = models.IntegerField()
    category_id = models.IntegerField()
    ...
    def get_category_name:
        returns the name of the category of the RequestDetail e.g. 'category3'

我有一个基于通用类的ListView,它应该显示所有包含至少一个RequestDetail的请求,该请求属于用户在设置中设置为启用的类别(RequestFilter)。

views.py

class DashManagerRequestsView(generic.ListView):
    template_name = 'dashboard/dashmanagerrequests.html'
    context_object_name = 'request_list'

    def get_categories_enabled(self):
        return self.request.user.requestfilter.get_categories_enabled()

    def get_queryset(self):
        """Returns all requests as an ordered list."""
        requestfilter_list = self.get_categories_enabled()
        return Requests.objects.order_by('-date_add').filter(details__get_category_name__in=requestfilter_list)

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(DashManagerRequestsView, self).dispatch(*args, **kwargs)

我也尝试使用F()表达式,但这不起作用,因为它只比较了SAME模型实例上两个不同字段的值。我得到的最接近的是获取用户的已启用类别的列表,并查找类别名称是否包含此列表的一部分:

return Requests.objects.order_by('-date_add').filter(details__get_category_name__in=requestfilter_list)

但是这会引发关系字段不支持嵌套查找错误

1 个答案:

答案 0 :(得分:1)

谢谢schillingt,他推动我走向正确的方向,我想出了一个解决方案。

由于无法使用模型方法过滤QuerySet,因此通过使用第二个for循环与RequestDetail模型方法相关,在过滤函数外执行期间生成允许id的列表。当然,这也可以使用列表理解或类似的东西来完成:

def get_queryset(self):
    queryset = Requests.objects.order_by('-ps_date_add')
    request_ids = []
    for request in queryset:
        for detail in request.details.all():
            if detail.get_category_name() in self.get_categories_enabled():
                request_ids.append(request.id)
    q = q.filter(id__in=request_ids)
    return q

如果涉及到大量数据,这可能不是效率方面的最佳解决方案。