当前位置: 首页 > 知识库问答 >
问题:

按照行顺序在多个字段中搜索

容宏逸
2023-03-14

我有一个如下的模型:

class Foo(models.Model):
    fruit = models.CharField(max_length=10)
    stuff = models.CharField(max_length=10)
    color = models.CharField(max_length=10)
    owner = models.CharField(max_length=20)
    exists = models.BooleanField()
    class Meta:
        unique_together = (('fruit', 'stuff', 'color'), )

它填充了一些数据:

fruit  stuff  color   owner  exists
Apple  Table   Blue     abc    True
 Pear   Book    Red     xyz   False
 Pear  Phone  Green     xyz   False
Apple  Phone   Blue     abc    True
 Pear  Table  Green     abc    True

我需要合并/加入一个集合(不是queryset):

[('Apple', 'Table', 'Blue'), ('Pear', 'Phone', 'Green')]

所以基本上,当我用这个元组列表搜索这个模型时,第0行和第2行应该返回。

目前,我的解决方法是将 Foo.objects.all() 读取到数据帧中,并与元组列表进行合并,并将 ID 传递给 Foo.objects.filter()。我还尝试迭代列表并在每个元组上调用 Foo.object.get(),但它非常慢。这个清单相当大。

当我尝试按照当前答案的建议链接Q时,它抛出了一个OperationalError(太多SQL变量)。

我的主要目标如下:

从模型中可以看出,这三个字段共同构成了我的主键。该表包含大约15k个条目。当我从另一个来源获取数据时,我需要检查数据是否已经在我的表中,并相应地创建/更新/删除(新数据可能包含多达15k个条目)。有没有一种干净高效的方法来检查这些记录是否已经在我的表中?

注意:元组列表不必是那种形状。我可以修改它,将其转换为另一个数据结构或转置它。

共有3个答案

巫马自明
2023-03-14

这是正确的查询:

q = Foo.objects.filter(
    Q(fruit='Apple', stuff='Table', color='Blue') |
    Q(fruit='Pear', stuff='Phone', color='Green')
)

此查询也可以工作(如果您不喜欢Q):

q = Foo.objects.filter(
    fruit='Apple', stuff='Table', color='Blue'
) | Foo.objects.filter(
    fruit='Pear', stuff='Phone', color='Green'
)
鄂曦之
2023-03-14

如果您知道这些字段构成了您的自然关键字,并且您必须对它们进行大量的查询,请将这个自然关键字添加为一个适当的字段,并采取措施来维护它:

class FooQuerySet(models.QuerySet):
    def bulk_create(self, objs, batch_size=None):
        objs = list(objs)
        for obj in objs:
            obj.natural_key = Foo.get_natural_key(obj.fruit, obj.stuff, obj.color)
        return super(FooQuerySet, self).bulk_create(objs, batch_size=batch_size)

    # you might override update(...) with proper F and Value expressions, 
    # but I assume the natural key does not change

class FooManager(models.Manager):
    def get_queryset(self):
        return FooQuerySet(self.model, using=self._db)

class Foo(models.Model):
    NK_SEP = '|||'  # sth unlikely to occur in the other fields

    fruit = models.CharField(max_length=10)
    stuff = models.CharField(max_length=10)
    color = models.CharField(max_length=10)
    natural_key = models.CharField(max_length=40, unique=True, db_index=True)

    @staticmethod
    def get_natural_key(*args):
        return Foo.NK_SEP.join(args) 

    def save(self, *args, **kwargs):
        self.natural_key = Foo.get_natural_key(self.fruit, self.stuff, self.color)
        Super(Foo, self).save(*args, **kwargs)

    objects = FooManager()

    class Meta:
        unique_together = (('fruit', 'stuff', 'color'), )

现在您可以查询:

from itertools import starmap

lst = [('Apple', 'Table', 'Blue'), ('Pear', 'Phone', 'Green')]
existing_foos = Foo.objects.filter(natural_key__in=list(starmap(Foo.get_natural_key, lst)))

并批量创建:

Foo.objects.bulk_create(
    [
        Foo(fruit=x[0], stuff=x[1], color=x[2]) 
        for x in lst 
        if x not in set(existing_foos.values_list('fruit', 'stuff', 'color'))
    ]
)
微生昌勋
2023-03-14

