I have a search bar with autocomplete functionality in my Django app that is displaying results based on user input. I connected this search bar to 3 models. Code below:
search_items.html
{% block body %}
<section >
<h2>Model 1</h2>
<hr>
<div >
{% for qa in qa_list %}
<div >{% include 'components/model_1_search.html' %}</div>
{% empty %}
<div >
<img src="{% static 'text no results.svg' %}">
</div>
{% endfor %}
</div>
</section>
<section >
<h2>Model 2</h2>
<hr>
<div >
{% for article in article_list %}
<div >{% include 'components/model_2_search.html' %}</div>
{% empty %}
<div >
<img src="{% static 'text no results.svg' %}">
</div>
{% endfor %}
</div>
</section>
<section >
<h2>Model 3</h2>
<hr>
<div >
{% for video in video_list %}
<div >{% include 'components/model_3_search.html' %}</div>
{% empty %}
<div >
<img src="{% static 'text no results.svg' %}">
</div>
{% endfor %}
</div>
</section>
<hr>
views.py
@login_required
def search_address_qa(request):
query = request.GET.get('title')
payload = []
if query:
lookups = Q(title__icontains=query)
address_objects = Article.objects.filter(lookups, status=1).distinct()
address_objects_qa = QA.objects.filter(lookups, status=1).distinct()
for address_object in address_objects or address_objects_qa:
payload.append(address_object.title)
return JsonResponse({'status':200, 'data': payload})
@login_required
def search_items(request):
query = request.GET.get('q')
modelone= ModelOne.objects.filter(title__icontains=query)
modeltwo= ModelTwo.objects.filter(title__icontains=query)
modelthree= ModelThree.objects.filter(title__icontains=query)
if query is not None:
lookups = Q(title__icontains=query) | Q(tags__name__icontains=query) | Q(short_description__icontains=query) | Q(body__icontains=query) | Q(category__title__icontains=query)
modelone = ModelOne.objects.filter(lookups).distinct()
modeltwo = ModelTwo.objects.filter(lookups).distinct()
modelthree= ModelThree.objects.filter(lookups, status=1).distinct()
context = {
'article_list': modelone,
'qa_list': modeltwo,
'video_list': modelthree,
}
return render(request, 'search/search_items.html', context)
I am not sure if this is the best way of doing it but I am currently struggling with displaying no results because I want to display only one text no results.svg
if there are no results in 3 models.
Moreover, if there is an object found only in Model 1
then I want to hide Model 2
and Model 3
. The same rule should apply to Model 2
and Model 3
so if I find an object only in Model 2
then Model
1 and Model 2
sections should disappear
CodePudding user response:
You can just directly render into the template instead of calculating so many things. You can do it as follows:
{% if article_list %}
show result here
{% else %}
display no results.svg
{% endif %}
{% if qa_list %}
show result here
{% else %}
display no results.svg
{% endif %}
{% if video_list %}
show result here
{% else %}
display no results.svg
{% endif %}
The if the tag will evaluate as false if it is empty. This will reduce the .count() calculations and sending more variable.
CodePudding user response:
Just evaluate the state of play and pass it through the context.
count1 = modelone.count()
count2 = modeltwo.count()
count3 = modelthree.count()
no_results = (count1 == 0 and count2 == 0 and count3 == 0)
context = {
'no_results' : no_results,
'article_list': modelone,
'qa_list': modeltwo,
'video_list': modelthree,
}
The other part of the question is ill-formed. What does it mean to find an object only in model 1 but not in model 2? They are by definition different model types, therefore in what terms are they consideredthe same? Once you can express this in Python, evaluate it before rendering your template, so it can easily express what to not render in simple if tests
{% if no_results %}
display no results.svg
{% else %}
...
{% endif %}
Other things which might help. You can render a queryset empty with queryset.none()
(so a template which iterates over it {% for x in queryset %}
iterates zero times and renders the {% empty %}
part if it's present.