django-vuejs-api-views

Translation Table

English Chinese
front-end 前端
back-end 后端
pagination 分页
tweaking 拧(这里应该是修改的意思)
queries 查询
Decimal 十进制
querysets 查询集

Building a Modern Web Application with Django REST Framework and Vue: Building Views and REST API

Throughout this part of these tutorial series you will continue developing a CRUD (Create, Read, Update and Delete) application with a restful API back-end and a Vue front-end using Django, Django REST framework and Vue (with Axios as an HTTP client). In this part you’ll specifically build the REST API and the front-end views to consume and display data from the API endpoints. You will also see how to integrate your Vue application with your Django back-end in production. As always you can find the source code of the demo project in this Github repository.

You can check the second article from this link

  • Building the REST API: You will create a simple REST API around one model (Product) with DRF(Django REST Framework) and learn how to add pagination to your APIs.
  • Creating the Service to Consume the API: You will create the class that interfaces with your API using Axios.
  • Creating the Front End Views: You will create different views and routes for the Vue application and see how you can protect some routes from non authenticated users.
  • Getting Ready for Production: Finally you’ll prepare your app for production by tweaking some settings in Vue and Django parts.

Building the REST API

Django REST framework is a powerful and easy to use package for building Web APIs.

Let’s get started by building a simple REST API using Django REST framework.

Adding the Product Model

Django has a powerful ORM (Object Relational Mapper) that allows you to work with multiple database management systems without actually writing any SQL. All you need to do is to define models in Python classes and Django will take care of mapping Python classes to SQL queries.

The API is built around a simple product model so continuing with the project you’ve built in the previous part open the catalog/models.py file then add the following model

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from django.db import models

class Product(models.Model):

sku = models.CharField(max_length=13,help_text="Enter Stock Keeping Unit")
name = models.CharField(max_length=200, help_text="Enter product name")
description = models.TextField(help_text="Enter product description")

buyPrice = models.DecimalField(decimal_places=2, max_digits=20,help_text="Enter product price per unit")
sellPrice = models.DecimalField(decimal_places=2, max_digits=20,help_text="Enter product price per unit")

unit = models.CharField(max_length=10,help_text="Enter product unit")

quantity = models.DecimalField(decimal_places=1, max_digits=20,help_text="Enter quantity")

def get_absolute_url(self):
"""
Returns the url to access a particular instance of Product.
"""
return reverse('product-detail-view', args=[str(self.id)])

def __str__(self):

return self.sku

This is a Python class that extends the special Django class Model which is imported from the django.db.models built-in package. Every Django model needs to extends the Modelclass. You then specify the model fields using classes like CharField, TextField and DecimalField etc.

Now you need to migrate your database to add the new changes

1
2
python manage.py makemigrations
python manage.py migrate

Next let’s add some seed data using a data migration

So first make an empty migration by running the following command:

1
python manage.py makemigrations catalog --empty

Next open your migration file in your app migrations folder (catalog/migrations) then create a function that will executed by the RunPython() method when you apply your migration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from django.db import migrations
from django.conf import settings

def create_data(apps, schema_editor):
Product = apps.get_model('catalog', 'Product')
Product(sku='sku1',name='Product 1', description='Product 1', buyPrice=100 , sellPrice=100,unit='kilogram', quantity=100).save()
##...

class Migration(migrations.Migration):
dependencies = [
('catalog', '0001_initial'),
]
operations = [
migrations.RunPython(create_data),
]

You can then migrate your database to create the initial data

1
python manage.py migrate

Adding the Serializer Class

From Django REST framework docs here is the definition of a serializer

Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

Serializers允许将复杂数据(如查询集和模型实例)转换为Python数据类型,然后可以轻松地将其呈现为JSON,XML或其他内容类型。 序列化程序还提供反序列化,允许在首次验证传入数据后将解析后的数据转换回复杂类型。

Create a serializers.py file inside your the catalog app folder then add the following code to create a serializer class for the product model

1
2
3
4
5
6
7
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):

class Meta:
model = Product
fields = ('pk','sku', 'name', 'description', 'buyPrice','sellPrice','unit','quantity')

Adding the API Views

After adding the database model and the serializer class and also some seed data the next thing is to create the API views that will be responsible for creating, updating, deleting and fetching data from the database and send it back to users as JSON database when users request the appropriate API endpoint so go ahead and open the catalog/views.py file then start by adding the following imports

1
2
3
4
5
6
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import Product
from .serializers import *

This code imports different classes from DRF package, paginator classes to add pagination and then the Product model and its serializer class.

Adding the Product List/Create API View

In your catalog/views.py add the following view function which can process either GET or POST requests to either return paginated list of products or create a product.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@api_view(['GET', 'POST'])
def product_list(request):
"""
List products, or create a new product.
"""
if request.method == 'GET':
data = []
nextPage = 1
previousPage = 1
products = Product.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(products, 10)
try:
data = paginator.page(page)
except PageNotAnInteger:
data = paginator.page(1)
except EmptyPage:
data = paginator.page(paginator.num_pages)

serializer = ProductSerializer(data,context={'request': request} ,many=True)
if data.has_next():
nextPage = data.next_page_number()
if data.has_previous():
previousPage = data.previous_page_number()

return Response({'data': serializer.data , 'count': paginator.count, 'numpages' : paginator.num_pages, 'nextlink': '/api/products/?page=' + str(nextPage), 'prevlink': '/api/products/?page=' + str(previousPage)})

elif request.method == 'POST':
serializer = ProductSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

This function first checks if it’s a GET or POST request then preforms the processing based on the type of the request:

  • If it’s a GET request, the function retrieves the page number from the GET request or use the first page by default if no page is submitted then retrieves the request page of products, serialize it and return it back alongside with other information such as the next page and previous page links.
  • If it’s a POST request, the function creates the product based on the POST data.

Adding the Product Detail API View

Now you need to add the view function that will be responsible for getting, updating or deleting a single product by id depending on the type of the HTTP request (GET, PUT or DELETE).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@api_view(['GET', 'PUT', 'DELETE'])
def product_detail(request, pk):
"""
Retrieve, update or delete a product instance.
"""
try:
product = Product.objects.get(pk=pk)
except Product.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)

if request.method == 'GET':
serializer = ProductSerializer(product,context={'request': request})
return Response(serializer.data)

elif request.method == 'PUT':
serializer = ProductSerializer(product, data=request.data,context={'request': request})
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

elif request.method == 'DELETE':
product.delete()
return Response(status=status.HTTP_204_NO_CONTENT)