views:

69

answers:

2

I have this code I'm using to generate a list of records categorized into year, make, series, body style, and color for vehicles. I'd like to customize this further this way:

  • for the year, I want to have only up to 2004 being individual...the rest will fall under other i.e. 2009, 2008, 2007, 2006, 2005, 2004, Other.
  • for the make, I want to display the six makes with the highest popularity...there's a field in the model I'm using to assign the popularity of a make with a value of primary (highest), secondary or tertiary. The rest will fall under Other.
  • For the body style and color, I want to have the items having less than 3 records falling under Other.

My code is as below:

year_count = vehicle_query.order_by(
  '-common_vehicle__year__year').values('common_vehicle__year__year').
  annotate(count=Count('id'))
make_count = vehicle_query.order_by(
  'common_vehicle__series__model__manufacturer__manufacturer').
  values('common_vehicle__series__model__manufacturer__manufacturer').
  annotate(count=Count('id'))
style_count = vehicle_query.order_by(
  'common_vehicle__body_style__style').values
  ('common_vehicle__body_style__style').annotate(count=Count('id'))
colour_count = vehicle_query.order_by(
  'exterior_colour__exterior_colour').values(
  'exterior_colour__exterior_colour').annotate(count=Count('id'))
A: 

The bulk of what you're asking would probably better be handled outside of Django and instead by client-side javascript. To be clear, you could have portions handled by Django, but it would be cleaner not doing so. There are benefits to doing it this way:

  1. Your Django template code stays cleaner
  2. It will degrade nicely
  3. You can later update the interface (change the javascript) and not have to worry about breaking the Django template

To handle this you could simply make a script that when given a <ul> tag (and maybe some arguments) will render that list in the format you're asking about.

Here's a simple example using jQuery. For this example, I'm going to wrap the functionality in a using a jQuery plugin pattern.

Say your django template outputs the following...

<ul>
    <li>Chevy</li>
    <li>Mazda</li>
    <li>Honda</li>
    <li>Ford</li>
    <li>BMW</li>
</ul>

jquery.showmorelist.js

(function($) {

    $.fn.ShowMoreList = function(visibleItemCount) {

        // Wrap parent element
        var parent = $(this).wrap('<div class="show-more-list"></div>').parent();
        var ul = $(this);

        // Enumerate children and hide extras
        var counter = 0;
        $(this).children().filter('li').each(function(){
            counter += 1;
            if (counter > visibleItemCount) {
                $(this).hide();
                $(this).addClass('hidden');
            }
        });

        // Add link and bind click
        var link = $('<a href="#">&gt; Show More</a>').click(function(){
           $(ul).children().filter('.hidden').show();
        });
        $(parent).append(link);
    }

})(jQuery);

page.html

<script type="text/javascript" src="jquery.showmorelist.js"></script>
<script type="text/javascript">
    // On page load...
    $(function() {
            $('ul').ShowMoreList(4);    // Shows only the first 4 items
    });
</script>

This is a rather simple example, and it won't switch the "Show More" to "Hide More" but you should be able to figure that out from the context.

T. Stone
thanks...I was looking for a non-javascript solution but as I have a deadline to beat, this'll have to do.
Stephen
I've tried out this code but it doesn't work as I thought it would...it only displays 2009 then everything else goes under "Show More"...also nothing happens when I click on "Show More"
Stephen
A: 

I managed to get a solution, so I thought it'd be good to update the answer here:

In the head section I have this:

<script type="text/javascript" src="{{ MEDIA_URL }}share/jquery/jquery.min.js"></SCRIPT>
<script type="text/javascript">
(function($) {
$(document).ready(function() {
 //hide the additional content under "Display More"
 $("div.additional_content").hide();

 $("a.more").click(function () { 
  //show or hide the additional content
  $(this).siblings("div.additional_content").toggle();
  //change the attributes and text value of the link toggle
  if($(this).text() == "Display Less"){
   $(this).removeClass("less");
   $(this).addClass("more");
   $(this).html("Display More");
  }else{
   $(this).removeClass("more");
   $(this).addClass("less");
   $(this).html("Display Less");
  }
  return false;
 });       
});
})(jQuery);

Then wherever I want to reduce the number of available options I have this:

<div class="module_wrap">
  <div class="module"> {% if year_count %} <strong>{% trans "Year" %}</strong> <br />
    {% for item in year_count|slice:":6" %}
    <ul>
      <li> <a href="/inventory/year/{{ item.common_vehicle__year__year }}/">{{ item.common_vehicle__year__year }} ({{ item.count }})</a> {% if request.session.chosen_year %} <a href="/undo_year/"><img src="{{ MEDIA_URL }}img/undo.gif" border="0" alt="Remove Year Filter" title="Remove Year Filter" /></a> {% endif %} </li>
    </ul>
    {% endfor %}
    <div class="additional_content"> {% for item in year_count|slice:"6:" %}
      <ul>
        <li> <a href="/inventory/year/{{ item.common_vehicle__year__year }}/">{{ item.common_vehicle__year__year }} ({{ item.count }})</a></li>
      </ul>
      {% endfor %} </div>
    {% if year_count|slice:"6:" %}<a href="" class="more">Display More</a><br />
    {% endif %} <br />
  </div>
</div>
{% endif %}
Stephen