A site I write and maintain, TallyMusic.net, is designed to help people quickly and easily find local music events, but until recently, it lacked a date filter. This made it hard for users to plan for future events, as the user has to scroll through everything sooner before finding the desired future data.
I know that when I’m in a city for a particular set of dates, I want to be able to filter my search to just the dates I’m there – so I figured it was time to add this functionality to my site.
views.py
from .models import Concert from django.db.models import Q def filter_by_date(request): if request.method == "GET": # get start and end dates from the template start_date = request.GET.get('start') end_date = request.GET.get('end') # try to find things on or between those dates try: concerts = Concert.objects.filter( Q(date__gte=start_date) & Q(date__lte=end_date) ) except Concert.DoesNotExist: concerts = None # convert our date strings to datetime objects for better rendering start_date = datetime.datetime.strptime(start_date, "%Y-%m-%d") end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d") # let's render it, yo template = "concerts/calendar.html" context = { "concerts" : concerts, "start_date" : start_date, "end_date" : end_date } return render(request, template, context) else: return render(request, "concerts/calendar.html", {})
In our views.py
file, we’re first getting the start and end dates to filter by, then collecting that data from our database using the Concert.objects.filter()
command. After that, we’re turning our start and end dates from strings to datetime objects, which will help them be displayed in a more readable manner in the frontend. Finally, we return a render()
of what we found.
urls.py
url(r'^date_filter/$', views.filter_by_date, name="date_filter"),
I added just a single line to my urls.py
file, adding the above to the bottom of my urlpatterns
list.
calendar.html
<div id="datefilter-container"> <p class="js-command">Find concerts by date ↓</p> <div id="datefilter"> <form name="date-range-form" id="date-range-form" action="{% url 'concerts:date_filter' %}" method="GET"> <label for="start">Start date:</label> <input type="date" id="start" name="start" required> <label for="end">End date:</label> <input type="date" id="end" name="end" required> <button type="submit" name="date_filter">Submit</button> </form> </div> </div>
On the frontend, I added a bit of HTML to my existing layout, then combined it with some CSS and a short jQuery script for extra value.
concert_styles.css
#datefilter-container { text-align: center; margin: 0 0 1.69em; } #datefilter { height: 0; overflow: hidden; position: static; } #datefilter.open { height: auto; } .js-command { cursor: pointer; } input[type=date] { color: #1D2731; background-color: #D9B310; margin-right: 1.69vw; } button[name="date_filter"] { color: #1D2731; background-color: #D9B310; }
date_filter_toggle.js
$(document).ready(function(){ $("#datefilter-container .js-command").click(function(){ $(this).parent("#datefilter-container").find("#datefilter").toggleClass("open"); }); });
base.html
<script src="{% static 'date_filter_toggle.js' %}"></script>
Don’t forget to include your JavaScript file on the page!
With the HTML, CSS, and JavaScript added, our initial date filter is hidden behind the height: 0;
style, like so:
Clicking on the element triggers JavaScript to toggle the open
class on our div#datefilter
element, overriding the height: 0;
style and showing us the element we’ve spent all this time building:
Cool! How does it work?
Looks like there’s plenty of great shows to choose from this weekend! TallyMusic is an open-source project, so feel free to visit its repo here.