0

Using a ListView to display search results from a user query.

How can I add a redirect if the item they search for has an exact match, to that specific DetailView?

class WikiSearchView(ListView):
    template_name = "encyclopedia/wiki_search.html"
    model = Entry
    paginate_by = 25
    context_object_name = "searchResults"

    def get_queryset(self):
        search = self.request.GET.get('q')
        object_list = Entry.objects.filter(Q(title__icontains=search))
        return object_list

I tried to add a try/except with Entry.objects.get to look for an exact match and then use a return redirect(xyz), but that didn't work.

stiction
  • 13
  • 5
  • in the `get_querst` after the qs is ready, check its length if its equal to 1 so there is one exact match. but this method has nothing to do with the redirect or rendering pages. so yiu sould do that in other methods like `get/post` of the class. inside get/post method call get_queryset and check thats length and redirect to detail page. – mh-firouzjah Dec 29 '20 at 06:56

2 Answers2

1

The solution below works. Here's why:

As referenced by a fellow user here: https://stackoverflow.com/a/19707855/11616858 You can simply return a filter for the get_queryset.

As Mahdi mentioned, we need to handle redirections in the get() method override, or we'll get a 500 server error. An exact match will result in 1 entry, we check if the property we want, title, is an exact match case sensitive, if so, we redirect, if not we render the default. The no matched terms case is handled in the template.

class WikiSearchView(ListView):
    template_name = "encyclopedia/wiki_search.html"
    model = Entry
    paginate_by = 25
    context_object_name = "searchResults"

    def get_queryset(self):
        search = self.request.GET.get('q')
        return Entry.objects.filter(Q(title__icontains=search))

    def get(self, request, *args, **kwargs):
        if len(self.get_queryset()) == 1:
            if self.request.GET.get('q') == self.get_queryset().first().title:
                return redirect('wiki:wiki-detail', wikiEntry=self.get_queryset().first().title)

        context = {"searchResults": self.get_queryset()}
        return render(request, self.template_name, context)

NOTE: Debug is set to false, as I have implemented custom error page template handling, and we are running using --insecure to serve static files on the localhost.

stiction
  • 13
  • 5
0

You can try like this using exists() method:

class WikiSearchView(ListView):
    template_name = "encyclopedia/wiki_search.html"
    model = Entry
    paginate_by = 25
    context_object_name = "searchResults"
    search = None

    def get_queryset(self):
        queryset = super().get_queryset() 
        return queryset.filter(Q(title__icontains= self.search))

    def get(self, request, *args, **kwargs):
        self.search = request.GET.get('q') 
        query = Entry.objects.filter(title__iexact= self.search)  # search for title by ignoring upper/lowecase letters
        if query.exists():
            return redirect('detail-view', pk=query.first().pk)
        return super().get(request, *args, **kwargs)
ruddra
  • 50,746
  • 7
  • 78
  • 101
  • still getting server errors, may be because I'm running in Debug = false mode, and --insecure for runserver to serve static files locally. Not sure if this has to do with it but I posted what works – stiction Dec 30 '20 at 07:48