django restful framework 序列化

案例: 一个网域domain可以绑定多台服务器主机assets, 但是一台服务器只能绑定一个网域. 数据模型之间关系适用于一对多.

一 . 数据模型: models

  1. 定义 assets 模型:apps/assets/models/asset.py

    #!/usr/bin/env python
    # -*- coding: utf-8 -*- import uuid
    from django.db import models class Asset(models.Model): id = models.UUIDField(default=uuid.uuid4, primary_key=True)
    ops_id = models.CharField(max_length=30, unique=True, null=True, blank=True, verbose_name=_('ops asset id'))
    ip = models.GenericIPAddressField(max_length=32, verbose_name=_('IP'), db_index=True)
    hostname = models.CharField(max_length=128, verbose_name=_('Hostname'))
    domain = models.ForeignKey("assets.Domain", null=True, blank=True, related_name='assets', verbose_name=_("Domain"), on_delete=models.SET_NULL) # 使用Foreignkey关联外键
    created_by = models.CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by'))
    date_created = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created'))
    comment = models.TextField(max_length=128, default='', blank=True, verbose_name=_('Comment')) def __str__(self):
    return '{0.hostname}({0.ip})'.format(self) class Meta:
    verbose_name = _("Asset")
  2. domain 模型如下:apps/assets/models/domain.py

# -*- coding: utf-8 -*-

import uuid

