基于动态属性的django查询()

时间:2011-01-21 00:38:47

标签: python django django-queryset

我想知道是否有办法使用property()使用动态生成的python属性在查询集上使用Django的filter()。我有first_namelast_name的每个用户,我想根据其连接的名称first_name last_name进行过滤。 (这背后的原因是,当我进行自动填充时,我会搜索查询是否与名字,姓氏或部分串联匹配。我希望John S匹配John Smith,例如。< / p>

我创建了name

的属性
def _get_name(self):
    return self.first_name + " " + self.last_name
    name = property(_get_name)

这样我就可以调用user.name来获取连接名称。

但是,如果我尝试User.objects.filter(name__istartswith=query),我会收到错误Cannot resolve keyword 'name' into field.

关于如何做到这一点的任何想法?我是否必须在数据库中创建另一个字段来存储全名?

4 个答案:

答案 0 :(得分:13)

接受的答案并非完全正确。

在许多情况下,您可以在模型管理器中将get()覆盖为关键字参数的pop动态属性,然后将要查询的实际属性添加到kwargs关键字中参数字典。请务必返回super,以便定期get()次调用返回预期结果。

我只是粘贴我自己的解决方案,但对于__startswith和其他条件查询,您可以向split添加一些逻辑双下划线并正确处理。

以下是我的解决方法,允许通过动态属性进行查询:

class BorrowerManager(models.Manager):
    def get(self, *args, **kwargs):
        full_name = kwargs.pop('full_name', None)
        # Override #1) Query by dynamic property 'full_name'
        if full_name:
            names = full_name_to_dict(full_name)
            kwargs = dict(kwargs.items() + names.items())
        return super(BorrowerManager, self).get(*args, **kwargs)

在models.py中:

class Borrower(models.Model):
    objects = BorrowerManager()

    first_name = models.CharField(null=False, max_length=30)
    middle_name = models.CharField(null=True, max_length=30)
    last_name = models.CharField(null=False, max_length=30)
    created = models.DateField(auto_now_add=True)

在utils.py中(为了上下文):

def full_name_to_dict(full_name):
    ret = dict()
    values = full_name.split(' ')
    if len(values) == 1:
        raise NotImplementedError("Not enough names to unpack from full_name")
    elif len(values) == 2:
        ret['first_name'] = values[0]
        ret['middle_name'] = None
        ret['last_name'] = values[1]
        return ret
    elif len(values) >= 3:
        ret['first_name'] = values[0]
        ret['middle_name'] = values[1:len(values)-1]
        ret['last_name'] = values[len(values)-1]
        return ret
    raise NotImplementedError("Error unpacking full_name to first, middle, last names")

答案 1 :(得分:9)

filter()在数据库级别上运行(它实际上是在编写SQL),因此不可能将它用于基于python代码(dynamic property in your question)的任何查询。

这是该部门许多其他答案的答案:)

答案 2 :(得分:3)

我有类似的问题,正在寻找解决方案。理所当然地认为搜索引擎是最好的选择(例如django-haystackElasticsearch),这就是我如何仅使用Django ORM为您的需求实现一些代码(您可以替换{{1} } icontains}:

istartswith

就我而言,我不知道用户是否会插入“from django.db.models import Value from django.db.models.functions import Concat queryset = User.objects.annotate(full_name=Concat('first_name', Value(' '), 'last_name') return queryset.filter(full_name__icontains=value) first_name”或反之,所以我使用了以下代码。

last_name

使用Django&lt; 1.8,您可能需要使用SQL from django.db.models import Q, Value from django.db.models.functions import Concat queryset = User.objects.annotate(first_last=Concat('first_name', Value(' '), 'last_name'), last_first=Concat('last_name', Value(' '), 'first_name')) return queryset.filter(Q(first_last__icontains=value) | Q(last_first__icontains=value)) 函数求助extra,如下所示:

CONCAT

答案 3 :(得分:0)

认为在django中不可能过滤不作为数据库字段存在的属性,但是你可以做些什么来制作很酷的自动完成搜索是这样的:

if ' ' in query:
    query = query.split()
    search_results = list(chain(User.objects.filter(first_name__icontains=query[0],last_name__icontains=query[1]),
                                    User.objects.filter(first_name__icontains=query[1],last_name__icontains=query[0])))
else:
    search_results =  User.objects.filter(Q(first_name__icontains=query)| Q(last_name__icontains=query))

此代码为您的系统用户提供了开始输入名字或姓氏的灵活性,用户会感谢您允许这样做。