How to implement sort by button?


#1

Hi there I have a new question!

For a given list of “Things” being shown, I want to…

  1. List them by default / initial page load by “Recently Added”. I have a “created” field in my model using DateTimeField for each Thing
  2. I want to implement a Sort By button that is defaulted to “Recently Added”, and dropdown options to be by “Price (Lowest)”, or “Price (Highest)”. I have a “price” field in my model using IntegerField that will a value of either 1, 2, 3, or 4, I intend to translate these to dollar signs ($) essentially like Yelp.

Any thoughts on how to best do this? Thank you!


#2
  1. In your query in the view, you want to use order_by: https://docs.djangoproject.com/en/2.1/ref/models/querysets/#django.db.models.query.QuerySet.order_by

  2. I think there are a few ways to do this… what I would do would be to output your results as recently added, but in your template, add data attributes (https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes) to put the price field in. And then in Javascript, when the dropdown is changed, you can resort the results based on the data attribute.

Another option would be to do an AJAX request to do another database query: https://simpleisbetterthancomplex.com/tutorial/2016/08/29/how-to-work-with-ajax-request-with-django.html

I hope that is enough to help you!


#3

Thank you! I will try it out and report back should I have more questions!


#4

Ok, so I was able to do price sorting, using JQuery and data-attributes. The problem is I’m unable to sort by highest, and I’m unable to get re-sort by ‘created’ again. My hunch is because $collection only works for integers? I found this snippet online and know this is a bit beyond Django/Python so let me know if I should ask elsewhere!

/** 
 * This function returns a callback for data-attribute based sorting.
 *
 * @param sortCriteria
 *   Name of the data-attribute for sorting.
 * @param itemsToSort
 *   A string selector for items for sorting.
 * @param container
 *   A container to put items.
 * @returns {Function}
 */

var sortByDataAttr = function(sortCriteria, itemsToSort, container) {
    return function() {

      // Grab all the items for sorting.
      var $collection = $(itemsToSort);

      // Sort them and append in to container.
      $collection.sort(function(a, b) {
        return $(a).data(sortCriteria) - $(b).data(sortCriteria)
      }).appendTo($(container));
    };
  },
  /**
   * Remove class from all elements and apply to current.
   *
   * @param current
   *   HTML node to apply class.
   * @param activeClass
   *   Active-state string class.
   */
  highlightActive = function(current, activeClass) {
    $('.' + activeClass).removeClass(activeClass);
    $(current).addClass(activeClass);
  };

// Sort by 'data-created' at the start.
highlightActive('.btn-sort-created', 'btn-sort--active');
sortByDataAttr('created', '.item', '.list');

$('.btn-sort-created').on('click', function() {
  highlightActive(this, 'btn-sort--active');
  sortByDataAttr('created', '.item', '.list')();
});

$('.btn-sort-price-lowest').on('click', function() {
  highlightActive(this, 'btn-sort--active');
  sortByDataAttr('price', '.item', '.list')();
});

$('.btn-sort-price-highest').on('click', function() {
  highlightActive(this, 'btn-sort--active');
  sortByDataAttr('-price', '.item', '.list')();
});

#5

Oooh I’m going to have to admit that I’m poor at Javascript, so here’s where you’d probably should ask someone else. 😬Sorry I can’t help more in this aspect!


#6

No worries, thank you for the response!