from django.db import models
from django.utils.translation import ugettext_lazy as _ class Domain(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
name = models.CharField(max_length=128, unique=True, verbose_name=_('Name'))
comment = models.TextField(blank=True, verbose_name=_('Comment'))
date_created = models.DateTimeField(auto_now_add=True, null=True, verbose_name=_('Date created')) class Meta:
verbose_name = _("Domain") def __str__(self):
return self.name
  1. 模型说明
  • Assets 模型中有个domain字段,使用 ForeignKey 关联 Domain模型, 并指定 related_name= assets, 表示在domain模型中,会隐藏一个

    assets字段. 在使用反向查找时(通过domain查assets)使用此字段

二. 序列化: serializers

  1. 序列化类用来对request/response参数进行校验. 这里使用 ModelSerializer

  2. 代码: apps/assets/serializers/domain.py

    # -*- coding: utf-8 -*-
    
    from rest_framework import serializers
    from ..models import Domain class DomainBindAssetSerializer(serializers.ModelSerializer): class Meta:
    model = Domain
    fields = ['id','name','assets']
    read_only_fields = ('id', 'name') def update(self, instance, validated_data):
    instance.id = validated_data.get('id',instance.id)
    instance.name = validated_data.get('name',instance.name)
    instance.save()
    instance.assets.set(validated_data.get('assets',instance.assets.all()))
    return instance
  3. 代码解析

    • fields = ['id','name','assets'] 说明此序列化检验字段
    • update 方法为了绑定 接口 更新字段, 特别注意, assets字段是隐藏字段,不能直接更新domain的assets字段, 需要使用domain.assets.set(object)
    • 最后返回domain实例

三, 视图: views

视图函数使用标准的 restful接口.

  1. 实现反向更新domain下的assets

  2. 代码: apps/assets/api/domain.py

    # ~*~ coding: utf-8 ~*~
    
    from common.permissions import IsOrgAdminOrAppUser
    from common.utils import get_logger
    from rest_framework import status
    from rest_framework.generics import RetrieveUpdateDestroyAPIView
    from rest_framework.views import Response from .. import serializers
    from ..models import Domain, Gateway class DomainWithAssetsUpdateApi(RetrieveUpdateDestroyAPIView):
    queryset = Domain.objects.all()
    serializer_class = serializers.DomainBindAssetSerializer
    permission_classes = ()
    authentication_classes = () def get_object(self, pk):
    try:
    return Domain.objects.get(id=pk)
    except Domain.DoesNotExist:
    logger.error("domain id is not existed.")
    False def get(self, request, *args, **kwargs):
    """query domain with assets"""
    data = {"msg": '', 'result': None, 'code': None}
    domain = self.get_object(kwargs.get('pk'))
    try:
    if not domain:
    raise Exception("Domain not exists! Check url!")
    serializer = serializers.DomainBindAssetSerializer(domain)
    code = status.HTTP_200_OK
    data['result'] = serializer.data
    data['code'] = code
    logger.info("Domain bind assets:{}".format(domain.assets))
    except Exception as e:
    code = status.HTTP_422_UNPROCESSABLE_ENTITY
    data['msg'] = str(e)
    data['code'] = code
    logger.error(str(e))
    finally:
    return Response(data=data, status=code) def put(self, request, *args, **kwargs):
    """bind assets to domain"""
    data = {"msg": '', 'result': None, 'code': None} domain = self.get_object(kwargs.get("pk", None))
    if not domain:
    code = status.HTTP_404_NOT_FOUND
    data['msg'] = "Domain not exists, check url!"
    data['code'] = code
    return Response(data=data, status=code) try:
    serializer = serializers.DomainBindAssetSerializer(data=request.data, instance=domain, partial=True)
    if serializer.is_valid():
    serializer.save()
    code = status.HTTP_202_ACCEPTED
    data['result'] = serializer.data
    data['code'] = code
    else:
    code = status.HTTP_422_UNPROCESSABLE_ENTITY
    data['msg'] = serializer.errors
    data['code'] = code
    except Exception as e:
    code = 500
    data['msg'] = str(e)
    data['code'] = code
    logger.error("Assets bind domain occur error:{}".format(str(e)))
    finally:
    return Response(data=data, status=code)
  3. 代码说明

    • 接口只实现: 查询(get), 更新(put)接口
    • get接口通过url解析当前查询domain.id, 使用DomainBindAssetSerializer反序列化查询的结果并返回给接口.
    • put接口相对复杂一下:
      • 首先将使用DomainBindAssetSerializer将 请求的字段request.data进行序列化, partial=True表示允许只更新要修改的字段.
      • 将解析的结果进行校验
      • 如果正常,使用save(),即调用 DomainBindAssetSerializer . update()的方法对数据进行更新

四, 路由: urls

定义访问路由

  1. 代码如下:apps/assets/urls/api_urls.py

    # coding:utf-8
    from django.urls import path
    from rest_framework_bulk.routes import BulkRouter
    from rest_framework_nested import routers from .. import api app_name = 'assets' router = BulkRouter()
    router.register(r'assets', api.AssetViewSet, 'asset')
    router.register(r'domain', api.DomainViewSet, 'domain') urlpatterns = [
    ...
    path('domain/<uuid:pk>/assets/',api.DomainWithAssetsUpdateApi.as_view(), name='domain-assets-update'),
    ...
    ] urlpatterns += router.urls + cmd_filter_router.urls

五. 测试 : test

测试使用postman

  1. get 查询接口: /api/assets/v1/domain/e5d52f79-42fc-4147-8c76-296bb7cae37b/assets/
// 返回格式如下
{
"msg": "",
"result": {
"id": "e5d52f79-42fc-4147-8c76-296bb7cae37b",
"name": "mao",
"assets": [
"323fff34-1baf-46b8-9784-cb2fc6046966",
"5c65c106-1750-47de-a2f3-031c07996eda",
"940cd754-267a-4531-88cd-e4cc248cc936"
]
},
"code": 200
}
  1. put 更新接口: /api/assets/v1/domain/e5d52f79-42fc-4147-8c76-296bb7cae37b/assets/
// request data
{
"assets": [
"323fff34-1baf-46b8-9784-cb2fc6046966",
"5c65c106-1750-47de-a2f3-031c07996eda",
]
} //response data
{
"msg": "",
"result": {
"id": "e5d52f79-42fc-4147-8c76-296bb7cae37b",
"name": "mao",
"assets": [
"323fff34-1baf-46b8-9784-cb2fc6046966",
"5c65c106-1750-47de-a2f3-031c07996eda"
]
},
"code": 202
}

django restful framework 一对多方向更新数据库的更多相关文章

  1. 3- vue django restful framework 打造生鲜超市 - model设计和资源导入

    3- vue django restful framework 打造生鲜超市 - model设计和资源导入 使用Python3.6与Django2.0.2(Django-rest-framework) ...

  2. 在django restful framework中设置django model的property

    众所周知,在django的model中,可以某些字段设置@property和setter deleter getter,这样就可以在存入数据的时候进行一些操作,具体原理请参见廖雪峰大神的博客https ...

  3. 4- vue django restful framework 打造生鲜超市 -restful api 与前端源码介绍

    4- vue django restful framework 打造生鲜超市 -restful api 与前端源码介绍 天涯明月笙 关注 2018.02.20 19:23* 字数 762 阅读 135 ...

  4. 1- vue django restful framework 打造生鲜超市

    Vue+Django REST framework实战 使用Python3.6与Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站 项目支持支 ...

  5. django restful framework教程大全

    一. 什么是RESTful REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移” REST从资源的角 ...

  6. Django restful Framework 之Requests and Response 方法

    前言: 本章主要介绍REST framework 内置的必要的功能. Request objects Response objects Status codes Wrapping API views ...

  7. 7- vue django restful framework 打造生鲜超市 -商品类别数据展示(上)

    Vue+Django REST framework实战 搭建一个前后端分离的生鲜超市网站 Django rtf 完成 商品列表页 并没有将列表页的数据json 与前端的页面展示结合起来 讲解如果将dr ...

  8. 6- vue django restful framework 打造生鲜超市 -完成商品列表页(下)

    Vue+Django REST framework实战 搭建一个前后端分离的生鲜超市网站 Django rtf 完成 商品列表页下 drf中的request和response drf对于django的 ...

  9. Django restful Framework 之序列化与反序列化

    1. 首先在已建好的工程目录下新建app命名为snippets,并将snippets app以及rest_framework app加到工程目录的 INSTALLED_APPS 中去,具体如下: IN ...

随机推荐

  1. Java 并发编程(四):如何保证对象的线程安全性

    01.前言 先让我吐一句肺腑之言吧,不说出来会憋出内伤的.<Java 并发编程实战>这本书太特么枯燥了,尽管它被奉为并发编程当中的经典之作,但我还是忍不住.因为第四章"对象的组合 ...

  2. Web for pentester_writeup之Code injection篇

    Web for pentester_writeup之Code injection篇 Code injection(代码注入) Example 1 <1> name=hacker' 添加一个 ...

  3. 暑期集训20190729 字典序(dictionary)

    [题目描述] 你需要构造一个1~n的排列,使得它满足m个条件,每个条件形如(ai,bi),表示ai必须在bi前面. 在此基础上,你需要让1尽可能靠前,然后你需要让2尽可能靠前,然后是3,4,5,…,n ...

  4. [考试反思]0908NOIP模拟测试40:颠簸

    怎么说呢?好像也没什么可说的. 把我的优缺点都表现出来了的一场考试. T3是个小的dp想出来就能打,打出来就能A.我上来过了一遍题目觉得T3最简单(然而也并不是很简单) 然后就开始打,交,其实已经A了 ...

  5. 关于Set和Map数据结构的一点学习

    关于js的Set和Map结构的学习和记录 对阮一峰老师的ES6入门和网上有关资料的的一点学习和记录 1.Set数据结构 Set构造函数的参数是一个可遍历( iterator)对象 Set中的成员值是唯 ...

  6. 跳跳棋——二分+建模LCA

    题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在a,b,c这三个位置.我们要通过最少的跳动把他们的位置移动 ...

  7. python线程threading.Timer源码解读

    threading.Timer的作用 官方给的定义是: """Call a function after a specified number of seconds: t ...

  8. springboot使用dubbo和zookeeper

    2019-11-17 yls 创建服务接口模块 接口工程只提供接口,不提供实现,在后面的提供者和消费者中使用 在使用接口的模块中只需要写具体实现类,避免了在每个模块中重复编写接口 在接口中引入依赖包 ...

  9. Netty学习篇⑤--编、解码

    前言 学习Netty也有一段时间了,Netty作为一个高性能的异步框架,很多RPC框架也运用到了Netty中的知识,在rpc框架中丰富的数据协议及编解码可以让使用者更加青睐: Netty支持丰富的编解 ...

  10. DAL

    using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Data;u ...