你有< code>('fruit ',' stuff ',' color')字段唯一在一起

因此,如果您的搜索元组是< code>('Apple ',' Table ',' Blue')并且我们连接它,那么它也将是一个唯一的字符串

f = [('Apple', 'Table', 'Blue'), ('Pear', 'Phone', 'Green')]
c = [''.join(w) for w in f]
# Output: ['AppleTableBlue', 'PearPhoneGreen']

因此,我们可以过滤注释上的查询集并利用 Concat。

Foo.objects.annotate(u_key=Concat('fruit', 'stuff', 'color', output_field=CharField())).filter(u_key__in=c)
# Output: <QuerySet [<Foo: #0row >, <Foo: #2row>]>

这将适用于元组和列表

如果输入是2元组列表:

[('Apple', 'Table', 'Blue'), ('Pear', 'Phone', 'Green')]

转置后输入将为:

transpose_input = [('Apple', 'Pear'), ('Table', 'Phone'), ('Blue', 'Green')]

我们可以通过统计each_tuple_size和input_list_size很容易地识别出输入是转置的。因此,我们可以使用zip再次转置它,上面的解决方案将按预期工作。

if each_tuple_size == 2 and input_list_size == 3:
    transpose_again = list(zip(*transpose_input))
    #  use *transpose_again* variable further

如果输入是 3 个元组的列表:

[('Apple', 'Table', 'Blue'), ('Pear', 'Phone', 'Green'), ('Pear', 'Book', 'Red')]

转置后输入将为:

transpose_input = [('Apple', 'Pear', 'Pear'), ('Table', 'Phone', 'Book'), ('Blue', 'Green', 'Red')]

因此,不可能确定每个<code>n*n

 类似资料:
  • 问题内容: 我有一些带有名称字段的文档。我正在使用名称字段的分析版本进行搜索和排序。排序是在一个级别上进行的,即名称首先是按字母顺序排序的。但是在字母列表中,名称是按字典顺序而不是按字母顺序排序的。这是我使用的映射: 谁能提供相同的解决方案? 问题答案: 深入研究Elasticsearch文档,我偶然发现了这一点: 排序和排序规则 不区分大小写的排序 假设我们有三个用户文档,其名称字段分别包含Bo

  • 已知字母序列【d, g, e, c, f, b, o, a】,请实现一个函数针对输入的一组字符串 input[] = {“bed”, “dog”, “dear”, “eye”},按照字母顺序排序并打印,结果应为:dear, dog, eye, bed。 说明 本问题在网上比较常见,但这里尝试用另外一个思路,并且用python来写,与众多用c++的有所不同,且似乎短小了不少。自己感觉比网上参考到的更

  • 在ElasticSearch中为多个字段指定排序顺序的最佳方法是什么?查询字符串格式似乎根本不起作用: 人们希望先按字段1排序,然后按字段2排序,但似乎只有一个字段排序正确。完整的符号效果更好,但第一个条目偶尔会出现错误的搜索顺序:

  • 问题内容: 如果我有这样的数据: 我如何将命令连接成这样: 我在下面使用了此查询,但命令列的顺序不依其顺序号而定: 任何意见和建议将不胜感激。^ _ ^ 问题答案: 永远不要使用。阅读为什么不在Oracle中使用WM_CONCAT函数? 请参阅本主题https://stackoverflow.com/a/28758117/3989608。 它没有记录,并且依赖的任何应用程序一旦升级到后都将无法工作

  • 问题内容: 我正在使用最新版本的elasticsearch-php以及最新版本的MongoDB和ElasticSearch。 我需要对可以包含一个或多个值的多个字段进行搜索。例: country_code应为NL,BE或DE,并且类别应包含AA01,BB01,CC02或ZZ11 我以为我会按照以下方式解决它(PHP): 但是结果甚至还不能接近我期望返回的数据。 有时 $ countries 和/或

  • 问题内容: 我有一个用户模型和一个提交模型。每个提交都有一个上载用户的外键字段user_submitted。 我的问题很简单:如何获得提交量最多的三个用户的列表? 我尝试在用户模型上创建num_submissions方法: 然后执行: 但这失败了,就像我尝试过的所有其他尝试一样。我实际上可以使用智能数据库查询吗?还是我应该在视图文件中做些更怪异的事情? 问题答案: 你没有在示例模型代码中提及,但在