目錄

簡(jiǎn)介
Django是一套完善而強(qiáng)大的web開發(fā)框架, 結(jié)合Django Restframework我們可以非??斓拇罱ㄒ惶缀笈_(tái)的api, 該api主要特點(diǎn):
- 標(biāo)準(zhǔn)的Restful接口, 支持增刪改查
每個(gè)模型分列表和詳情兩種接口, 列表GET獲取列表/POST新建,詳情接口GET獲取詳情/PUT修改/DELETE刪除 - 所有接口自帶權(quán)限認(rèn)證
使用Basic Auth, 詳細(xì)權(quán)限可以通過Admin配置
而我們只需要設(shè)計(jì)好我們的Models(數(shù)據(jù)模型)
實(shí)現(xiàn)步驟
1. 環(huán)境搭建
使用Python3+Django2.1+Django Restframework
pip3 install django
pip3 install djangorestframework
2. 創(chuàng)建項(xiàng)目及應(yīng)用
創(chuàng)建一個(gè)名為django_shop的項(xiàng)目,進(jìn)入項(xiàng)目目錄,創(chuàng)建一個(gè)名為shop的應(yīng)用
django-admin startproject django_shop
cd django_shop
python3 -m manage.py startapp shop
3. 在項(xiàng)目設(shè)置中注冊(cè)我們的應(yīng)用及rest_framework
修改項(xiàng)目目錄下django_shop/settings.py文件
INSTALLED_APP列表中增加兩行, 注冊(cè)應(yīng)用及rest_framework框架
INSTALLED_APPS = [
...
'shop.apps.ShopConfig',
'rest_framework'
]
文件末尾增加如下REST_FRAMWORK配置, 以使Api權(quán)限生效
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
]
}
4. 設(shè)計(jì)和編寫Models(數(shù)據(jù)模型)
Models設(shè)計(jì)實(shí)際上就是數(shù)據(jù)庫(kù)表設(shè)計(jì), 一個(gè)Model對(duì)應(yīng)一張數(shù)據(jù)庫(kù)表, 數(shù)據(jù)模型(數(shù)據(jù)庫(kù)表)的設(shè)計(jì)是一個(gè)項(xiàng)目的核心, 我們需要考慮:
- 需要哪些模型(表)?
- 每個(gè)表包含什么字段?
- 表與表之間的相互關(guān)系(一對(duì)多/一對(duì)一/多對(duì)多)
我們這里設(shè)計(jì)4個(gè)模型(表):
- Category: 商品分類模型, 包含字段name(分類名稱), slug(分類鏈接)
- Product: 商品模型, 包含字段category(所屬分類), name(商品名稱), slug(商品鏈接), description(商品描述), price(商品價(jià)格), available(是否上架), created(創(chuàng)建時(shí)間), modified(修改時(shí)間)
- Order: 訂單模型, 包含字段username(客戶姓名), mobile(客戶電話), address(客戶地址), city(客戶城市), pay_status(是否支付), created(創(chuàng)建時(shí)間), modified(修改時(shí)間)
- OrderItem: 訂單條目(訂單中每種商品一個(gè)條目), 包含字段order(所屬訂單), product(訂購(gòu)的商品), quantity(訂購(gòu)數(shù)量)
修改項(xiàng)目目錄下的models.py, 創(chuàng)建我們需要的模型
from django.db import models
class Category(models.Model):
name = models.CharField("分類名稱", max_length=200, db_index=True)
slug = models.SlugField("分類鏈接", max_length=200, db_index=True, unique=True)
class Product(models.Model):
category = models.ForeignKey(Category, related_name='category', on_delete=models.CASCADE, verbose_name="所屬分類")
name = models.CharField("商品名稱", max_length=200, db_index=True)
slug = models.SlugField("商品鏈接", max_length=200, db_index=True)
description = models.TextField("商品描述", blank=True)
price = models.DecimalField("商品價(jià)格", max_digits=10, decimal_places=2)
available = models.BooleanField("是否上架", default=True)
created = models.DateTimeField("創(chuàng)建時(shí)間", auto_now_add=True)
updated = models.DateTimeField("更新時(shí)間", auto_now=True)
class Order(models.Model):
username = models.CharField("客戶姓名", max_length=50)
mobile = models.CharField("客戶電話", max_length=25)
address = models.CharField("客戶地址", max_length=250)
city = models.CharField("客戶城市", max_length=100)
pay_status = models.BooleanField("是否支付", default=False)
created = models.DateTimeField("創(chuàng)建時(shí)間", auto_now_add=True)
updated = models.DateTimeField("更新時(shí)間", auto_now=True)
class OrderItem(models.Model):
order = models.ForeignKey(Order, related_name='order_items', on_delete=models.CASCADE, verbose_name="所屬訂單")
product = models.ForeignKey(Product, related_name='product_items', on_delete=models.CASCADE, verbose_name="訂購(gòu)產(chǎn)品")
quantity = models.PositiveIntegerField("訂購(gòu)數(shù)量", default=1)
5. 生成數(shù)據(jù)庫(kù)表并創(chuàng)建超級(jí)用戶
在項(xiàng)目目錄下打開命令行窗口, 使用以下命令創(chuàng)建models.py對(duì)應(yīng)的表
python3 manage.py makemigrations
python3 manage.py migrate
使用以下命令創(chuàng)建超級(jí)用戶
python3 manage.py createsuperuser
輸入用戶名/郵箱/密碼(兩遍)創(chuàng)建超級(jí)用戶
6. 編寫Restful Api
6.1 為每個(gè)數(shù)據(jù)模型建立對(duì)應(yīng)的序列化器
每一個(gè)Model實(shí)際上都是一個(gè)Python類的對(duì)象, 對(duì)象一般只能存活于內(nèi)存中,想要進(jìn)行保存和傳輸(作為響應(yīng)返回), 我們一般需要將對(duì)象轉(zhuǎn)化為字符串, 這稱之為序列化
由于每個(gè)Model對(duì)象的結(jié)構(gòu)不同, 我們要為每個(gè)對(duì)象建立對(duì)應(yīng)的序列化器(用于將該Model對(duì)象轉(zhuǎn)為字符串)
在shop應(yīng)用目錄下新建文件夾api, 在api下新建serializers.py,用于存放所有Model的序列化器, 內(nèi)容如下:
from rest_framework import serializers
from ..models import Category, Product, Order, OrderItem
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category # 要序列化的模型
fields = '__all__' # 要序列化的字段
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
class OrderItemSerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'
默認(rèn)情況下, 每個(gè)Model都可以采用同樣的套路, 復(fù)制粘貼修改即可
6.2 為每個(gè)模型建立對(duì)應(yīng)的Restful Api
在標(biāo)準(zhǔn)的Restful Api模式中, 每個(gè)Model建立兩個(gè)接口:
- List接口: GET返回列表/POST新建
- Detail接口: GET返回詳情/PUT修改/DELETE刪除
在shop/api/目錄下新建views.py, 內(nèi)容如下:
from rest_framework import generics
from .serializers import CategorySerializer, ProductSerializer, OrderSerializer, OrderItemSerializer
from ..models import Category, Product, Order, OrderItem
class CategoryList(generics.ListCreateAPIView):
queryset = Category.objects.all()
serializer_class = CategorySerializer
class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Category.objects.all()
serializer_class = CategorySerializer
class ProductList(generics.ListCreateAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
class ProductDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
class OrderList(generics.ListCreateAPIView):
queryset = Order.objects.all()
serializer_class = OrderSerializer
class OrderDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Order.objects.all()
serializer_class = OrderSerializer
class OrderItemList(generics.ListCreateAPIView):
queryset = OrderItem.objects.all()
serializer_class = OrderItemSerializer
class OrderItemDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = OrderItem.objects.all()
serializer_class = OrderItemSerializer
套路同樣一致, 復(fù)制粘貼修改即可
- generics.ListCreateAPIView: 指該接口支持列表和新建
- generics.RetrieveUpdateDestroyAPIView: 指該接口支持詳情/更新/刪除
generics還支持各種單獨(dú)的方法, 詳見generics源碼(Pycharm中按住Ctrl點(diǎn)擊generics)
6.3 為接口掛載接口地址
在shop/api/下新建urls.py, 用于存放本應(yīng)用api的接口地址, 每個(gè)Model格式一樣, 內(nèi)容如下:
from django.urls import path
from . import views
app_name = 'shop' # 指定命名空間
urlpatterns = [
path('categories/', views.CategoryList.as_view(), name='category_list'),
path('categories/<pk>/', views.CategoryDetail.as_view(), name='category_detail'),
path('products/', views.ProductList.as_view(), name='product_list'),
path('products/<pk>/', views.ProductDetail.as_view(), name='product_detail'),
path('orders/', views.OrderList.as_view(), name='order_list'),
path('orders/<pk>/', views.OrderDetail.as_view(), name='order_detail'),
path('order_items/', views.OrderItemList.as_view(), name='order_item_list'),
path('order_items/<pk>/', views.OrderItemDetail.as_view(), name='order_item_detail'),
]
將應(yīng)用api的接口地址掛在到項(xiàng)目的總路由下
修改項(xiàng)目路徑django_shop目錄下的urls.py, 內(nèi)容如下:
from django.contrib import admin
from django.urls import path, include # 在原有的基礎(chǔ)上增加導(dǎo)入include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/shop/', include('shop.api.urls', namespace='shop')), # 增加該行
]
7. 運(yùn)行項(xiàng)目及調(diào)試接口
在項(xiàng)目路徑下打開命令窗口, 運(yùn)行 python3 manage.py runserver啟動(dòng)開發(fā)服務(wù)器
打開網(wǎng)頁(yè)訪問: http://127.0.0.1:8000/api/shop/categories/
即可看到分類列表接口(其他列表接口同理修改url即可, 如.../api/shop/projects/)
當(dāng)前尚無(wú)數(shù)據(jù)(非登錄狀態(tài)無(wú)權(quán)限修改數(shù)據(jù))
訪問: http://127.0.0.1:8000/admin/ 使用超級(jí)管理員登錄,并重新回到接口頁(yè)面, 可使用POST創(chuàng)建新數(shù)據(jù), 如下圖:

創(chuàng)建后重新刷新頁(yè)面(分類列表接口)即可看到創(chuàng)建的數(shù)據(jù)
分類詳情接口, 訪問: http://127.0.0.1:8000/api/shop/categories/1/
注意, 列表和詳情統(tǒng)一使用復(fù)數(shù)categories, 1為該分類的id

使用Postman測(cè)試Api
- 使用Postman測(cè)試所有接口都需要提供Basic Auth授權(quán), 操作方法如下

- 使用POST新建數(shù)據(jù)(支持表單和JSON格式), 其他接口及操作方法同理

注: 本次搭建的是通用的增刪改查接口, 一般還需要根據(jù)項(xiàng)目實(shí)際需要進(jìn)行添加和修改
下一節(jié)帶著大家從Models 10分鐘快速定制一套Admin后臺(tái)系統(tǒng)
PS: 雖然標(biāo)題是10分鐘搭建一套R(shí)estful Api接口, 但是實(shí)際寫這篇文章從下午7點(diǎn)下班一致在辦公室寫到凌晨1:20(現(xiàn)在), 碼字不易, 歡迎多多點(diǎn)贊/評(píng)論和贊賞, 如有什么其他想學(xué)的教程也可留言給我