0

In list view template I created a filter form that filters posts, and again their is a sort dropdown to sort them:

<form id="sortForm">
    <select class="input-text" id="sort" onchange="document.querySelector('#sortSubmitBtn').click()" name="sort"
        id="sort">
        <option disabled selected>Sort by</option>
        <option value="price_l2h" {% if 'price_l2h' == values.sort %} selected {% endif %}>
            Price (low to high)</option>
        <option value="price_h2l" {% if 'price_h2l' == values.sort %} selected {% endif %}>
            Price (high to low)</option>
    </select>
    {% if values.keywords %}
    <input type="hidden" name="keywords" id="keywords" value="{{ values.keywords }}">
    {% endif %}
    {% if values.mls_number %}
    <input type="hidden" name="mls_number" id="mls_number" value="{{ values.mls_number }}">
    {% endif %}

    <button type="submit" id="sortSubmitBtn" style="display: none;">Submit</button>
</form>

and here is the Ajax I used to sort it, but it doesn't work. I used same Ajax syntax to save data in models it worked fine, but this one doesn't work.

<script>
    $(document).on('submit', '#sortForm', function (e) {
        e.preventDefault();

        $.ajax({
            type: 'GET',
            url: "{% url 'listing:search' %}",
            data: {
                sort: $('#sort').val(),
                keywords: $('#keywords').val(),
                mls_number: $('#mls_number').val(),
                csrfmiddlewaretoken: "{{ csrf_token }}",
            },
            success: function () {
                alert('Form submitted successfully!!');
            }
        })
    })

</script>

the urls.py:

path('search/', search, name='search'),

Thank you I hope someone help me with this.

edit: This is how GUI looks, on select I want it to sort lists:

enter image description here

edit: views.py added

def search(request):
    queryset = Listing.objects.all().order_by('listing_date')

    listing_for = request.GET.get('listing_for')

    # filter by price
    min_price = request.GET.get('min_price')
    max_price = request.GET.get('max_price')
    if min_price and max_price:
        queryset = queryset.filter(price__range=(min_price, max_price))

    # Filter by new mls number
    mls_number = request.GET.get('mls_number')
    if mls_number:
        queryset = queryset.filter(mls_number__exact=mls_number)

    # filter by keyword
    keywords = request.GET.get('keywords')
    if keywords:
        queryset = queryset.filter(Q(description__icontains=keywords) | Q(
            lot_feature__title__icontains=keywords) | Q(interior_feature__title__icontains=keywords) | Q(exterior_finish__title__icontains=keywords) | Q(extra_feature__title__icontains=keywords) | Q(appliances__title__icontains=keywords) | Q(view__title__icontains=keywords)).distinct()

    # sorting function
    sort_by = request.GET.get('sort')
    if sort_by:
        if sort_by == 'price_l2h':
            queryset = queryset.order_by('price')
        elif sort_by == 'price_h2l':
            queryset = queryset.order_by('-price')
        elif sort_by == 'newest':
            queryset = queryset.order_by('-listing_date')
        elif sort_by == 'bedrooms':
            queryset = queryset.order_by('-bedrooms')
        elif sort_by == 'bathrooms':
            queryset = queryset.order_by('-bathrooms')
        elif sort_by == 'sqrft':
            queryset = queryset.order_by('-sqrft')

    context = {
        'listings': queryset,
        'city': city,
        'provinces': provinces,
        'prices': prices,
        'property_types': property_type,
        'rooms': rooms,
        'values': request.GET,
        'int_values': int_values,
        'page': page,
    }

    return render(request, 'listing/listings.html', context)
Mir Stephen
  • 1,758
  • 4
  • 23
  • 54
  • any errors ? can you add your view also, how it does not work ? – ytsejam Jun 17 '20 at 15:13
  • there're no errors, the list filters as expected but the page refreshes which I don't want because I am using Ajax. Why Ajax is not working here – Mir Stephen Jun 17 '20 at 15:38

3 Answers3

1

That is not how ajax works, you will need to send a JsonResponse and operate it. For this kind of operation you can use django-rest-framework which will make your job simplier. If you dont want to use it, you have to modify your code similar to this link.

ytsejam
  • 3,291
  • 7
  • 39
  • 69
1

Let us assume that you have following table:

<select name="orderby" class="form-control" id="sort">
                                            <option value="default" selected="selected">Default sorting</option>
                                            <option value="rating" name ="rating">Sort by average rating</option>
                                            <option value="date" name ="date">Sort by latest</option>
                                            <option value="price-low" name ="price-low">Sort by price: low to high</option>
                                            <option value="price-high" name ="price-high">Sort by price: high to low</option>
                                        </select>

We are picking id attribute from the select and pulling data value from Ajax.

$(document).ready(function(){
    $('#sort').on('change', function() {
        var sortid = $('#sort').val();

        $.ajax({
            type: 'POST',
            url: $(this).data('url'),
            datatype: 'json',
            data: {'sortid': sortid}
        }).done(function (data) {
            $('.product-wrapper').html(data.sort_by_choice);
        });
    });

    


}

Here, when the value of #sort id is changed, we are assigning that value to variable sortid.

And we are passing the data via Ajax to server.

I have used POST method, if we do not define method, default method will be GET. I am assigning current URL, we can assign direct URL only too. eg: url: shop/,

our Datatype is JSON and data is the data obtained from variable.

Now lets create our views.py below:

def products(request):
    
    products = Products.objects.all().order_by('created_at')
    if request.is_ajax() or request.method == 'POST':
        sort_parameter = request.POST.get('sortid')
    
        if sort_parameter == 'price-high':
            products = products.order_by('price')
        elif sort_parameter == 'price-low':
            products = products.order_by('-price')
        elif sort_parameter == 'date':
            products = products.order_by('-created_at')
        
        
        products = render_to_string(
            template_name="shop.html", 
           context = {
                    'products': products,
             }
        )

        json_sort = {"sort_by_choice": products}
        return JsonResponse(data=json_sort, safe=False)
            
    return render(request, 'ecommerce/shop.html', {'products': products})
    

Here if the request is ajax,I get the sort_parameter from POST get method. My post type is POST if your type is GET in javascript file you need to get by GET method.

After that,

I have looped the sort parameter and rendered the parameter to string. We need to render_to_string because it loads a template and calls its render() method immediately.

After this we need to return JsonResponse for the AJAX request.

And if the request is not AJAX, return regular response.

To load JsonResponse and render_to_string import:

from django.template.loader import render_to_string
from django.http import JsonResponse
Madhav Dhungana
  • 476
  • 4
  • 13
0

For sorting the data on the server-side you can use your QuerySet's order_by-method or the Model's ordering-Meta-option.

You could also sort the returned data in JavaScript on the client-side.

S.Moenig
  • 80
  • 7
  • I know how to sort, the functionality works fine. How to apply Ajax here, why Ajax is not working? – Mir Stephen Jun 17 '20 at 14:50
  • as [@ytsejam](https://stackoverflow.com/a/62465272/6329309) said you need to send a JsonResponse. [this answer](https://stackoverflow.com/questions/2428092/creating-a-json-response-using-django-and-python?answertab=active#tab-top) explains well how to do that. – S.Moenig Jun 19 '20 at 12:23