django restful framework 一对多方向更新数据库

目录

  • django restful framework 序列化

    • 一 . 数据模型: models
    • 二. 序列化: serializers
    • 三, 视图: views
    • 四, 路由: urls
    • 五. 测试 : test

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
}

原文地址:https://www.cnblogs.com/failymao/p/11996910.html

时间: 2024-07-31 16:09:28

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

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

3- vue django restful framework 打造生鲜超市 - model设计和资源导入 使用Python3.6与Django2.0.2(Django-rest-framework)以及前端vue开发的前后端分离的商城网站 项目支持支付宝支付(暂不支持微信支付),支持手机短信验证码注册, 支持第三方登录.集成了sentry错误监控系统. 本小节内容: model设计与资源引入 资源初始化 数据库设计,数据表结构 新建虚拟环境 mkvirtualenv -p=D:\softEnv

Django Restful Framework【第三篇】认证、权限、限制访问频率

一.认证 认证请求头 views.py #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.permissions import

Django Restful Framework【第四篇】版本、解析器、序列化和请求数据验证

一.版本 程序也来越大时,可能通过版本不同做不同的处理 没用rest_framework之前,我们可以通过以下这样的方式去获取. class UserView(APIView): def get(self,request,*args,**kwargs): version = request.query_params.get('version') print(version) if version=='v1': #如果版本是v1 ret = { 'code':111, 'msg':'版本一的内容'

Django Restful Framework

你在浏览器中输入了一个地址的时候发生了什么事情? 1.HOST 2.DNS 3.HTTP/HTTPS协议 发送一个协议 4.进入了实现了WSGI协议的服务器(wsgiref uwsgi(C语言实现,多线程,多进程,PHP,TOMCAT)) 5.请求进入Django 6. 前后端不分离:中间件->路由分发->对应的视图函数->找到模板,渲染数据-> 返回模板的字符串 前后端分析:中间件->路由分发->返回JSON数据 Django源代码解读 graph TD A[路由匹配

Django Restful Framework【第五篇】分页、视图、路由、渲染器

一.分页 试问如果当数据量特别大的时候,你是怎么解决分页的? 方式a.记录当前访问页数的数据id 方式b.最多显示120页等 方式c.只显示上一页,下一页,不让选择页码,对页码进行加密 1.基于limit offset 做分页 from rest_framework.pagination import LimitOffsetPagination urls.py urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^app01/(?P<v

vue+django+restful framework ForYou2.0

1.技术储备 项目环境搭建 vue环境搭建 nodejs cnpm 运行vue项目: cnpm install cnpm  run dev 前后端分离的优点: pc.移动端多端适用 SPA开发模式流行 前后端职责不清 开发效率,前后端相互等待 前端一直配合后端能力有限 后端开发语言与模板高度耦合,导致开发语言依赖严重 前后端分离缺点: 前后端学习成本增加 数据依赖导致文档重要性增加 前端工作量增加 SEO的难度增加 后端开发模式迁移增加成本 Vue基本概念 前端工程化 数据双向绑定 组件化开发

利用 Django REST framework 编写 RESTful API

利用 Django REST framework 编写 RESTful API Updateat 2015/12/3: 增加 filter 最近在玩 Django,不得不说 rest_framework 真乃一大神器,可以轻易的甚至自动化的搞定很多事情,比如: 自动生成符合 RESTful 规范的 API 支持 OPTION.HEAD.POST.GET.PATCH.PUT.DELETE 根据 Content-Type 来动态的返回数据类型(如 text.json) 生成 browserable

Django REST Framework批量更新rest_framework_extensions

Django REST framework 是一套基于Django框架编写RESTful风格API的组件. 其中mixins配合viewsets能极其方便简化对数据的增删改查, 但本身并没有对数据的批量更新删除,利用rest_framework_extensions扩展包可以轻松帮我们实现这些功能. 安装使用 pip install rest_framework_extensions views.py 在视图类中继承ListUpdateModelMixin 1 from rest_framewo

django修改模型后更新数据库

当django改变模型过后,需要重新更新数据库,更新方法如下 比如app的名字是rango python manage.py makemigrations rango(创建迁移脚本)  然后运行  python manage.py migrate