0

I'm currently setting up my Django project which is a search engine and I've been trying to estabish a connection between a custom Django View and a Javascript function but I kept having issues, so I decided to restart this from the beginning and hopefully get someone's help.

I have this Javascript code

const data = []  // Not sure how to get the data from the backend??

let index = 0;
let results = [];
const randomSearchMatchPercentages = ( array ) => {
    for ( const element of array ) {
        // define a maximum and a minimum range
        const maximum = index <= 100 ? 100 - index : 0;
        const minimum = maximum > 0 ? maximum - 5 : 0;

        element.match = Math.round( Math.random() * ( maximum - minimum ) + minimum ) + "%";
        results.push( element );

        // decrease the maximum and minimum for the next iteration
        index += 5;
    }
console.log( results );
}

randomSearchMatchPercentages( data );

That I need to connect with a custom View like this:

def MatchingScore(request):

    return JsonResponse(output)

I have established a connection and get the data from the backend for my autocomplete with this View:

def autocomplete(request):
    sqs = SearchQuerySet().autocomplete(
        content_auto=request.GET.get('query',''))[:5]
    destinations = {result.destination for result in sqs}
    s = [{"value": dest, "data": dest} for dest in destinations]
    output = {'suggestions': s}
    return JsonResponse(output)

And with this Javascript Function:

$(function () {
    'use strict';

    $('#q').autocomplete({
    serviceUrl: "http://127.0.0.1:8000/search/autocomplete/",
    minChars: 2,
    dataType: 'json',
    type: 'GET',
    onSelect: function (suggestion) {
        console.log( suggestion.value + ', data :' + suggestion.data);
    }
});

});

But I don't know what code to put inside of my def MatchingScore and how to adapt the Javascript code to make it work. I assume that I will need to get the data from my database in the same way as my autocomplete View and pass it to the javascript function.

My goal is farely simple: Generate random number between 100 and 0% and display it to an html list that look like this:

<div>
{% if  page_obj.object_list %}
      <ol class="row top20">

        {% for result in page_obj.object_list %}

     <li class="list-item">
      <div class="showcase col-sm-6 col-md-4">
           <a href="{{ result.object.get_absolute_url }}">
              <h3>{{result.object.title}}</h3>
              <img src="{{ result.object.image }}" class="img-responsive">
           </a>
      </div>
     <li>

         {% endfor %}
      </ol>
</div>

{% else %}
        <p> Sorry, no result found </p>
{% endif %}

How can I do this?

EDIT:

I have this custom forms.py file that I use with Django-Haystack for the search functionnalities:

from haystack.forms import FacetedSearchForm


class FacetedProductSearchForm(FacetedSearchForm):

    def __init__(self, *args, **kwargs):
        data = dict(kwargs.get("data", []))
        self.ptag = data.get('ptags', [])
        super(FacetedProductSearchForm, self).__init__(*args, **kwargs)

    def search(self):
        sqs = super(FacetedProductSearchForm, self).search()

        if self.ptag:
            query = None
            for ptags in self.ptag:
                if query:
                    query += u' OR '
                else:
                    query = u''
                query += u'"%s"' % sqs.query.clean(ptags)
            sqs = sqs.narrow(u'ptags_exact:%s' % query)

        return sqs

Then I pass the custom form into my Views with this class:

from haystack.generic_views import FacetedSearchView as BaseFacetedSearchView
from .forms import FacetedProductSearchForm

class FacetedSearchView(BaseFacetedSearchView):

    form_class = FacetedProductSearchForm
    facet_fields = ['ptags']
    template_name = 'search_result.html'
    paginate_by = 20
    context_object_name = 'object_list'

I've tried the first approach but I don't get any search results back, and since I already have pagination and an object_name, is there a way to implement both the def MatchingScore and the def random_search_match_percentages into this class by indenting it or something else so that I can call the match within this template tag? :

{% if  page_obj.object_list %}

        {% for result in page_obj.object_list %}

         {% endfor %}

{% else %}

{% endif %}
locq
  • 301
  • 1
  • 5
  • 22
  • Are you using django template engine or making a frontend with another framework like Angular or React and using django as a API that returns JSON on your views? Because in your `MatchingScore` view you are just returning a `JsonResponse`... – caiolopes May 07 '19 at 22:06
  • I use django template for the frontend and I did the `MatchingScore view` on purpose, because I don't know what to add in there, that's why I'm asking.. – locq May 07 '19 at 22:14
  • What exactly is the data you want for the `randomSearchMatchPercentages` function? – caiolopes May 07 '19 at 22:21
  • This is datas for my search engine so I use Elasticsearch as an index and a postgreslq database. Here's a sample of the structure of the index for a given product: `{"id": "search.product.5923", "django_ct": "search.product", "django_id": "5923", "text": "Hawaii\nLorem jsvc smc cbd ciecdbbc d vd bcvdvbj obcvb vcibs j dvx\n", "title": "My Title 2", "description": "Lorem jsvc smc cbd ciecdbbc d vd bcvdvbj obcvb vcibs j dvx", "destination": "Hawaii", "link": "uvergo.com", "image": "https://dummyimage.com/600x400/000/fff", "tags": ["Couple", "Family"], "content_auto": "Hawaii"}` – locq May 07 '19 at 22:38

