在尊重行顺序的情况下搜索多个字段

7 浏览
0 Comments

在尊重行顺序的情况下搜索多个字段

我有一个类似于以下的模型:

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

我需要将其与一个集合(不是查询集)合并/连接:

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

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

目前,我的解决方法是将Foo.objects.all()读入DataFrame,并与元组列表进行合并,然后获取ID传递给Foo.objects.filter()。我还尝试遍历列表,并在每个元组上调用Foo.object.get(),但速度非常慢。列表非常大。

当我尝试按照当前答案建议的链接Q时,它会抛出操作错误(SQL变量太多)。

我的主要目标是:

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

注意:元组列表不必是这种形式。我可以修改它,将其转换为其他数据结构或转置它。

0
0 Comments

在上述内容中,存在一个问题:如何在多个字段中进行搜索,同时保持行的顺序。问题的出现是因为在数据库中,没有直接支持按照多个字段进行搜索并保持行顺序的功能。为了解决这个问题,可以通过添加一个自然键(natural key)的字段来实现。

解决方法如下:

1. 在Foo类中添加一个自然键(natural key)字段:

natural_key = models.CharField(max_length=40, unique=True, db_index=True)

2. 在Foo类中重写save()方法,以确保自然键字段的正确性:

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

3. 创建一个自定义的QuerySet类FooQuerySet,重写bulk_create()方法,在创建对象时同时更新自然键字段:

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)

4. 创建一个自定义的Manager类FooManager,返回使用自定义的QuerySet类FooQuerySet:

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

5. 在Foo类中指定使用自定义的Manager类FooManager:

objects = FooManager()

通过以上步骤,我们现在可以在多个字段中进行搜索并保持行的顺序。以下是一些示例代码:

查询:

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'))
    ]
)

通过以上解决方法,我们可以在多个字段中进行搜索,并且保持行的顺序。

0
0 Comments

在这个问题中,出现了"OperationalError: too many SQL variables"错误。这个错误的原因是在一个查询中使用了太多的SQL变量。解决这个问题的方法是将查询分成几个较小的查询,这样性能会更好。

正确的查询方法是使用Q对象将多个条件连接起来,如下所示:

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

另外一种方法是将查询分成多个小的查询,并使用"|"运算符将它们连接起来,如下所示:

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

每次调用.get()方法都会向数据库发送一次查询,所以如果你使用多个.get()方法,就会有多个查询。当查询的长度增加时,就会出现上述错误。因此,将查询分成几个较小的查询是性能上更好的选择。

0
0 Comments

搜索多个字段并保持行顺序的问题是由于要在多个字段上进行搜索,并且希望保持搜索结果的行顺序。解决方法是使用Django的查询集过滤器和注释功能。

首先,给出了一个包含元组的列表f和一个用于搜索的元组c。通过将搜索元组中的元素连接起来,可以得到一个唯一的字符串列表。然后,可以使用注释功能和Concat函数对查询集进行筛选,根据连接后的唯一字符串列表在查询集中过滤。最后,返回符合条件的查询结果。

代码示例如下:

f = [('Apple', 'Table', 'Blue'), ('Pear', 'Phone', 'Green')]
c = [''.join(w) for w in f]
Foo.objects.annotate(u_key=Concat('fruit', 'stuff', 'color', output_field=CharField())).filter(u_key__in=c)

这个解决方法适用于元组和列表。

另外,文章还提到了转置案例。在转置案例中,如果输入是一个由元组组成的列表,可以使用zip函数进行转置。但是,对于每个n*n矩阵的情况,无法确定输入是否已经转置。

代码示例如下:

if each_tuple_size == 2 and input_list_size == 3:
    transpose_again = list(zip(*transpose_input))
    # 使用transpose_again变量继续处理

通过使用Django的注释和Concat函数,可以在多个字段上进行搜索并保持行顺序。对于转置的情况,可以通过计算每个元组的大小和输入列表的大小来确定是否进行转置操作。

0