Welcome!
Build a Cassandra Python REST Service
The first step to creating a microservice is to create a service. Let's see how to add a REST front end on Cassandra with Python and Django!
In this scenario, we'll learn how to:
- Install the necessary Django framework
- Configure a REST service with Django
- Connect the Django REST service to Cassandra
Python makes things easy and Django makes them even easier! We'll get you started!
Check out our datastax.com/dev site, where you can find many more resources to help you succeed with Apache Cassandra™.
ver 0.004
Congratulations!
You've completed the scenario!
Scenario Rating
In this scenario, we learned how to:
- Install the necessary Django framework
- Configure a REST service with Django
- Connect the Django REST service to Cassandra
This is a simple service, but it illustrates the important broad brush strokes.
Your environment is currently being packaged as a Docker container and the download will begin shortly. To run the image locally, once Docker has been installed, use the commands
cat scrapbook_datastax_cassandra-k8s/cassandra-django_container.tar | docker load
docker run -it /datastax_cassandra-k8s/cassandra-django:
Oops!! Sorry, it looks like this scenario doesn't currently support downloads. We'll fix that shortly.

Steps
Build a Cassandra Python REST Service
Set up the Django server
In this step, we are going to set up the web server. Let's start by clicking the following to create a virtual environment.
python3 -m venv env
source env/bin/activate
apt -y install python3 python3-pip
With our virtual environment set up, we're ready to set up the Django framework and create our rest
project.
Click the following.
pip install djangorestframework
django-admin startproject rest .
python manage.py migrate
Let's start our service, by clicking the following, just to show that we can run the service. It won't do much... yet!
python manage.py runserver
Let's hit the service to verify it's up and running. If the service is running, the following command will print out the HTML from the server. We'll execute the following command from a separate terminal (just click the following).
curl 127.0.0.1:8000
Excellent! We have a running HTTP service!
Serve up some JSON
In the previous step we got the service running. But, it's only serving up an HTML page. In this step we'll figure out how to serve up some JSON.
For this, we need to create our REST app.
Our app will be a simple service for keeping track of user credentials.
We'll call it users
.
Click on the following, which will stop the service in terminal 1 by sending a Ctrl-C and create the app.
python manage.py startapp users
We need to configure the users
app, which includes:
- Making Django aware of our new app by changing settings.py
- Creating a
User
model to store user credentials (i.e.,username
andpassword
) in users/models.py - Creating a serializer for our
User
model, which converts the credential info into JSON in users/serializers.py - Creating a view, or endpoint, for our
users
service in users/views.py - Adding a URL for the endpoint to rest/urls.py
Open the settings.py file by clicking the following.
rest/settings.py
You will want to make the INSTALLED_APPS
section like the following, which adds two entries at the bottom of the list (find the list and replace it with the content shown).
You can click the following to copy the contents to the clipboard.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'users.apps.UsersConfig',
]
What did we just do?
TheINSTALLED_APPS
list tells Django which apps to install.
We need the REST framework, so we added that to the list.
We also added our User app that we created above.
Next, add a User
model to models.py.
Click on the following to open the file.
users/models.py
Add the code to the file by clicking the following.
from django.db import models class User(models.Model): username = models.CharField(max_length = 20) password = models.CharField(max_length = 20)
What did we just do?
We need a place to store Cassandra records before we write them and after we read them. The model contains classes to do that. In this example, we created aUser
model class that maps to the table we will use.
The table will have two columns: username
and password
- just like our model.
We'll also create a serializers.py file to serialize the model. Click the following to open the file.
users/serializers.py
Here's the serializer code. Click on the code to copy it to the file.
from django.db import models from rest_framework import serializers from .models import User class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = '__all__'
What did we just do?
The job of the serializer class is to convert model classes to JSON and JSON to models. Django does the heavy lifting for us, so we need to import theserializers
package.
We also need to import our User
model.
We name the class based on our model name (e.g., User
) and add the word Serializer
.
Notice that the UserSerializer
class derives from the Django ModelSerializer
class.
In the inner
Meta
class, we specify which fields we want to include in the serialization.
If we want to include all the fields, we can use '__all__'
.
Alternatively, we can specify the fields we want to include in a tuple (e.g., ('username', 'password')
).
Finally, edit the views.py file to serve up the JSON.
You see that we have hard-coded the returned values (i.e., MyName
and MyPassword
).
We'll see how to extract these values from Cassandra in the next steps.
Click the following to open the file.
users/views.py
Include this code by clicking the following.
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .models import User from .serializers import UserSerializer class User(APIView): def get(self, request): user = User() user.username = 'MyName' user.password = 'MyPassword' serializer = UserSerializer(user) return Response(serializer.data) def post(self, request): pass
What did we just do?
The users/view.py file contains the code that Django executes when the service receives a request. You notice the two methodsget()
and post()
that correspond to the HTTP GET and POST requests.
For now, we just create a User
instance, load it up with some hard-coded values, pass it to the serializer and send the serialized results back to the client.
Finally, we'll add a url pattern to handle the request. Open the rest/urls.py file by clicking the following.
rest/urls.py
Replace the contents of the file with the following by clicking on the code.
from django.contrib import admin from django.urls import path from rest_framework.urlpatterns import format_suffix_patterns from users import views urlpatterns = [ path('admin/', admin.site.urls), path('user/', views.User.as_view()), ] urlpatterns = format_suffix_patterns(urlpatterns)
Let's restart the service in terminal 1 by clicking on the following.
python manage.py runserver
That's all there is to it. Let's hit the service in terminal 2 just to make sure it works. Click the following.
curl 127.0.0.1:8000/user/ | jq
Outstanding! The service is now serving up JSON!
Create the Python code
In this step, we'll demonstrate Python code to access the database.
Let's start by creating a user_credentials
table.
We've already installed and started Cassandra for you, so just click the following to stop the service and create the keyspace and table.
cqlsh -e "
CREATE KEYSPACE user_management
WITH REPLICATION = {
'class' : 'SimpleStrategy',
'replication_factor' : 1
};
CREATE TABLE user_management.user_credentials(
username text,
password text,
PRIMARY KEY(username));"
Note: We would never store passwords in plain-text in a production system, but we will for this example to keep things simple.
We can add a handful of records to the table. Click the following.
cqlsh -e "
INSERT INTO user_management.user_credentials
(username, password)
VALUES ('User1', 'YouWontGuessThis');
INSERT INTO user_management.user_credentials
(username, password)
VALUES ('User2', 'SuperSecret');
INSERT INTO user_management.user_credentials
(username, password)
VALUES ('User3', 'UncrackablePassword');"
Next, let's create a Python program to access the table. We need to install the Python driver for Cassandra. Click the following.
pip install cassandra-driver
Let's use the Python interpreter to try out some code. Launch the interpreter by clicking the following.
python
We'll connect to the cluster and create a session. Click the following.
from cassandra.cluster import Cluster
cluster = Cluster(protocol_version = 3)
session = cluster.connect()
Now, let's query our table by clicking the following.
results = session.execute('SELECT * FROM user_management.user_credentials')
for result in results:
print(result.username, result.password)
_ = '^^^ See the results!'
Exit the interpreter by clicking the following.
quit()
Perfect! The code you just completed gives you an example of how to access Cassandra from Python!
Plug the Python code into your service
In the previous step, we saw how to use Python to access the database. In this step, we'll access the database to retrieve a user's credentials based on a hard-coded username.
Let's modify the users/views.py file to access the database.
As mentioned, for now we will use a hard-coded username for the request - User1
.
In the next step we'll see how to get the username
from the URL.
users/views.py
In the following code, we add an import for the driver.
We also replace the old code that just created a user with code that gets the user from the database.
In both the old and new code, we serialize the User
the same way.
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .models import User from .serializers import UserSerializer # Here is the import for the python driver from cassandra.cluster import Cluster class User(APIView): def get(self, request): # here's the old code that just creates a User: ''' user = User() user.username = 'MyName' user.password = 'MyPassword' ''' # here's the new code that gets the User from the database: cluster = Cluster(protocol_version = 3) session = cluster.connect() results = session.execute("SELECT * FROM user_management.user_credentials WHERE username = %s", ("User1", )) user = results.one() # serialize the user like before serializer = UserSerializer(user) return Response(serializer.data) def post(self, request): pass
Restart the service by clicking the following.
python manage.py runserver
Now, issue a request to the service to see our code work! Click the following.
curl 127.0.0.1:8000/user/ | jq
Great! we see that we can access the database from within the service and return the result!
Add the username to the URL
The last step in retrieving a user is to wire the username value from the URL to the query.
Modify the rest/urls.py file to add the username
.
rest/urls.py
Add the username
to the URL pattern.
from django.contrib import admin from django.urls import path from rest_framework.urlpatterns import format_suffix_patterns from users import views urlpatterns = [ path('admin/', admin.site.urls), path('user/<str:username>/', views.User.as_view()), ] urlpatterns = format_suffix_patterns(urlpatterns)
Then, add username
as the third parameter to the get()
method in users/views.py and use parameter in the query.
users/views.py
Here's the updated code.
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .models import User from .serializers import UserSerializer # Here is the import for the python driver from cassandra.cluster import Cluster class User(APIView): def get(self, request, username): cluster = Cluster(protocol_version = 3) session = cluster.connect() results = session.execute("SELECT * FROM user_management.user_credentials WHERE username = %s", (username, )) user = results.one() serializer = UserSerializer(user) return Response(serializer.data) def post(self, request): pass
Restart the service by clicking the following.
python manage.py runserver
Let's query for User2
by clicking the following.
curl 127.0.0.1:8000/user/User2/ | jq
Superb! Our REST service can handle GET requests!
POST user data to the service
Let's try writing data to our service.
We won't put the data in the database until the next step.
But, in this step we'll see how to capture the data in the post()
method.
We need to add code to the post()
method inside users/views.py.
users/views.py
Here's the code.
from django.http import JsonResponse from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .models import User from .serializers import UserSerializer # Here is the import for the python driver from cassandra.cluster import Cluster class User(APIView): def get(self, request, username): cluster = Cluster(protocol_version = 3) session = cluster.connect() results = self.session.execute("SELECT * FROM user_management.user_credentials WHERE username = %s", (username, )) user = results.one() serializer = UserSerializer(user) return Response(serializer.data) def post(self, request): serializer = UserSerializer(data=request.data) if serializer.is_valid(): print("in post *************************************************") print("username = "+serializer.data.get("username"), "password = "+serializer.data.get("password")) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Modify the rest/urls.py file to add the POST endpoint. Note that you must place this URL before the GET URL, otherwise the URL pattern is ambiguous.
rest/urls.py
Add the user/add/
endpoint URL pattern.
from django.contrib import admin from django.urls import path from rest_framework.urlpatterns import format_suffix_patterns from users import views urlpatterns = [ path('admin/', admin.site.urls), path('user/add/', views.User.as_view()), path('user/<str:username>/', views.User.as_view()), ] urlpatterns = format_suffix_patterns(urlpatterns)
Click the following to restart the service.
python manage.py runserver
Give it a try by clicking the following!
curl -X POST -d '{"username": "User4", "password": "PasswordFor4" }' -H 'Content-Type: application/json' 127.0.0.1:8000/user/add/ | jq
As you can see, the post()
method prints out the correct username
and password
values.
Now, we're all set to write the credentials to Cassandra - in the next step.
Woot! You see how to access POST data!
POST a user to the database
Let's complete the POST
and write the data to the database.
Under the print statements in users/views.py, add the code to store the user credentials in the database.
users/views.py
We'll give you a chance to figure this out on your own, but if you need help, you can check out the solution.
Solution
from django.http import JsonResponse from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status from .models import User from .serializers import UserSerializer # Here is the import for the python driver from cassandra.cluster import Cluster class User(APIView): def get(self, request, username): cluster = Cluster(protocol_version = 3) session = cluster.connect() results = self.session.execute("SELECT FROM user_management.user_credentials WHERE username = %s", (username, )) user = results.one() serializer = UserSerializer(user) return Response(serializer.data) def post(self, request): serializer = UserSerializer(data=request.data) if serializer.is_valid(): print("in post **") print("username = "+serializer.data.get("username"), "password = "+serializer.data.get("password")) cluster = Cluster(protocol_version = 3) session = cluster.connect() results = session.execute("INSERT INTO user_management.user_credentials (username, password) VALUES(%s, %s)", (serializer.data.get("username"), serializer.data.get("password"))) return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Before we post the new user, let's look at what's in the table.
cqlsh -e "SELECT * FROM user_management.user_credentials;"
We need to start the service again. Click the following.
python manage.py runserver
Now, post the new user.
curl -X POST -d '{"username": "User4", "password": "PasswordFor4" }' -H 'Content-Type: application/json' 127.0.0.1:8000/user/add/ | jq
Finally, verify that the post worked by looking at the contents of the table now. Click the following.
cqlsh -e "SELECT * FROM user_management.user_credentials;"
You now see the credentials for User4
in the table!