Lesson 3
Enhancing Your To-Do API with Sorting
Introduction

Welcome back! So far, we've learned how to enhance our Django-based To-Do API by adding filtering capabilities. You now know how to filter todo items based on both simple and complex criteria, making your API more powerful and user-friendly.

Today, we will focus on adding sorting capabilities to our To-Do API. Sorting is crucial for making APIs more efficient and user-friendly by allowing users to organize data in meaningful ways. By the end of this lesson, you'll be able to sort your To-Do items based on various fields like priority and task name.

Let's get started!

Recap of Previous Setup

In the previous lesson, we set up various filters for our Todo model. Though filters are perfectly compatible with sorting, we will omit them for this lesson. This will allow us to focus solely on sorting problems and mastering them before learning to combine them with filtering.

That said, the setup is the same as at the start of the previous lesson: we have a Todo model with fields task, completed, assignee, priority, and group.

Integrating the OrderingFilter into the API

To enable sorting, we will use the OrderingFilter from the Django REST framework. This filter lets us specify which fields our users can use to sort the data.

First, we need to update our view to include the OrderingFilter. Here's how you do it:

Python
1# project/myapp/views.py 2from rest_framework.filters import OrderingFilter 3 4class TodoListCreate(generics.ListCreateAPIView): 5 queryset = Todo.objects.all() 6 serializer_class = TodoSerializer 7 filter_backends = [OrderingFilter] 8 ordering_fields = ['priority', 'task'] # Specify sortable fields
  • filter_backends = [OrderingFilter]: This line includes the OrderingFilter in our view, allowing us to handle sorting.
  • ordering_fields = ['priority', 'task']: This line specifies the fields by which users can sort the To-Do items, namely by priority and task.

And that’s it! With these small code changes, we've empowered our API with sorting capabilities.

Testing the Sorting Functionality: Setup

First, let’s add some sample To-Do items to test the sorting functionality. We will include a mix of task names to make their sorting more meaningful.

Python
1import requests 2 3base_url = 'http://127.0.0.1:8000/api/todos/' 4 5# Example data 6todos = [ 7 {"task": "Buy groceries", "completed": False, "priority": 1, "assignee": "Alice", "group": "Errands"}, 8 {"task": "Prepare presentation", "completed": True, "priority": 2, "assignee": "Bob", "group": "Work"}, 9 {"task": "Go to gym", "completed": False, "priority": 3, "assignee": "Charlie", "group": "Health"}, 10 {"task": "Finish homework", "completed": True, "priority": 1, "assignee": "Alice", "group": "Study"} 11] 12 13# Create TODO items 14for todo in todos: 15 response = requests.post(base_url, json=todo) 16 print(f'Created TODO: {response.json()}')
Testing the Sorting Functionality: Sorting by Single Field

Now, we'll perform GET requests to sort our To-Do items by a single field:

Python
1# Sort by priority ascending 2response = requests.get(base_url, params={'ordering': 'priority'}) 3 4# Sort by priority descending 5response = requests.get(base_url, params={'ordering': '-priority'})

Sorting by priority in ascending and descending order allows users to see tasks based on importance. Note that we use the minus (-) sign to indicate sorting in descending order.

Testing the Sorting Functionality: Tie Breaking

Next, let's sort our To-Do items by multiple fields to demonstrate tie-breaking. Different tasks can have the same priority. We will handle these ties by sorting tasks by their names in ascending alphabet order in case they have equal priority.

Python
1# Sort by priority, then by task ascending as tie-breaker 2response = requests.get(base_url, params={'ordering': 'priority,task'}) 3 4# Sort by priority descending, then by task ascending as tie-breaker 5response = requests.get(base_url, params={'ordering': '-priority,task'})

Using multiple fields, like priority and task, for sorting helps order To-Do items more granularly. When priority values are the same, the task field is used as a tie-breaker to provide a consistent order.

Note that you can separately control asc/desc order of fields by using the minus sign. Also, you can specify any number of fields for sorting, which will be used in the order you provided them. For example, if the 'ordering' is -priority,-task,assignee, then Django will:

  1. Sort items by priority descending
  2. Break priority ties by task descending
  3. Break ties in task by assignee ascending
Common Pitfalls and Troubleshooting Tips

Sorting is generally straightforward, but a common pitfall is missing or incorrect sorting parameters:

  • Always ensure the parameters match the ordering_fields specified.
  • If you try to sort by a field not listed in ordering_fields, it will be ignored.

By being aware of these pitfalls, you can ensure your API handles sorting correctly across different scenarios.

Combining Filtering and Sorting

Now that you have mastered both filtering and sorting independently, you can combine them to create a more powerful and versatile To-Do API. The setup is straightforward and similar to what you've already learned.

Here's how you can integrate both filtering and sorting in the view:

Python
1# project/myapp/views.py 2from rest_framework import generics 3from rest_framework.filters import OrderingFilter 4from django_filters.rest_framework import DjangoFilterBackend 5 6class TodoListCreate(generics.ListCreateAPIView): 7 queryset = Todo.objects.all() 8 serializer_class = TodoSerializer 9 filter_backends = [DjangoFilterBackend, OrderingFilter] 10 filterset_fields = ['completed', 'assignee', 'priority', 'group'] 11 ordering_fields = ['priority', 'task']
  • filter_backends = [DjangoFilterBackend, OrderingFilter]: This line includes both the DjangoFilterBackend and OrderingFilter in our view, allowing us to handle both filtering and sorting simultaneously.
  • filterset_fields = ['completed', 'assignee', 'priority', 'group']: This line specifies the fields by which users can filter the To-Do items.
  • ordering_fields = ['priority', 'task']: This line specifies the fields by which users can sort the To-Do items.
Example Request: Filtering and Sorting

Below is a sample request for filtering and sorting your To-Do items. We provide both filtering keys and the ordering key in the params dictionary.

Python
1response = requests.get(base_url, params={'completed': 'False', 'priority__gt': 1, 'ordering': 'priority'})

In this example:

  • We filter the To-Do items to include only those that are not completed and have a priority greater than 1.
  • We sort the filtered items by priority in ascending order ('ordering': 'priority').
Summary and Next Steps

You've now successfully added sorting capabilities to your To-Do API! Let's recap what we've covered:

  • We reviewed our existing setup.
  • We integrated the OrderingFilter into our views.
  • We tested our sorting functionality using real API calls.
  • We discussed common pitfalls and how to avoid them.

Great job making it to the end of the course! With this knowledge, your To-Do API is now more versatile and efficient. Make sure to try the practice exercises to solidify what you've learned, and feel free to apply these skills to real-world projects. Happy coding!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.