Custom sorting of search results

I have a view that displays a word list and allows you to search for words. How to do so that after searching, for example, the letter b first displayed words beginning with the letter b, and only then all other words containing the letter b?
What I have:
image
What I want:
image

views.py

class WordList(LoginRequiredMixin, ListView):
    model = Word
    context_object_name = 'word_list'

    def get_queryset(self):
        return Word.objects.order_by(Lower('english_word'))

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['word_list'] = context['word_list'].filter(user=self.request.user)
        search_input = self.request.GET.get('search-area') or ''
        if search_input:
            context['word_list'] = context['word_list'].filter(Q(english_word__contains=search_input) |
                                                               Q(polish_word__contains=search_input))
        context['search_input'] = search_input
        return context

word_list.html

<form method="get">
    <input type="text" name="search-area" placeholder="Search your word" value="{{search_input}}">
    <input type="submit" value="Search">
</form>

{% for word in word_list %}
<p></p>
<a href="{% url 'english:edit' word.id %}">{{ word.english_word }} - {{ word.polish_word }} - {{ word.pronunciation }}</a>
<button  class="btn btn-primary klasa" data-form-url="{% url 'english:delete_word' word.id %}" type="button" name="button">Delete</button>
{{word.id}}
{% endfor %}

You have at least two ways of doing this that I can think of off-hand.

  • You could do two searches, one for words starting with b and one for words containing a b but not starting with b, and then iterate through them. (Or use union, or join the lists, or any variant of these.)

  • You could use a conditional expression to add an additional value to the query to represent whether or not the word starts with b, and then sort based on that additional value.

1 Like