Angular API Calls with Django, Part 2: Building the Micro-Blog App
This is the second part of a two-part series exploring the use of the Angular 6 HttpClient to make API calls against a Django back-end using Django Rest Framework. In the first part, we learned how to authenticate against Django using the Django Rest Framework JWT package. This post demonstrates how to set up the Django models and views for the micro-blogging app, as well as the Angular Service and templates.
Overview
This is a decoupled application using two different frameworks. Thus, the data has to flow through several steps to get from the database to the user's screen. Here is a simple diagram of the data flow:
SQLite Database → Django Model → Django Serializer → Django ViewSet → Angular Service → Angular Component
This tutorial will explore how to create each of these pieces for our micro-blogging application.
The Django App
The Django models
Our micro-blog application contains two relevant data models: the User and the BlogPost. The User model is provided out-of-the-box by Django, so in our app's models, we only need to define the model class for our BlogPost. This is quite simple and defines a few fields, plus the magic Python "to-string" method called __str__()
.
microblog/models.py:
from django.db import models from django.contrib.auth.models import User from django.utils import timezone class BlogPost(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) date = models.DateTimeField( default=timezone.now ) body = models.CharField(default='', max_length=200) def __str__(self): return self.body
Once the model class is created, you can create and run Django migrations to persist the schema to the database. However, if you use the working example code on GitHub, the SQLite database already contains the necessary schema, and some test data as well.
The Serializer
Django Rest Framework works on a concept of Models, Serializers, and ViewSets. A Serializer describes how to convert the model objects to JSON and back. The Django ORM uses model classes, and the API endpoints use JSON. The Serializer is how one gets translated to the other.
microblog/serializers.py:
from django.contrib.auth.models import User from rest_framework import serializers from .models import BlogPost class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ('id', 'username', 'first_name', 'last_name') class BlogPostSerializer(serializers.ModelSerializer): user = serializers.StringRelatedField(many=False) class Meta: model = BlogPost fields = ('id', 'user', 'date', 'body')
Unlike our model classes above, we do need to provide a serializer for the User model. Django Rest Framework does not proivde this for us, even though the User model itself comes directly from Django.
In addition, we create a BlogPostSerializer class, which defines which fields on the BlogPost model should be converted to JSON. Notice that we also define a relationship to the User class. This means that, when we serialize a BlogPost object, the resulting JSON will contain a nested object which is a serialized User model. The JSON representation of a BlogPost might look like this:
{ "id": 1 "user": { "id": 10, "username": "alice123", "first_name": "Alice", "last_name": "Smith" }, "date": 1528071221, "body": "The quick brown fox jumped over the lazy dog" }
The Viewset
The next thing we need for Django Rest Framework is the ViewSet. This is a collection of Django Views (a.k.a., controllers) which are contained within a class.
microblog/views.py:
from django.shortcuts import render from django.contrib.auth.models import User from rest_framework import viewsets, permissions from .models import BlogPost from . import serializers from .permissions import ReadOnly def index(request, path=''): return render(request, 'index.html') class UserViewSet(viewsets.ModelViewSet): """ Provides basic CRUD functions for the User model """ queryset = User.objects.all() serializer_class = serializers.UserSerializer permission_classes = (ReadOnly, ) class BlogPostViewSet(viewsets.ModelViewSet): """ Provides basic CRUD functions for the Blog Post model """ queryset = BlogPost.objects.all() serializer_class = serializers.BlogPostSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, ) def perform_create(self, serializer): serializer.save(user=self.request.user)
Like the Serializers above, we have a ViewSet for both the User model and the BlogPost model.
In this example, the app does not allow editing the User models through the API, so the UserViewSet is configured with permission_classes = (ReadOnly, )
preventing the API from writing to it. How do you edit the user profiles, you ask? That's out of scope for this example, but the built-in Django admin app provides a way to do this should you need to. When building your own app, you might want to create an Angular component to allow users to edit their profiles, and change the ReadOnly permission to a different permission, allowing the users to edit their own profiles and no one else's.
The BlogPostViewSet class has a different permission class called IsAuthenticatedOrReadOnly. This allows the public to view any blog posts in our app, but only users who are logged in can post.
The Django URL configuration
We also need to add the ViewSet's URLs to our app's URL configuration.
First, we add the ViewSet URLs to our microblog app:
microblog/urls.py
from django.urls import path, include from rest_framework import routers from . import views router = routers.DefaultRouter(trailing_slash=False) router.register(r'posts', views.BlogPostViewSet) router.register(r'users', views.UserViewSet) urlpatterns = [ path(r'api/', include(router.urls)), path(r'', views.index, name='index') ]
Next, add the app's URLs to the project's URLs:
angular_django_example/urls.py
... urlpatterns = [ path('admin/', admin.site.urls), path(r'', include('microblog.urls')), # add this path(r'api-token-auth/', obtain_jwt_token), path(r'api-token-refresh/', refresh_jwt_token), ]
Trying out the API
Django Rest Framework comes with the Swagger API viewer already built in. To see what's available in the API, all you need to do is run python manage.py runserver
and visit localhost:8000/api to see the API endpoints in action.
Calling the API from Angular
We have completed the setup of the back end of the application. Now it's time to create our Angular components and services. These will call the API endpoints and also provide the user interface for the app.
In the previous post, we already set up the Django templates needed to serve the Angular app, so we can dive right in to the Angular code itself.
The Component and Template
In Part 1, we created the basic Angular component. Now, all we need is to add some additional properties and methods for working with the Blog Posts.
microblog/front-end/app.component.ts
Back to Top