django restful framework一対の多方向更新データベース
9357 ワード
目次 django restful frameworkシーケンス化 1.データモデル:models 2.シーケンス化:serializers 3、ビュー:views 4、ルーティング:urls 5.テスト:test
ケース:1つのネットワークドメインdomainは、複数のサーバホスト
assetsモデルの定義: domainモデルは、 モデル説明 Assetsモデルには を使用します.
シーケンス化クラスはrequest/responseパラメータを検証するために用いる.ここでは を用いるコード: コード解析 を示す. は、domainインスタンス を最後に返す.
ビュー関数は標準のrestfulインタフェースを使用する.逆更新domainでのassets を実現コード: コード説明 インタフェースは、クエリー(get)、更新(put)インタフェース のみを実装する. getインタフェースはurlを通じて現在のクエリーdomainを解析する.idは、 putインタフェースは比較的複雑です. は、まず、要求するフィールド 解析結果を検証する が正常である場合、save()が使用する、 .
アクセスルートの定義コードは、 です.
テストpostmanの使用 getクエリーインタフェース: put更新インタフェース:
django restful frameworkシーケンス化
ケース:1つのネットワークドメインdomainは、複数のサーバホスト
assets
をバインドすることができるが、1つのサーバは1つのネットワークドメインしかバインドできない.データモデル間の関係は一対多に適用する.一.データモデル:models
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")
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
domain
のフィールドがあり、ForeignKey
を使用してDomain
のモデルを関連付け、domainモデルではrelated_name= assets
のフィールドが非表示になることを示すassets
を指定する.逆検索を使用する場合(domainでassetsを調べる)このフィールド二.シーケンス化:serializers
ModelSerializer
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
fields = ['id','name','assets']
は、このシーケンス化検査フィールドupdate
の方法インタフェース
をバインドするため、特にassetsフィールドは非表示フィールドであり、domainのassetsフィールドを直接更新することはできず、domainを使用する必要がある.assets.set(object) 三、ビュー:views
ビュー関数は標準のrestfulインタフェースを使用する.
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)
DomainBindAssetSerializer
を用いるクエリの結果を逆シーケンス化し、インタフェースに返す.DomainBindAssetSerializer
をrequest.data
でシーケンス化し、 partial=True
は、変更するフィールドのみの更新を許可することを示す.DomainBindAssetSerializer
が呼び出される.update()
の方法でデータを更新する四、ルーティング:urls
アクセスルートの定義
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//assets/',api.DomainWithAssetsUpdateApi.as_view(), name='domain-assets-update'),
...
]
urlpatterns += router.urls + cmd_filter_router.urls
五.テスト:test
テストpostmanの使用
/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
}
/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
}