So far, our RESTful Web Service performed CRUD operations on a single database table. Now, we want to create a more complex RESTful Web Service with the Django REST framework to interact with a complex database model.
A drone is an IoT (short for Internet of Things) device that interacts with many sensors and actuators, including digital electronic speed controllers linked to engines, propellers, and sensors. A drone is also known as an Unnamed Aerial Vehicle (UAV). We will code a RESTful Web Service that will allow us to register competitions for drones that are grouped into drone categories. In our previous RESTful Web Service, we had toys grouped in toy categories and we used a string field to specify the toy category for a toy. In this case, we want to be able to easily retrieve all the drones that belong to a specific drone category. Thus, we will have a relationship between a drone and a drone category.
We must be able to perform CRUD operations on diverse resources and resource collections. Many resources have relationships with other resources, and therefore, we won't work with simple models. We will learn how to establish different kinds of relationships between the models.
The following list enumerates the resources and the model name we will use to represent them in a Django REST framework:
- Drone categories (DroneCategory model)
- Drones (Drone model)
- Pilots (Pilot model)
- Competitions (Competition model)
The drone category (DroneCategory model) just requires a name.
We need the following data for a drone (Drone model):
- A foreign key to a drone category (DroneCategory model)
- A name
- A manufacturing date
- A bool value indicating whether the drone participated in at least one competition or not
- A timestamp with the date and time in which the drone was inserted in the database
We need the following data for a pilot (Pilot model):
- A name
- A gender value
- An integer value with the number of races in which the pilot participated
- A timestamp with the date and time in which the pilot was inserted in the database
We need the following data for the competition (Competition model):
- A foreign key to a pilot (Pilot model)
- A foreign key to a drone (Drone model)
- A distance value (measured in feet)
- A date in which the drone controlled by the pilot reached the specified distance value
We will use diverse options that the Django REST framework provides us to materialize the relationship between resources. This way, we will be able to analyze different configurations that will make it possible for us to know which is the best option based on the specific requirements of new web services that we will develop in the future.
The following table shows the HTTP verbs, the scope and the semantics for the methods that our new RESTful Web Service must support. Each method is composed by an HTTP verb and a scope. All the methods have well-defined meanings for all the resources and resource collections. In this case, we will implement the PATCH HTTP verb for all the resources:
HTTP verb |
Scope |
Semantics |
GET |
Drone category |
Retrieve a single drone category. The drone category must include a list of URLs for each drone resource that belongs to the drone category. |
GET |
Collection of drone categories |
Retrieve all the stored drone categories in the collection, sorted by their name in ascending order. Each drone category must include a list of URLs for each drone resource that belongs to the drone category. |
POST |
Collection of drone categories |
Create a new drone category in the collection. |
PUT |
Drone category |
Update an existing drone category. |
PATCH |
Drone category |
Update one or more fields of an existing drone category. |
DELETE |
Drone category |
Delete an existing drone category. |
GET |
Drone |
Retrieve a single drone. The drone must include its drone category description. |
GET |
Collection of drones |
Retrieve all the stored drones in the collection, sorted by their name in ascending order. Each drone must include its drone category description. |
POST |
Collection of drones |
Create a new drone in the collection. |
PUT |
Drone |
Update an existing drone. |
PATCH |
Drone |
Update one or more fields of an existing drone. |
DELETE |
Drone |
Delete an existing drone. |
GET |
Pilot |
Retrieve a single pilot. The pilot must include a list of the registered competitions, sorted by distance in descending order. The list must include all the details for the competition in which the pilots and his related drone participated. |
GET |
Collection of pilots |
Retrieve all the stored pilots in the collection, sorted by their name in ascending order. Each pilot must include a list of the registered competitions, sorted by distance in descending order. The list must include all the details for the competition in which the pilot and his related drone participated. |
POST |
Collection of pilots |
Create a new pilot in the collection. |
PUT |
Pilot |
Update an existing pilot. |
PATCH |
Pilot |
Update one or more fields of an existing pilot. |
DELETE |
Pilot |
Delete an existing pilot. |
GET |
Competition |
Retrieve a single competition. The competition must include the pilot's name that made the drone reach a specific distance and the drone's name. |
GET |
Collection of competitions |
Retrieve all the stored competitions in the collection, sorted by distance in descending order. Each competition must include the pilot's name that made the drone reach a specific distance and the drone's name. |
POST |
Collection of competitions |
Create a new competition in the collection. The competition must be related to an existing pilot and an existing drone. |
PUT |
Competition |
Update an existing competition. |
PATCH |
Competition |
Update one or more fields of an existing competition. |
DELETE |
Competition |
Delete an existing competition. |
In the previous table, we have a huge number of methods and scopes. The following table enumerates the URIs for each scope mentioned in the previous table, where {id} has to be replaced with the numeric id or primary key of the resource:
Scope |
URI |
Collection of drone categories |
/drone-categories/ |
Drone category |
/drone-category/{id} |
Collection of drones |
/drones/ |
Drone |
/drone/{id} |
Collection of pilots |
/pilots/ |
Pilot |
/pilot/{id} |
Collection of competitions |
/competitions/ |
Competition |
/competition/{id} |
Let's consider that http://localhost:8000/ is the URL for the RESTful Web Service running on Django's development server. We have to compose and send an HTTP request with the following HTTP verb (GET) and request URL (http://localhost:8000/competitions/) to retrieve all the stored competitions in the collection.
GET http://localhost:8000/competitions/
Our RESTful Web Service must be able to update a single field for an existing resource. In order to make this possible, we will implement the PATCH method. Remember that the PUT method is meant to replace an entire resource and the PATCH method is meant to apply a delta to an existing resource, that is, to update one or more fields for an existing resource.
We definitely want our RESTful Web Serice to support the OPTIONS method for all the resources and collections of resources. This way, we will provide a consistent web service.
We will use the ORM (short for Object-Relational Mapping) included in Django. In addition, we will take advantage of many features and reusable elements included in the latest version of the Django REST framework to make it easy to build our web service without writing a huge amount of code.
In this case, we will work with a PostgreSQL database. However, in case you don't want to spend time installing PostgreSQL, you can skip the changes we make in the Django REST framework ORM configuration and continue working with the default SQLite database, as we did with our first RESTful Web Service.