Issue
I am trying to build a search function for my blog that searches through the two models Articles
and Spots
. The two models are connected via the pivot table ArticleSpots
.
My blog is structured so that there are multiple spots in each article.
When a query is searched I want the query to be searched within both models but only display clickable articles. I have a html page for each article but not for each spots, so all the spots that resulted from the search have to be shown as the article which contains the spot. Hope that makes sense!
This is the code that I came up with but the problem is that I get a lot of duplicates in the variable results
. There are duplicates within each articles_from_spots
and articles_from_query
, and there are also overlaps between them.
Is this the right way to accomplish this ? How can I remove the duplicates from the results? Any help would be appreciated!
views.py
def search(request):
query = request.GET.get("q")
articles_from_query = Articles.objects.filter(
Q(title__icontains=query) |
Q(summary__icontains=query)
)
spots_from_query = Spots.objects.filter(
Q(title__icontains=query) |
Q(summary__icontains=query) |
Q(content__icontains=query)
)
articles_from_spots = []
for x in spots_from_query:
article = Articles.objects.filter(articlespots__spot=x)
articles_from_spots.extend(article)
results = chain(articles_from_spots, articles_from_query)
context = {
'results': results,
}
return render(request, "Search.html", context)
models.py
class Articles(models.Model):
title = models.CharField(max_length=155)
summary = models.TextField(blank=True, null=True)
class ArticleSpots(models.Model):
article = models.ForeignKey('Articles', models.DO_NOTHING)
spot = models.ForeignKey('Spots', models.DO_NOTHING)
class Spots(models.Model):
title = models.CharField(max_length=155)
summary = models.TextField(blank=True, null=True)
content = models.TextField(blank=True, null=True)
Solution
You should be able to do this in a single query following the relationship from article to spot
Articles.objects.filter(
Q(title__icontains=query) |
Q(summary__icontains=query) |
Q(articlespots__spot__title__icontains=query) |
Q(articlespots__spot__summary__icontains=query) |
Q(articlespots__spot__content__icontains=query)
).distinct()
If you were to add a ManyToManyField from Article to Spots it would simplify this a bit and makes sense from a design POV
class Articles(models.Model):
...
spots = models.ManyToManyField('Spots', through='ArticleSpots')
Articles.objects.filter(
Q(title__icontains=query) |
Q(summary__icontains=query) |
Q(spots__title__icontains=query) |
Q(spots__summary__icontains=query) |
Q(spots__content__icontains=query)
).distinct()
Answered By - Iain Shelvington
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.