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!
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
.
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:
Python1# 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 theOrderingFilter
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.
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.
Python1import 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()}')
Now, we'll perform GET requests to sort our To-Do items by a single field:
Python1# 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.
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.
Python1# 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:
- Sort items by
priority
descending - Break
priority
ties bytask
descending - Break ties in
task
byassignee
ascending
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.
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:
Python1# 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 theDjangoFilterBackend
andOrderingFilter
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.
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.
Python1response = 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'
).
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!