Django从Models 10分钟建立一套RestfulApi

目录

效果预览

简介

Django是一套完善而强大的web开发框架, 结合Django Restframework我们可以非常快的搭建一套后台的api, 该api主要特点:

  • 标准的Restful接口, 支持增删改查
    每个模型分列表和详情两种接口, 列表GET获取列表/POST新建,详情接口GET获取详情/PUT修改/DELETE删除
  • 所有接口自带权限认证
    使用Basic Auth, 详细权限可以通过Admin配置

而我们只需要设计好我们的Models(数据模型)

实现步骤

1. 环境搭建

使用Python3+Django2.1+Django Restframework

pip3 install django
pip3 install djangorestframework

2. 创建项目及应用

创建一个名为django_shop的项目,进入项目目录,创建一个名为shop的应用

django-admin startproject django_shop
cd django_shop
python3 -m manage.py startapp shop

3. 在项目设置中注册我们的应用及rest_framework

修改项目目录下django_shop/settings.py文件
INSTALLED_APP列表中增加两行, 注册应用及rest_framework框架

INSTALLED_APPS = [
    ...
    'shop.apps.ShopConfig',
    'rest_framework'
]

文件末尾增加如下REST_FRAMWORK配置, 以使Api权限生效

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
    ]
}

4. 设计和编写Models(数据模型)

Models设计实际上就是数据库表设计, 一个Model对应一张数据库表, 数据模型(数据库表)的设计是一个项目的核心, 我们需要考虑:

  • 需要哪些模型(表)?
  • 每个表包含什么字段?
  • 表与表之间的相互关系(一对多/一对一/多对多)

我们这里设计4个模型(表):

  • Category: 商品分类模型, 包含字段name(分类名称), slug(分类链接)
  • Product: 商品模型, 包含字段category(所属分类), name(商品名称), slug(商品链接), description(商品描述), price(商品价格), available(是否上架), created(创建时间), modified(修改时间)
  • Order: 订单模型, 包含字段username(客户姓名), mobile(客户电话), address(客户地址), city(客户城市), pay_status(是否支付), created(创建时间), modified(修改时间)
  • OrderItem: 订单条目(订单中每种商品一个条目), 包含字段order(所属订单), product(订购的商品), quantity(订购数量)

修改项目目录下的models.py, 创建我们需要的模型

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("商品价格", max_digits=10, decimal_places=2)
    available = models.BooleanField("是否上架", default=True)
    created = models.DateTimeField("创建时间", auto_now_add=True)
    updated = models.DateTimeField("更新时间", 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("创建时间", auto_now_add=True)
    updated = models.DateTimeField("更新时间", 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="订购产品")
    quantity = models.PositiveIntegerField("订购数量", default=1)

5. 生成数据库表并创建超级用户

在项目目录下打开命令行窗口, 使用以下命令创建models.py对应的表

python3 manage.py makemigrations
python3 manage.py migrate

使用以下命令创建超级用户

python3 manage.py createsuperuser

输入用户名/邮箱/密码(两遍)创建超级用户

6. 编写Restful Api

6.1 为每个数据模型建立对应的序列化器

每一个Model实际上都是一个Python类的对象, 对象一般只能存活于内存中,想要进行保存和传输(作为响应返回), 我们一般需要将对象转化为字符串, 这称之为序列化
由于每个Model对象的结构不同, 我们要为每个对象建立对应的序列化器(用于将该Model对象转为字符串)

在shop应用目录下新建文件夹api, 在api下新建serializers.py,用于存放所有Model的序列化器, 内容如下:

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__'

默认情况下, 每个Model都可以采用同样的套路, 复制粘贴修改即可

6.2 为每个模型建立对应的Restful Api

在标准的Restful Api模式中, 每个Model建立两个接口:

  • List接口: GET返回列表/POST新建
  • Detail接口: GET返回详情/PUT修改/DELETE删除
    在shop/api/目录下新建views.py, 内容如下:
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

套路同样一致, 复制粘贴修改即可

  • generics.ListCreateAPIView: 指该接口支持列表和新建
  • generics.RetrieveUpdateDestroyAPIView: 指该接口支持详情/更新/删除

generics还支持各种单独的方法, 详见generics源码(Pycharm中按住Ctrl点击generics)

6.3 为接口挂载接口地址

在shop/api/下新建urls.py, 用于存放本应用api的接口地址, 每个Model格式一样, 内容如下:

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'),
]

将应用api的接口地址挂在到项目的总路由下
修改项目路径django_shop目录下的urls.py, 内容如下:

from django.contrib import admin
from django.urls import path, include  # 在原有的基础上增加导入include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/shop/', include('shop.api.urls', namespace='shop')),  # 增加该行
]

7. 运行项目及调试接口

在项目路径下打开命令窗口, 运行 python3 manage.py runserver启动开发服务器
打开网页访问: http://127.0.0.1:8000/api/shop/categories/
即可看到分类列表接口(其他列表接口同理修改url即可, 如.../api/shop/projects/)
当前尚无数据(非登录状态无权限修改数据)
访问: http://127.0.0.1:8000/admin/ 使用超级管理员登录,并重新回到接口页面, 可使用POST创建新数据, 如下图:

使用Post创建新数据

创建后重新刷新页面(分类列表接口)即可看到创建的数据

分类详情接口, 访问: http://127.0.0.1:8000/api/shop/categories/1/

注意, 列表和详情统一使用复数categories, 1为该分类的id

分类详情接口操作, 其他模型列表/详情操作同理

使用Postman测试Api

  1. 使用Postman测试所有接口都需要提供Basic Auth授权, 操作方法如下
使用BasicAuth授权, 用户名和密码是超级用户的用户名和密码
  1. 使用POST新建数据(支持表单和JSON格式), 其他接口及操作方法同理
使用POST新建数据

注: 本次搭建的是通用的增删改查接口, 一般还需要根据项目实际需要进行添加和修改

下一节带着大家从Models 10分钟快速定制一套Admin后台系统

PS: 虽然标题是10分钟搭建一套Restful Api接口, 但是实际写这篇文章从下午7点下班一致在办公室写到凌晨1:20(现在), 码字不易, 欢迎多多点赞/评论和赞赏, 如有什么其他想学的教程也可留言给我

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,039评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,223评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,916评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,009评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,030评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,011评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,934评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,754评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,202评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,433评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,590评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,321评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,917评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,568评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,738评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,583评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,482评论 2 352

推荐阅读更多精彩内容