Django ajax search button more than one data

Question:

I have a django project. In this project, I made a search box with ajax, but the same data is coming more than once. Is the problem in ajax? or is the problem in django? I am not sure. Please help me.

Hey guys.I have a django project. In this project, I made a search box with ajax, but the same data is coming more than once. Is the problem in ajax? or is the problem in django? I am not sure. Please help me.

Hey guys.I have a django project. In this project, I made a search box with ajax, but the same data is coming more than once. Is the problem in ajax? or is the problem in django? I am not sure. Please help me.
my html code


   enter code here

<form class="search-content" method="POST">
               {% csrf_token %}
               <input type="text" name="text" placeholder="Ne Aramıştınız?"  id="searchInputChange">
               <button>Ara <i class="fas fa-search"></i></button>
           </form>

           <div class="all-dietitans-content">
               <div id="null-search-dietitians">
                   Aradığınız sonuç bulunamadı. Lütfen aradığınız kelimeyi gözden geçiriniz.
               </div>
               {% for posts in posts%}
               <div class="dietitans" data-firs-load="true">
                   <div class="left-image">
                       <img src="{{posts.photo}}" alt="">
                       <a onclick="openVideoModal(event)" data-iframe-link="{{posts.video}}">
                           <i class="far fa-play-circle"></i>
                           <br>
                           İzle
                       </a>
                   </div>

                   <div class="right-content">
                       <div class="dietitans-infos">
                           <div class="left">
                               <div class="name">
                                   {{posts.isim}} {{posts.soyisim}}
                               </div>
                               <div class="degree">
                                   {{posts.uzmanlik}}
                                   </div>
                               <div class="stars">
                                   <i class="fas fa-star"></i>
                                   <i class="fas fa-star"></i>
                                   <i class="fas fa-star"></i>
                                   <i class="fas fa-star"></i>
                                   <i class="fas fa-star notStar"></i>
                               </div>
                           </div>
                           <div class="right">
                               <div class="item">
                                   <div class="title">
                                       Yorum Sayısı
                                   </div>
                                   <div class="number">
                                       {{posts.yorum_sayi}}
                                   </div>
                               </div>
                               <div class="item">
                                   <div class="title">
                                       Danışan Sayısı
                                   </div>
                                   <div class="number">
                                       {{posts.danisan_sayi}}
                                   </div>
                               </div>
                           </div>
                       </div>
                       <div class="dietitans-services-content">
                           <div class="dietitans-description">
                               <div>Uzmanlıklar :</div>
                               <div> {{posts.hizmetler}} </div>
                           </div>
                           <div class="buttons-and-text">
                               <div class="buttons">
                                   <div class="button-style-2">
                                       <a href="{% url 'diyetisyen' slug=posts.slug %}">Profili İncele</a>
                                   </div>
                                   <div class="button-style-1">
                                       <a href="{%url 'randevu' slug=posts.slug %}">Randevu Al</a>
                                   </div>
                               </div>
                           </div>
                       </div>
                   </div>
               </div>
               {% endfor %}
           </div>

my ajax code


    enter code here

const nullDietitans = document.getElementById('null-search-dietitians')
const pagination = document.querySelector('.pagination')
const dietitiansContent = document.querySelector(".all-dietitans-content")
const dietitansFirstLoad = document.querySelectorAll('.all-dietitans-content > .dietitans[data-firs-load="true"]')
const searchInputChange=document.querySelector("#searchInputChange");

