0

編集:

みんなが読みすぎないようにするために:問題は私が何を理解していないかです

Q(tag_rep__tag=tag.id)

このモデルでは本当にそうです:

class Item(models.Model):

    tag_rep=generic.GenericRelation(TaggedItem)

ほとんどの場合、tag_rep__tagは、単一のタグではなく、タグのリストを返します。だから私は私がしたようにクエリを行うことはできません。tag_rep__tagを比較して、それがどうかを確認するにはどうすればよいですか?

  1. タグのリストのいずれかが含まれています
  2. タグのリストがすべて含まれています

タグ付けタグを持つアイテムのクエリセットベースのタグフィルターを作成しようとしています。私はすでにフィルターの作成に成功しましたが、それらはpythonに基づいておりfilter、リストを返します。

class TagFilter(object):

    def __init__(self,any_tags,avoid_tags,all_tags):
         # all tags as tag instances
         self.any_tags = any_tags
         self.avoid_tags = avoid_tags
         self.all_tags = all_tags

    def seek_any_tags(self, item):
        for tag in self.any_tags:
            if tag in item.tags:
               return True
        return False

    def items_with_any_tags(self,items):
        return filter(self.seek_any_tags,items)

これはかなりうまくいきましたが、フォームセットに渡す代わりにクエリセットが必要になりました。したがって、現在のメソッドはリストを返すため、機能しなくなります。私のモデルのタグにアクセスできるようにするために、私はこれを行いました:

from django.contrib.contenttypes import generic
from tagging.models import TaggedItem

class Item(models.Model):

    # some_fields here

    tag_rep = generic.GenericRelation(TaggedItem) 

フィルタseek_any_tagsは、データベースクエリの形式ですでに再構築できる唯一のものでした。いくつかのSO投稿を読み、多くのグーグルを行った後、私はこの解決策を思いつきました:

def seek_any_tags_qs(self,items):

    if self.any_tags!=None:
        q = reduce(lambda x, y: x | y, [Q(tag_rep__tag=tag.id) for tag in self.any_tags])
        items = items.filter(q)

    return items

とてもいいです、そしてはい、私はそれについて少し誇りに思っています。しかし、今、私が構築したいフィルターがさらに2つあります:avoid_any_tagsseek_all_tags。私はseek_any_tagsフィルターをしたのと同じ方法でそれらをやろうとしました:

def avoid_any_tags_qs(self,items):

    if self.avoid_tags != None:
        q = reduce(lambda x, y: x | y, [Q(tag_rep__tag=tag.id) for tag in self.avoid_tags])
        items = items.exclude(q)

    return items


def seek_all_tags_qs(self,items):

    if self.all_tags != None:
        q = reduce(lambda x, y: x & y, [Q(_tags__contains=tag.name) for tag in self.seek_tags])
        items.filter(q)

    return items

avoid_any_tagsなければ、avoid_tagsにタグのいずれかがあるすべてのアイテムを除外する必要があります。最後の1つはseek_all_tags、all_tagsにすべてのタグがあるアイテムのみを返す必要があります。

しかしavoid_any_tags、期待どおりには機能しません。これは、avoid_tagsにタグがあり、それ以外の要素がない要素のみを除外します。アイテムにavoid_tagsにないタグが含まれている場合、そのタグは除外されません。なぜだめですか?

4

2 に答える 2

1

これは(あなたの例から)完全に適切なクエリではないと思います:

Q(tag_rep__tag=tag.id)

ここにリストされている例に近いものをたどっていて、そのTaggedItemのタグフィールドがスラッグ(文字列)フィールドであると仮定していますか?したがって、すぐに、idがスラッグフィールドと等しい場合のフィルタリングは正しくないように見えます。また、GenericRelationがリスト(またはそのことについてはクエリセット)を表していることも正しいです。外部キーフィールドを指定するTaggedItemへの逆参照。したがって、次のことができるようになります。Item.tag_rep.all()

あなたの質問には非常に多くの追加情報があり、それを理解するのは少し難しいので、私はそのほとんどを無視して、あなたの要約を一番上で取り上げます。

# Any of a list of strings*
any_tags = ['foo', 'bar']
Item.objects.filter(tag_rep__tag__in=any_tags)

「指定されたタグリストにすべてのタグがあります」に関しては、これを行うための非常に複雑なdjangoクエリベースの方法があるかもしれませんが、これはクライアント側で中間ステップを使用するアプローチです。

# items having all tags in a given list of tags
from collections import defaultdict

tag_vals = Item.objects.all().values_list('id', 'tags__tag').distinct()
# produces result like:  `[(1, u'bdfl'), (1, u'boom'), (2, u'bar'), ...)`

all_tags = set(['boom', 'fizz'])

tag_groups = defaultdict(set)
for id_, tag in tag_vals:
    tag_groups[id_].add(tag)
# produces tag_groups like `{1: set([u'fizz', u'foo', u'boom']), ...}`

item_ids = [id_ for id_,tags in d.iteritems() if tags.issubset(all_tags)]
Item.objects.filter(id__in=item_ids)

この最後の例では、アイテムにタグが['a,'b']あり、all_tagsが['a','b',c']である状況に一致しますが、アイテムにall_tagsよりも多くのタグがある状況には一致しませんが、アイテムにあるタグは一致します。どちらの方法でも一致させるには、そのitem_idsフィルターを変更する必要があります。

item_ids = [id_ for id_,tags in d.iteritems() if \
                tags.issubset(all_tags) or tags.issuperset(all_tags)]
Item.objects.filter(id__in=item_ids)
于 2012-05-25T17:57:15.490 に答える
0

簡単に言うと、これは機能するコードです。

# does the item have any of the seek tags?
has_seek_tags = Q(tags__id__in=self.seek_tags)
items = items.filter(has_seek_tags).distinct()

# does the item have any of the avoid tags?    
has_avoid_tags= Q(tags__id__in=self.avoid_tags)
items = items.exclude(has_avoid_tags).distinct()

# now apply the queries
for tag_id in self.all_tags:
    items = items.filter(has_avoid_tags)

私がまだ理解していないのは、forループのitems.filterがこれと同じではない理由です。

q = reduce(lambda x,y: x&y, [Q(tags__id__exact=tag_id) for tag_id in self.all_tags)
items = items.filter(q)

しかし、それ自体が問題かもしれません。

于 2012-05-25T20:27:58.303 に答える