1

不明な数のクエリセットをリストに連結する方法はありますか?

ここに私のモデルがあります:

class Item(models.Model):
    name = models.CharField(max_length=200)
    brand = models.ForeignKey(User, related_name='brand')
    tags = models.ManyToManyField(Tag, blank=True, null=True)
    def __unicode__(self):
        return self.name
    class Meta:
        ordering = ['-id']

class Tag(models.Model):
    name = models.CharField(max_length=64, unique=True)
    def __unicode__(self):
        return self.name

私が使用しているクエリには、次の 2 種類があります。

  1. items = Item.objects.filter(brands__in=brands)

  2. items = Item.objects.filter(tags__name='80s').filter(tags__name='comedy')

2 番目のタイプのクエリに関しては、ユーザーは検索を保存でき (たとえば、「80 年代のコメディ」)、複数の検索を同時に保存できるため、保存した検索ごとにクエリを作成する必要があります。

私は当初、両方のケースを処理する単一のクエリを試して構築したかったのですが ( Django Combining AND and OR Queries with ManyToMany Field を参照)、これを行う最善の方法はすべてのクエリをリストに結合することだと思います。

私は@akaiholaがここで提案していることを気に入っています.Django ビューで2つ以上のクエリセットを組み合わせるには? しかし、可変数のクエリで itertools.chain を使用する方法がわかりません。

それを達成するための最良の方法を知っている人はいますか?

編集: 言い忘れましたが、私が探しているのは、特定のブランドのアイテム、または必要なタグがすべて付いているアイテムです。

4

1 に答える 1

3

少し非正統的ですが、再帰を使用できます。したがって、あなたの例では:

def recursive_search(tags, results_queryset):
    if len(tags) > 0:
        result_qs = result_queryset.filter(tags_name=tags[0])
        if result_queryset.exists():
            return filter_recursion(tags[1:],result_queryset)
        else:
            return None
    return result_queryset

tags = ["comedy", "80s", "action", "thriller"]  # This can be variable
result_queryset = Item.objects.filter(brands__in=brands) # Could be Item.objects.all()
print recursive_search(tags, result_queryset)

したがって、検索するタグのリストと、条件に一致する可能性のあるすべてのアイテムのクエリセットから始めます(この場合、特定のブランドのアイテムのリストから始めます)

次に、タグのリストを1つずつ再帰的に調べ、クエリセットを削減します。レベルごとに、クエリセット全体を、言及されているすべてのタグを持つアイテムのみに再フィルタリングします。

それで:

  • 最初の呼び出し/レベルは、お気に入りのタグを持つすべてのアイテムに対して行われます。
  • 2番目の呼び出し/レベルは、タグがお気に入り最も大きいすべてのアイテムに対して行われます。

フィルタによって返されるクエリセットがNoneの場合、必要なすべてのタグを持つアイテムがないことを意味し、メソッドは終了してNoneを返します(つまり、失敗の最初のインスタンスで終了します)。さらに、データベースへのヒットは1回だけである必要があります(私は思います!)

私はこれをテストしました、そしてそれはうまくいくはずです、それでそれを試してみてください

編集

ブランドから返されたクエリセット(q1)と、itertools(q2)を使用して上記で作成されたクエリセットを連結するには:

list = []
for item in itertools.chain(q1, q2):
    list.append(item)

編集2

これは、1つのクエリで必要なことを達成しませんか?

# list of tags = ['comedy','80s']
qs = Item.objects.all( Q(brand__iexact="brand name") | Q(tags__name__in=[tag for tag in list_of_tags]) )
于 2011-06-04T00:28:12.620 に答える