Building a carpool web API with Django (part 3)
In part 2 of the series we added some validation to our custom User
model as well as unit tests. In this post we are going to create more models – Vehicle
, Place
and Trip
.
Vehicle
Let’s start by adding a Vehicle
model that will hold information about a vehicle such as make, model, image etcetera. Let’s go to our kapool
directory and activate our virtual environment by running pipenv shell
. You should see the prefix (kapool)
on your terminal to indicate that the virtual environment is now active. Let’s install pillow, an image processing library that Django uses. Run the following command:
pipenv install pillow==6.2.0
With pillow installed let’s create a new app called vehicles
by running this command:
python manage.py startapp vehicles
Before we forget we need to register our vehicles
app to our project by adding it to the list of INSTALLED_APPS
in our kapool_project/settings.py
:
# kapool_project/settings.py
INSTALLED_APPS = [
# ...
'vehicles.apps.VehiclesConfig', # new
]
While we are still in the settings
module we need to tell Django where our media files will be stored. Let’s add MEDIA_ROOT
and MEDIA_URL
configurations to our settings.
# kapool_project/settings.py
MEDIA_URL = '/media/' # new
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # new
Now let’s go to the vehicles/models.py
file and create our Vehicle
model:
# vehicles/models.py
from django.contrib.auth import get_user_model
from django.db import models
from django.utils.translation import ugettext_lazy as _
class Vehicle(models.Model):
user = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
related_name='vehicles',
verbose_name=_('Owner')
)
make = models.CharField(
max_length=30,
verbose_name=_('Make'),
null=False,
blank=False
)
model = models.CharField(
max_length=30,
verbose_name=_('Model'),
null=False,
blank=False
)
reg_number = models.CharField(
max_length=30,
verbose_name=_('Registration number'),
null=False,
blank=False
)
image = models.ImageField(
upload_to='vehicles/',
verbose_name=_('Image'),
null=True,
blank=True
)
def __str__(self):
return f'{self.make} {self.model} owned by {self.user}'
class Meta:
verbose_name = _('Vehicle')
verbose_name_plural = _('Vehicles')
Let’s make migrations by running the following command:
python manage.py makemigrations
And migrate our changes to the database:
python manage.py migrate
We now need to register our vehicle model to our admin page:
# vehicles/admin.py
from django.contrib import admin
from .models import Vehicle
@admin.register(Vehicle)
class VehicleAdmin(admin.ModelAdmin):
list_display = ('make', 'model', 'reg_number')
Now run your server using this command python manage.py runserver
and go to http://localhost:8000/admin/
. You will see the Vehicles
section where you can view and add vehicles.
Place
We need to add a Place
model that will represent the origin and destination of a Trip
. Once again let’s create a new app called places
by running this command after we’ve stopped our server if it was running:
python manage.py startapp places
And add the new app to the INSTALLED_APPS
list in kapool_project/settings.py
:
# kapool_project/settings.py
INSTALLED_APPS = [
# ...
'places.apps.PlacesConfig', # new
]
Let’s now create the Place
model inside places/models.py
:
# places/models.py
from django.db import models
from django.utils.translation import ugettext_lazy as _
class Place(models.Model):
name = models.CharField(
max_length=100,
unique=True,
null=False,
blank=False,
verbose_name=_('Name')
)
def __str__(self):
return self.name
class Meta:
verbose_name = _('Place')
verbose_name_plural = _('Places')
Let’s migrate our changes to the database:
python manage.py makemigrations && python manage.py migrate
Register the model to the admin site:
from django.contrib import admin
from .models import Place
@admin.register(Place)
class PlaceAdmin(admin.ModelAdmin):
list_display = ('name',)
You can run your server and go to the admin page to see if you have a Places
section.
Trip
Let’s now add the Trip
model and like before we first create a new app called trips
:
python manage.py startapp trips
and add it to the list of installed apps:
# kapool_project/settings.py
INSTALLED_APPS = [
# ...
'trips.apps.TripsConfig', # new
]
We can now create our Trip
model in trips/models.py
:
# trips/models.py
from datetime import date
from django.core.exceptions import ValidationError
from django.contrib.auth import get_user_model
from django.db import models
from django.utils.translation import ugettext_lazy as _
from places.models import Place
from vehicles.models import Vehicle
class Trip(models.Model):
user = models.ForeignKey(
get_user_model(),
on_delete=models.CASCADE,
null=False,
blank=False,
related_name='trips',
verbose_name=_('Driver'),
)
origin = models.ForeignKey(
Place,
on_delete=models.CASCADE,
null=False,
blank=False,
related_name='trip_origins',
verbose_name=_('From')
)
destination = models.ForeignKey(
Place,
on_delete=models.CASCADE,
null=False,
blank=False,
related_name='trip_destinations',
verbose_name=_('To')
)
vehicle = models.ForeignKey(
Vehicle,
on_delete=models.CASCADE,
null=False,
blank=False,
related_name='trip_vehicles',
verbose_name=_('Vehicle')
)
trip_date = models.DateField(
null=False,
blank=False,
verbose_name=_('Trip date')
)
def save(self, *args, **kwargs):
if self.origin == self.destination:
raise ValidationError(
'Origin and destination cannot be the same'
)
if self.trip_date < date.today():
raise ValidationError(
'Trip date cannot be in the past'
)
super(Trip, self).save(*args, **kwargs)
def __str__(self):
return f'{self.origin} to {self.destination} by {self.user}'
class Meta:
verbose_name = _('Trip')
verbose_name_plural = _('Trips')
We have added some validation to our model to ensure that origin
and destination
cannot be the same and also the trip date cannot be in the past. Now let’s migrate our model to the database:
python manage.py makemigrations && python manage.py migrate
And finally let’s register our model to the admin site:
# trips/admin.py
from django.contrib import admin
from .models import Trip
@admin.register(Trip)
class TripAdmin(admin.ModelAdmin):
list_display = ('trip_date', 'origin', 'destination', 'user',)
What did we do?
In this post we created three models – Vehicle
, Place
and Trip
with some validation on the Trip
model. Now we have most of the models we need to build our API. In the next post we will start working on our REST
API. You can check the source code for the project on GitHub. Once again, thanks so much for reading.
Comments