searchInputChange.addEventListener('input',(e)=>{
    nullDietitans.style.display = 'none'
    let searchValue=e.target.value.trim();
    
    if(searchValue.length>=3){
        if(searchValue === ''){
            dietitansFirstLoad.forEach(element=>{
                element.style.display = 'flex'
            })
            pagination.style.display = 'flex'
            document.querySelectorAll('.all-dietitans-content > .dietitans[data-search="true"]').forEach(element=>{
                element.remove()
            })
            nullDietitans.style.display = 'none'
        }
        else{
            fetch("/getDietitians",{
                body: JSON.stringify({searchText:searchValue}),
                method: "POST",

            })
            .then((res)=>res.json())
            .then((data)=>{
                console.log(data)
                dietitansFirstLoad.forEach(element=>{
                    element.style.display = 'none'
                })
                pagination.style.display = 'none'
                if(data.length > 0){
                    $.each(data,(index,value)=>{
                        $.each(data,(index1,value1)=>{
                            
                            $(".all-dietitans-content").append('' +
                                '<div class="dietitans" data-search="true"><div class="left-image">' +
                                '<img src="'+value1.photo+'" alt="">' +
                                '<a onclick="openVideoModal(event)" data-iframe-link="'+value1.video+'">' +
                                '<i class="far fa-play-circle"></i><br>İzle</a></div><div class="right-content"><div class="dietitans-infos"><div class="left"><div class="name">' +
                                value1.isim + ' ' + value1.soyisim +
                                '</div><div class="degree">' +
                                value1.uzmanlik +
                                '</div><div class="stars"><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i><i class="fas fa-star"></i></div></div><div class="right"><div class="item"><div class="title">Yorum Sayısı</div><div class="number">' +
                                value1.yorum_sayi +
                                '</div></div><div class="item"><div class="title">Danışan Sayısı</div><div class="number">' +
                                value1.danisan_sayi +
                                '</div></div></div></div><div class="dietitans-services-content"><div class="dietitans-description"><div>Uzmanlıklar :</div><div>' +
                                value1.hizmetler +
                                '</div></div><div class="buttons-and-text"><div class="buttons"><div class="button-style-2">' +
                                '<a href="/diyetisyen/'+value1.slug+'">Profili İncele</a>' +
                                '</div><div class="button-style-1">' +
                                '<a href="/randevu/'+value1.slug+'">Randevu Al</a>' +
                                '</div></div></div></div></div></div>')
                        })
                    })
                }
                else{
                    nullDietitans.style.display = 'block'
                    document.querySelectorAll('.all-dietitans-content > .dietitans[data-search="true"]').forEach(element=>{
                        element.remove()
                    })
                }
            });
        }
    }
    else{
        dietitansFirstLoad.forEach(element=>{
            element.style.display = 'flex'
        })
        pagination.style.display = 'flex'
        document.querySelectorAll('.all-dietitans-content > .dietitans[data-search="true"]').forEach(element=>{
            element.remove()
        })
        nullDietitans.style.display = 'none'
    }

})


Asked By: Burak Demirer

||

Answers:

It’s because you’re doing multiple queries and | to combine them, that’s why it is returning duplicates.
instead of doing list = query1 | query2 use Q objects

@csrf_exempt
def getDietitians(request):
    from django.http import JsonResponse
    if request.method == "POST": 
        search_str=json.loads(request.body).get('searchText')

        from django.db.models import Q
        expenses = diyetisyenler.objects.filter(
            Q(isim__istartswith=search_str) | 
            Q(soyisim__istartswith=search_str) | 
            Q(uzmanlik__icontains=search_str) | 
            Q(hizmetler__icontains=search_str)
            )

        data=expenses.values()
        return JsonResponse(list(data),safe=False)

Edit

Answer: JS issue, the item list should be removed on every search


And I’ve worked with similar applications, so I’ll drop some ideas I’ve done 🙂

Delay

It might be a good idea to add a delay, so it’s not posting for every single keystroke.

Example: Searching for abc
  1. Searches for a
  2. Searches for ab
  3. Searches for abc

With a delay, I’ve got it at 400 milliseconds, more than likely I’ll just search once for abc – unless the person types super slow

View
// global unfortunately :(
var interval = 0;
var counter = 0;

$('#inputfield').on('input', function(e) {
    if (!$(this).is(':focus')){ return; }
    var search = $(this).val().trim();

    if (search){
        clearInterval(interval);
        interval = setInterval(function() {
            counter++;

            if (counter >= 4){ // 4 * 100 => 400 millisecond delay
                clearInterval(interval);
                counter = 0;

                searchfunction(this);
            };
        }, 100);
    }else{
        // Could clear results here
    };
};

Ping-Pong Timestamp

Larger Queries will sometimes overwrite smaller ones

Example:
  1. Send search for a (query1) [takes 15 seconds]
  2. Send search for absolutely (query2) [takes 2 seconds]
  3. query2 returns
  4. query1 returns, overwriting query2 (not good)
Solution
  1. On Javascript POST, send 'time': Date.now(), along with search
  2. In python return time with the results
    • {'list':list(data), 'time':request.POST.get('time')}
  3. On Javascript POST return, check if return is newer than rendered
    • If newer: updated results & it’s time (time would be any way to store when you sent the search for the what’s rendered)
    • If older: just skip the render
Answered By: Nealium
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.