1

こんにちは私はDjangoのタグ付けシステムを作成しようとしていますが、今日、フィルターまたはQオブジェクト(django.db.models.Q)で奇妙な動作が発生しました。

検索文字列をQオブジェクトに変換する関数を作成しました。次のステップは、これらのクエリでTaggedObjectをフィルタリングすることです。しかし、残念ながら私は奇妙な振る舞いをします。

1つのタグ要素のみを検索します。

検索(id=20)=> Q: (AND: ('tags__tag__id', 20)) すると、IDが1127と132の2つのタグ付きオブジェクトが返されます。

(id=4)=> を検索するQ: (AND: ('tags__tag__id', 4)) と、2つのオブジェクトも返されますが、今回は1180と1127です。

これが、relutingSQLクエリです。

SELECT "django_content_type"."id", "django_content_type"."name", "django_content_type"."app_label", "django_content_type"."model" 
FROM "django_content_type" 
WHERE ("django_content_type"."model" = slogan  AND "django_content_type"."app_label" = slogans ) 
ORDER BY "django_content_type"."name" ASC

SELECT "slogans_slogan"."id", "slogans_slogan"."headline", "slogans_slogan"."text", "slogans_slogan"."author"
FROM "slogans_slogan"
  INNER JOIN "htags_objecttagbridge" ON ("slogans_slogan"."id" = "htags_objecttagbridge"."object_id")
WHERE ("htags_objecttagbridge"."tag_id" = 4  AND "htags_objecttagbridge"."content_type_id" = 9 )
LIMIT 21

'または'接続詞で2つのタグを検索します。

(id=4) or (id=20)ここまではすべて問題ありませんが、 => のようにもう少し複雑なクエリを実行すると、Q: (OR: ('tags__tag__id', 4), ('tags__tag__id', 20)) 4(!)オブジェクト1180、1127、1127、132が返されます。

およびSQL:

SELECT "slogans_slogan"."id", "slogans_slogan"."headline", "slogans_slogan"."text", "slogans_slogan"."author"
FROM "slogans_slogan"
  INNER JOIN "htags_objecttagbridge" ON ("slogans_slogan"."id" = "htags_objecttagbridge"."object_id")
WHERE ((("htags_objecttagbridge"."tag_id" = 4 AND "htags_objecttagbridge"."content_type_id" = 9 ) OR "htags_objecttagbridge"."tag_id" = 20 ) AND "htags_objecttagbridge"."content_type_id" = 9 )
LIMIT 21

しかし、ID 1127のオブジェクトは2回返されますが、それは私が望む動作ではありません。私はそれと一緒に暮らす必要があり、そのリストを統一する必要がありますか、それとも私は別のことをすることができますか?Qオブジェクトの表現は私にはうまく見えます。

2つのタグ'と'接続詞を検索します

しかし、最悪の場合、(id=20) and (id=4)=> を検索するとQ: (AND: ('tags__tag__id', 20), ('tags__tag__id', 4))、オブジェクトがまったく返されません。しかし、なぜ?表現は問題なく、ID1127のオブジェクトは両方でタグ付けされている必要があります。私は何が欠けていますか?

これがSQLです。

SELECT "slogans_slogan"."id", "slogans_slogan"."headline", "slogans_slogan"."text", "slogans_slogan"."author" 
FROM "slogans_slogan"
  INNER JOIN "htags_objecttagbridge" ON ("slogans_slogan"."id" = "htags_objecttagbridge"."object_id")
WHERE ("htags_objecttagbridge"."tag_id" = 4  AND "htags_objecttagbridge"."content_type_id" = 9  AND "htags_objecttagbridge"."tag_id" = 20 )
LIMIT 21

[編集]: このSQLステートメントが間違っていることに気づきました。少なくとも私が望むものではありません。ここでは、1つのObjectTagBridgeのIDが4であり、同時にIDが20であるためです。しかし、私の場合、これらは2つの異なるものです。

関係するクラスの関連部分もここにあります:

class TaggedObject(models.Model):
    """
        class that represent a tagged object
    """
    tags = generic.GenericRelation('ObjectTagBridge',
                                   blank=True, null=True)

class ObjectTagBridge(models.Model):
    """
        Help to connect a generic object to a Tag.
    """
    # pylint: disable-msg=W0232,R0903
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    tag = models.ForeignKey('Tag')

class Tag(models.Model):
    ...

ご協力いただきありがとうございます

4

1 に答える 1

5

問題 1 (一意性) の場合: クエリを個別にする必要があります。重複は、区別しない限り、そのタイプのクエリの予想される動作です。

問題 2 については、おそらく、クエリセットの仕組みの微妙ではあるが重要な部分に触れています。次のようなクエリを作成した場合:

mymodel.objects.filter(tags__tag__id=4, tags__tag__id=5)

id=4 と id=5 の両方を持つ単一のタグを持つモデルをクエリしていますが、これはもちろんタグではありません。しかし、代わりに次のようにクエリすると:

mymodel.objects.filter(tags__tag__id=4).filter(tags__tag__id=5)

id=4 のタグと id=5 のタグを持つモデルが得られます。同じことが Q オブジェクトにも当てはまります。それらは個別に分割するfilterexclude、単一のタグ関係を参照しないように呼び出す必要があります。これはここに文書化されています

于 2010-05-01T13:41:11.557 に答える