0

ブログの検索に取り組んでいます。とにかく、私はそれを実装するのにいくつかの問題があります。

私は2つのモデルを持っています:

class Article(models.Model):
    title = models.CharField(max_length=255)
    content = models.TextField()

class Tag(models.Model):
    article = models.ForeignKey(Article)
    content = models.CharField(max_length=255)

実際の検索には、フレーズとタグの2つのフィールドがあります。フレーズはとを検索する必要がありますArticle.titleArticle.content、タグはTagオブジェクトを含む記事を検索する必要がありますTag.content

私もテスト中です!

def test_by_phrase_and_tags(self):
    article_content = "spam"
    tag_content1 = "eggs"
    tag_content2 = "cheese"
    article1 = test_utilities.create_article(content=article_content)
    article2 = test_utilities.create_article(content=article_content)
    test_utilities.create_tag(article1, content=tag_content1)
    test_utilities.create_tag(article2, content=tag_content1)
    test_utilities.create_tag(article2, content=tag_content2)
    response = self.client.get(reverse("blog_search"), {
        "phrase": article_content,
        "tags": "{}, {}".format(tag_content1, tag_content2)
    })
    found_articles = response.context[-1]["found_articles"]
    self.assertEqual(found_articles, [article2])

内容が等しい2つの記事、両方の記事に設定される等しいタグ、および2番目の記事にのみ設定される一意のタグを作成します。

次に、コンテンツ(両方の記事が一致する必要があります)と両方のタグ(2番目の記事のみが一致する必要があります)を持つ記事をリクエストします。全体として、私は2番目の記事だけが返されると断言しています。

生のSQLとDjangoORMで多くのことを試しましたが、どれもうまくいかないようです。

サブクエリを使用する場合:

SELECT * FROM blog_article
WHERE blog_article.content = "spam"
AND blog_article.id IN (
    SELECT blog_tag.article_id FROM blog_tag
    WHERE blog_tag.content = "eggs"
    OR blog_tag.content = "cheese"
);

参加して:

SELECT * FROM blog_article
JOIN blog_tag
ON blog_article.id = blog_tag.article_id
WHERE blog_article.content = "spam"
AND blog_tag.content = "eggs"
AND blog_tag.content = "cheese";

ORMと同じことと他のこと...

spamでは、タイトルまたはコンテンツがあり、タグが付いている記事を取得するにはどうすればよいですか?私は困惑しています。

4

2 に答える 2

2

eggs私があなたを正しく理解しているなら、あなたは両方のタグがあり、それらの一方ではない記事を探していcheeseます、そしてあなたはこれを行うことができます:

SELECT * 
FROM blog_article a
INNER JOIN
(
   SELECT article_id
   FROM blog_tag
   WHERE content IN ('eggs', 'cheese')
   GROUP BY article_id
   HAVING COUNT(DISTINCT content) = 2
) b ON a.id = b.article_id
WHERE a.content = 'spam';

SQLフィドルデモ

このクエリの背後にある考え方は、彼らがリレーショナル除算と呼んでいるものであり、そのための1つの方法は、サブクエリが行うことです。

   SELECT article_id
   FROM blog_tag
   WHERE content IN ('eggs', 'cheese')
   GROUP BY article_id
   HAVING COUNT(DISTINCT content) = 2

これは:

   GROUP BY article_id
   HAVING COUNT(DISTINCT content) = 2

これにより、グループ化された各article_idタグに両方のタグが付けられ、記事に1つある場合は、COUNT(DISTINCT content)= 1になり、これが削除されます。

于 2013-02-01T17:53:31.760 に答える
1

私が正しく理解している場合は、フレーズまたはタグでarticle.title記事をフィルタリングする必要があります。article.content

まずrelated_name、タグモデルでfor記事を定義します。

class Tag(models.Model):
    article = models.ForeignKey(Article, related_name='tags')

今クエリ:

from django.db.models import Q

# supposed input
phrase = 'my search string'
tags = ['tag1', 'tag2']

articles = Article.objects.filter(
   Q(title__icontains=phrase) |
   Q(content__icontains=phrase)) \
   .filter(tags__content__in=tags) \
   .annotate(num_tags=Count('tags')) \
   .filter(num_tags=len(tags))
于 2013-02-01T17:58:50.710 に答える