1 Answers1

0

I think you have two different approaches for what you are trying to achieve here, if I understand the problem correctly.

One approach is: you can convert this Javascript code you want to run to Python code (since it does not do any specific JavaScript stuff like dealing with the DOM) and call it from the MatchingScore passing the data you want by grabbing it like you did with the autocomplete function.

from django.shortcuts import render
from django.core.paginator import Paginator


def random_search_match_percentages(array):
    from random import random
    from math import floor

    index = 0
    results = []

    for element in array:
        # define a maximum and a minimum range
        maximum = 100 - index if index <= 100 else 0
        minimum = maximum - 5 if maximum > 0 else 0

        num = floor(random() * (maximum - minimum) + minimum + 0.5)
        element.match = '{}%'.format(num)  # add the match param
        results.append(element)

        # decrease the maximum and minimum for the next iteration
        index += 5

    return results


# small tip: this naming convention you are using is generally used
# for python classes, not function. Generally python developers
# write function names using snake case, like this: matching_score
def MatchingScore(request):
    some_data = MyModel.objects.all()  # just an example of grabbing data...
    paginator = Paginator(some_data, per_page=20)
    page_obj = paginator.get_page(page)

    results = random_search_match_percentages(page_obj)

    return render(request, 'my_app/my_view.html', {'results': results})

Then, you can access your data inside this my_view.html just like your Django template code snippet.

Create a my_view.html file inside your app templates folder, i.e: django_project/my_app/templates/my_app/my_view.html with the following:

<div>
{% if results|length %}
  <ol class="row top20">
    {% for result in results %}
      <li class="list-item">
        <div class="showcase col-sm-6 col-md-4">
           <a href="{% url 'some-product-url' result.django_id %}">
            <h3>{{ result.title }}</h3>
              <!-- use the match param added on the
              random_search_match_percentages function -->
              <p>{{ result.match }}</p>
              <img src="{{ result.image }}" class="img-responsive">
           </a>
        </div>
      </li>
  {% endfor %}
  </ol>
{% else %}
  <p>Sorry, no result found</p>
{% endif %}
</div>

Another approach is to:

1) make a django view that returns the JSON data you want (like autocomplete view, for example)

def matching_score_data(request):
    # grab your data...
    return JsonResponse(data)

2) then, make a simple view

from django.shortcuts import render


def MatchingScore(request):
    return render(request, 'my_app/my_view.html')

3) Then, put your JavaScript code inside the `my_view.html. For the data, you can make an AJAX call to get it. To render the list. you will need to manipulate the DOM using JavaScript.

<ol class="row top20" id="my_list">
</ol>

<script>
$(function () {
    'use strict';

    const randomSearchMatchPercentages = array => {
        let index = 0;
        let results = [];

        for (const element of array) {
            // define a maximum and a minimum range
            const maximum = index <= 100 ? 100 - index : 0;
            const minimum = maximum > 0 ? maximum - 5 : 0;

            element.match = Math.round( Math.random() * ( maximum - minimum ) + minimum ) + "%";
            results.push(element);

            // decrease the maximum and minimum for the next iteration
            index += 5;
        }
        return results;
    }

    $.get("/matching_score_data", function(data) {
        // randomSearchMatchPercentages function in here...
        const results = randomSearchMatchPercentages(data);

        // now, to show the list you need to manipulate
        // the DOM appending the elements inside the
        // #my_list ol element
        for (let i = 0; i < data.length; i++) {
            $("#my_list ol").append(`
                <li class="list-item">
                    <div class="showcase col-sm-6 col-md-4">
                        <a href="${results[i].url}">
                            <h3>${results[i].title}</h3>
                            <p>${results[i].match}</p>
                            <img src="${results[i].image}" class="img-responsive">
                        </a>
                    </div>
                </li>
            `);
        }
    });
});
</script>

IMHO: i think the approach one is easier because you have the power of django template engine and do not need manipulate the DOM with javascript. Besides, you will need to create just one view instead of two.

Refs:

caiolopes
  • 561
  • 8
  • 14
  • Thanks so much, really appreciated! For N.3 in the second approach how can I display the actual randomize percentages in the appended list? And I would like to try the first approach but how can I add the randomSearchMatchPercentages logic in there? Could you include an example? – locq May 08 '19 at 00:35
  • So I have implemented the first approach, I just have to find out how to display the randomized percentage to my list in html. Any solutions? – locq May 08 '19 at 01:46
  • Thank you so much, +1 for the amazing explanation! I have added an Update to my original question, can you take a look at it? – locq May 08 '19 at 16:17