gpt4 book ai didi

Django get_next_by_FIELD 使用复杂的 Q 查找

转载 作者:行者123 更新时间:2023-12-05 06:42:54 26 4
gpt4 key购买 nike

在为 Django 模块创建前端时,我在 Django 核心中遇到了以下问题:

为了从模型查询中显示指向下一个/上一个对象的链接,我们可以使用 extra-instance-methods模型实例的:get_next_by_FIELD()get_previous_by_FIELD()。其中 FIELD 是 DateField 或 DateTimeField 类型的模型字段。

让我们用一个例子来解释它

from django.db import models

class Shoe(models.Model):
created = models.DateTimeField(auto_now_add=True, null=False)
size = models.IntegerField()

显示鞋子列表的 View ,不包括尺码等于 4 的鞋子:

def list_shoes(request):
shoes = Shoe.objects.exclude(size=4)

return render_to_response(request, {
'shoes': shoes
})

并让下面的 View 显示一只鞋和相应的链接到上一只和下一只鞋子。

def show_shoe(request, shoe_id):
shoe = Shoe.objects.get(pk=shoe_id)

prev_shoe = shoe.get_previous_by_created()
next_shoe = shoe.get_next_by_created()

return render_to_response('show_shoe.html', {
'shoe': shoe,
'prev_shoe': prev_shoe,
'next_shoe': next_shoe
})

现在,无论鞋子尺码如何,show_shoe View 都会显示指向上一个/下一个的链接。但实际上我只想要尺码不是 4 的鞋子。因此,我尝试使用 get_(previous|next)_by_created() 方法的 **kwargs 参数来过滤掉不需要的鞋子,如文档所述:

Both of these methods will perform their queries using the default manager for the model. If you need to emulate filtering used by a custom manager, or want to perform one-off custom filtering, both methods also accept optional keyword arguments, which should be in the format described in Field lookups.

编辑:注意“应该”这个词,因为那样 (size_ne=4) 也应该起作用,但它不起作用。

实际问题

使用查找大小过滤__ne ...

def show_shoe(request, shoe_id):
...
prev_shoe = shoe.get_previous_by_created(size__ne=4)
next_shoe = shoe.get_next_by_created(size__ne=4)
...

... 无效,它抛出 FieldError:无法将关键字“size_ne”解析为字段。

然后我尝试使用否定的 complex lookup使用 Q 对象:

from django.db.models import Q

def show_shoe(request, shoe_id):
...
prev_shoe = shoe.get_previous_by_created(~Q(size=4))
next_shoe = shoe.get_next_by_created(~Q(size=4))
...

... 也没有用,抛出 TypeError:_get_next_or_previous_by_FIELD() got multiple values for argument 'field'

因为 get_(previous|next)_by_created 方法只接受 **kwargs。

实际解决方案

由于这些实例方法使用 _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs)我将其更改为使用 *args 接受位置参数并将它们传递给过滤器,例如 **kwargs。

def my_get_next_or_previous_by_FIELD(self, field, is_next, *args, **kwargs):
"""
Workaround to call get_next_or_previous_by_FIELD by using complext lookup queries using
Djangos Q Class. The only difference between this version and original version is that
positional arguments are also passed to the filter function.
"""
if not self.pk:
raise ValueError("get_next/get_previous cannot be used on unsaved objects.")
op = 'gt' if is_next else 'lt'
order = '' if is_next else '-'
param = force_text(getattr(self, field.attname))
q = Q(**{'%s__%s' % (field.name, op): param})
q = q | Q(**{field.name: param, 'pk__%s' % op: self.pk})
qs = self.__class__._default_manager.using(self._state.db).filter(*args, **kwargs).filter(q).order_by('%s%s' % (order, field.name), '%spk' % order)
try:
return qs[0]
except IndexError:
raise self.DoesNotExist("%s matching query does not exist." % self.__class__._meta.object_name)

这样调用它:

...
prev_shoe = shoe.my_get_next_or_previous_by_FIELD(Shoe._meta.get_field('created'), False, ~Q(state=4))
next_shoe = shoe.my_get_next_or_previous_by_FIELD(Shoe._meta.get_field('created'), True, ~Q(state=4))
...

终于做到了。

现在给你的问题

有没有更简单的方法来处理这个问题? shoe.get_previous_by_created(size__ne=4) 应该按预期工作还是我应该向 Django 人员报告这个问题,希望他们会接受我的 _get_next_or_previous_by_FIELD() 修复?

环境:Django 1.7,尚未在 1.9 上进行测试,但 _get_next_or_previous_by_FIELD() 的代码保持不变。

编辑: 的确,使用 Q 对象的复杂查找不是“字段查找”的一部分,它更多地是 filter() 和 exclude() 函数的一部分。当我认为 get_next_by_FIELD 也应该接受 Q 对象时,我可能错了。但由于涉及的更改很少,而且使用 Q 对象的优势很大,我认为这些更改应该上游。

标签:django、复杂查找、查询、get_next_by_FIELD、get_previous_by_FIELD

(在这里列出标签,因为我没有足够的声誉。)

最佳答案

您可以创建 custom lookup ne并使用它:

.get_next_by_created(size__ne=4)

关于Django get_next_by_FIELD 使用复杂的 Q 查找,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35602780/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com