与(动态)列表相比,如何使用关系字段过滤查询集
How to filter a QuerySet with relation fields compared to a (dynamic) list
我有一个请求模型,它与其 RequestDetails 具有一对多关系。我还有一个与 auth.user
具有一对一关系的 RequestFilter。我想要做的是在通用 ListView 中显示所有请求,其中至少有一个 RequestDetail 具有由 RequestFilter 设置启用的类别。我尝试以不同的方式完成此操作,但仍然以 "Relation fields do not support nested lookups" 错误 告终。这是我所做的:
指定模型:
用户根据以下 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'
我有一个基于 class 的通用 ListView,它应该显示包含至少一个 RequestDetail 的所有请求,该 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)
但这引发了一个关系字段不支持嵌套查找错误。
感谢 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
如果涉及大量数据,就效率而言,这可能不是最佳解决方案。
我有一个请求模型,它与其 RequestDetails 具有一对多关系。我还有一个与 auth.user
具有一对一关系的 RequestFilter。我想要做的是在通用 ListView 中显示所有请求,其中至少有一个 RequestDetail 具有由 RequestFilter 设置启用的类别。我尝试以不同的方式完成此操作,但仍然以 "Relation fields do not support nested lookups" 错误 告终。这是我所做的:
指定模型:
用户根据以下 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'
我有一个基于 class 的通用 ListView,它应该显示包含至少一个 RequestDetail 的所有请求,该 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)
但这引发了一个关系字段不支持嵌套查找错误。
感谢 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
如果涉及大量数据,就效率而言,这可能不是最佳解决方案。