I’m working on search for my blog. Anyway, I’m having some problems with implementing it.
I’m having two models:
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)
Actual search has two fields: phrase and tags. Phrase should look in Article.title and Article.content, but tag should look for articles that have Tag object by Tag.content.
I’m having a test too!
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])
It creates two articles with equal content, equal tag that’s set for both articles and unique tag that’s set only for 2nd article.
Then I request articles that have the content (both articles should match) and both tags (only 2nd article should match). Overall, I’m asserting that only 2nd article is returned.
I have tried a lot of things with raw SQL and Django ORM, but none seems to work.
With a sub-query:
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"
);
With a join:
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";
The same and other things with ORM…
So how can I get articles that have spam in title or content and have tags? I’m stumped.
If i understand correctly you want to filter the articles by
article.titleorarticle.contentwith the phrase or with tags:First define a
related_namefor article in tags model:Now query: