今天作发布单历史和服务器历史的API时,遇到的问题。即,有的字段有可能有None,比如发布单历史,在正式发布单的新建和编译时,env的字段是空的。如果一视同仁的序列化,就会报错。
一,model字段
from django.db import models
from .base_models import BaseModel
from .env_models import Env
from .release_models import Release, ReleaseStatus
from .server_models import Server
DEPLOY_CHOICES = (
('deploy', '部署'),
('rollback', '回滚'),
)
OP_CHOICES = (
('deploy', '部署'),
('maintenance', '启停维护'),
)
ACTION_CHOICES = (
('fetch', '获取软件'),
('stop', '停止'),
('stop_status', '停止状态检测'),
('deploy', '部署'),
('rollback', '回滚'),
('start', '启动'),
('start_status', '启动状态检测'),
('health_check', '服务健康检测'),
)
# 发布单历史,记录发布单的生命周期,新建,编译,流转,部署,回滚部署
class ReleaseHistory(BaseModel):
release = models.ForeignKey(Release,
related_name='ra_release_history',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name='发布单')
env = models.ForeignKey(Env,
related_name="ra_release_history",
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="环境")
deploy_status = models.ForeignKey(ReleaseStatus,
related_name='ra_release_history',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="发布单状态")
deploy_type = models.CharField(max_length=255,
choices=DEPLOY_CHOICES,
blank=True,
null=True,
verbose_name="部署类型")
log = models.TextField(verbose_name="日志内容")
class Meta:
db_table = 'ReleaseHistory'
verbose_name = 'ReleaseHistory发布单历史'
verbose_name_plural = 'ReleaseHistory发布单历史'
# 服务器变更历史,记录服务器上的部署,停止,回滚
class ServerHistory(BaseModel):
server = models.ForeignKey(Server,
related_name='ra_server_history',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name='服务器')
release = models.ForeignKey(Release,
related_name='ra_server_history',
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name='发布单')
env = models.ForeignKey(Env,
related_name="ra_server_history",
blank=True,
null=True,
on_delete=models.SET_NULL,
verbose_name="环境")
op_type = models.CharField(max_length=255,
choices=OP_CHOICES,
blank=True,
null=True,
verbose_name="操作类型")
action_type = models.CharField(max_length=255,
choices=ACTION_CHOICES,
blank=True,
null=True,
verbose_name="服务器操作类型")
log = models.TextField(verbose_name="日志内容")
class Meta:
db_table = 'ServerHistory'
verbose_name = 'ServerHistory服务器历史'
verbose_name_plural = 'ServerHistory服务器历史'
从Model定义中可以看到,env,release这些字段都有可能为None
二,过滤器
from django_filters import OrderingFilter
from django_filters.rest_framework import FilterSet
from django_filters import filters
from cmdb.models import ReleaseHistory
from cmdb.models import ServerHistory
class ReleaseHistoryFilter(FilterSet):
release = filters.CharFilter(field_name='release__name', lookup_expr='icontains',)
begin_time = filters.DateTimeFilter(field_name='create_date', lookup_expr='gte',)
end_time = filters.DateTimeFilter(field_name='create_date', lookup_expr='lte',)
sort = OrderingFilter(fields=('create_date',))
class Meta:
model = ReleaseHistory
fields = ['release', 'begin_time', 'end_time']
class ServerHistoryFilter(FilterSet):
server = filters.CharFilter(field_name='server__name', lookup_expr='icontains',)
begin_time = filters.DateTimeFilter(field_name='create_date', lookup_expr='gte',)
end_time = filters.DateTimeFilter(field_name='create_date', lookup_expr='lte',)
sort = OrderingFilter(fields=('create_date',))
class Meta:
model = ServerHistory
fields = ['server', 'begin_time', 'end_time']
- 在过滤时,发布单历史主要以发布单为过滤项,服务器历史主要以IP为过滤项。
三,序列化
from rest_framework import serializers
from cmdb.models import ReleaseHistory
from cmdb.models import ServerHistory
class ReleaseHistorySerializer(serializers.ModelSerializer):
env = serializers.CharField(source='env.name', default=None)
release = serializers.CharField(source='release.name', default=None)
create_user = serializers.CharField(source='create_user.username')
class Meta:
model = ReleaseHistory
fields = '__all__'
class ServerHistorySerializer(serializers.ModelSerializer):
server = serializers.CharField(source='server.name', default=None)
env = serializers.CharField(source='env.name', default=None)
release = serializers.CharField(source='release.name', default=None)
create_user = serializers.CharField(source='create_user.username')
class Meta:
model = ServerHistory
fields = '__all__'
- env = serializers.CharField(source='env.name', default=None)这里的default=None参数是关键,如果不带这个参数,就会出现以下的错误:
AttributeError: Got AttributeError when attempting to get a value for field
env_nameon serializer
ReleaseHistorySerializer. The serializer field might be named incorrectly and not match any attribute or key on the
ReleaseHistoryinstance. Original exception text was: 'NoneType' object has no attribute 'name'.
四,ListView
from rest_framework.generics import ListAPIView
from cmdb.models import ReleaseHistory
from cmdb.models import ServerHistory
from .filters import ReleaseHistoryFilter
from .filters import ServerHistoryFilter
from .serializers import ReleaseHistorySerializer
from .serializers import ServerHistorySerializer
from utils.ret_code import *
class ReleaseHistoryListView(ListAPIView):
queryset = ReleaseHistory.objects.all()
serializer_class = ReleaseHistorySerializer
filter_class = ReleaseHistoryFilter
def get(self, request, *args, **kwargs):
res = super().get(self, request, *args, **kwargs)
return_dict = build_ret_data(OP_SUCCESS, res.data)
return render_json(return_dict)
class ServerHistoryListView(ListAPIView):
queryset = ServerHistory.objects.all()
serializer_class = ServerHistorySerializer
filter_class = ServerHistoryFilter
def get(self, request, *args, **kwargs):
res = super().get(self, request, *args, **kwargs)
return_dict = build_ret_data(OP_SUCCESS, res.data)
return render_json(return_dict)
- 常规套路,指定查询集,序列化,过滤器就好,然后,统一自定义返回值。
五,URL路由
from django.urls import path
from . import views
app_name = "history"
urlpatterns = [
path('release/', views.ReleaseHistoryListView.as_view(), name='release'),
path('server/', views.ServerHistoryListView.as_view(), name='server'),
]
六,POSTMAN测试
2021-01-27 21_46_40-悬浮球.png
http://localhost:8000/history/release/?release=20210126194249879220CA
{
"code": 0,
"message": "操作成功",
"data": {
"count": 9,
"next": null,
"previous": null,
"results": [
{
"id": 60,
"env": null,
"release": "20210126194249879220CA",
"create_user": "admin",
"name": "9e07a326-5fcb-11eb-a19f-1cbfc0db9238",
"description": null,
"update_date": "2021-01-26T19:42:49.929118+08:00",
"create_date": "2021-01-26T19:42:49.929118+08:00",
"base_status": true,
"deploy_type": null,
"log": "Create",
"deploy_status": 22
},
{
"id": 61,
"env": null,
"release": "20210126194249879220CA",
"create_user": "admin",
"name": "b0aca356-5fcb-11eb-9fb9-1cbfc0db9238",
"description": null,
"update_date": "2021-01-26T19:43:21.205546+08:00",
"create_date": "2021-01-26T19:43:21.205546+08:00",
"base_status": true,
"deploy_type": null,
"log": "Building",
"deploy_status": 23
},
{
"id": 62,
"env": null,
"release": "20210126194249879220CA",
"create_user": "admin",
"name": "e2d8882c-5fcb-11eb-90c5-1cbfc0db9238",
"description": null,
"update_date": "2021-01-26T19:44:45.381243+08:00",
"create_date": "2021-01-26T19:44:45.381243+08:00",
"base_status": true,
"deploy_type": null,
"log": "Build",
"deploy_status": 25
},
{
"id": 63,
"env": "dev",
"release": "20210126194249879220CA",
"create_user": "admin",
"name": "ff36723b-5fcb-11eb-a874-1cbfc0db9238",
"description": null,
"update_date": "2021-01-26T19:45:32.982678+08:00",
"create_date": "2021-01-26T19:45:32.982678+08:00",
"base_status": true,
"deploy_type": null,
"log": "Ongoing",
"deploy_status": 27
},
{
"id": 64,
"env": "dev",
"release": "20210126194249879220CA",
"create_user": "admin",
"name": "121d5041-5fcc-11eb-a04a-1cbfc0db9238",
"description": null,
"update_date": "2021-01-26T19:46:04.706438+08:00",
"create_date": "2021-01-26T19:46:04.706438+08:00",
"base_status": true,
"deploy_type": "deploy",
"log": "Success",
"deploy_status": 28
},
{
"id": 65,
"env": "dev",
"release": "20210126194249879220CA",
"create_user": "admin",
"name": "93e08010-5fcc-11eb-85d2-1cbfc0db9238",
"description": null,
"update_date": "2021-01-26T19:49:42.399962+08:00",
"create_date": "2021-01-26T19:49:42.399962+08:00",
"base_status": true,
"deploy_type": null,
"log": "Ongoing",
"deploy_status": 27
},
{
"id": 66,
"env": "dev",
"release": "20210126194249879220CA",
"create_user": "admin",
"name": "a0c503fd-5fcc-11eb-b9b8-1cbfc0db9238",
"description": null,
"update_date": "2021-01-26T19:50:04.060525+08:00",
"create_date": "2021-01-26T19:50:04.060525+08:00",
"base_status": true,
"deploy_type": "rollback",
"log": "Success",
"deploy_status": 28
},
{
"id": 67,
"env": "dev",
"release": "20210126194249879220CA",
"create_user": "admin",
"name": "a2a5af61-5fce-11eb-bc32-1cbfc0db9238",
"description": null,
"update_date": "2021-01-26T20:04:26.178675+08:00",
"create_date": "2021-01-26T20:04:26.178675+08:00",
"base_status": true,
"deploy_type": null,
"log": "Ongoing",
"deploy_status": 27
},
{
"id": 68,
"env": "dev",
"release": "20210126194249879220CA",
"create_user": "admin",
"name": "b02ed13f-5fce-11eb-99cb-1cbfc0db9238",
"description": null,
"update_date": "2021-01-26T20:04:48.897537+08:00",
"create_date": "2021-01-26T20:04:48.897537+08:00",
"base_status": true,
"deploy_type": "deploy",
"log": "Success",
"deploy_status": 28
}
]
}
}
http://localhost:8000/history/server/?server=192.168.1.211
{
"code": 0,
"message": "操作成功",
"data": {
"count": 41,
"next": "http://localhost:8000/history/server/?currentPage=2&server=192.168.1.211",
"previous": null,
"results": [
{
"id": 4,
"server": "192.168.1.211",
"env": "dev",
"release": "20210124230452791843DX",
"create_user": "admin",
"name": "1f841979-5f12-11eb-8f06-1cbfc0db9238",
"description": null,
"update_date": "2021-01-25T21:35:00.794408+08:00",
"create_date": "2021-01-25T21:35:00.794408+08:00",
"base_status": true,
"op_type": "deploy",
"action_type": "fetch",
"log": "APP_NAME: go-demo prepare success."
},
{
"id": 5,
"server": "192.168.1.211",
"env": "dev",
"release": "20210124230452791843DX",
"create_user": "admin",
"name": "22470a81-5f12-11eb-a81a-1cbfc0db9238",
"description": null,
"update_date": "2021-01-25T21:35:05.419020+08:00",
"create_date": "2021-01-25T21:35:05.419020+08:00",
"base_status": true,
"op_type": "deploy",
"action_type": "stop",
"log": "18729\nAPP_NAME: go-demo is success stop."
},
{
"id": 7,
"server": "192.168.1.211",
"env": "dev",
"release": "20210124230452791843DX",
"create_user": "admin",
"name": "23499475-5f12-11eb-80ae-1cbfc0db9238",
"description": null,
"update_date": "2021-01-25T21:35:07.118277+08:00",
"create_date": "2021-01-25T21:35:07.118277+08:00",
"base_status": true,
"op_type": "deploy",
"action_type": "stop_status",
"log": "APP_NAME: go-demo is success on stop."
},
{
"id": 10,
"server": "192.168.1.211",
"env": "dev",
"release": "20210124230452791843DX",
"create_user": "admin",
"name": "243a35dc-5f12-11eb-bf37-1cbfc0db9238",
"description": null,
"update_date": "2021-01-25T21:35:08.705017+08:00",
"create_date": "2021-01-25T21:35:08.705017+08:00",
"base_status": true,
"op_type": "deploy",
"action_type": "deploy",
"log": "APP_NAME: go-demo deploy success."
},
{
"id": 12,
"server": "192.168.1.211",
"env": "dev",
"release": "20210124230452791843DX",
"create_user": "admin",
"name": "26d0b5cf-5f12-11eb-9779-1cbfc0db9238",
"description": null,
"update_date": "2021-01-25T21:35:13.038520+08:00",
"create_date": "2021-01-25T21:35:13.038520+08:00",
"base_status": true,
"op_type": "deploy",
"action_type": "start",
"log": "APP_NAME: go-demo is start success in 3 seconds. \\n"
},
{
"id": 14,
"server": "192.168.1.211",
"env": "dev",
"release": "20210124230452791843DX",
"create_user": "admin",
"name": "27bd0f32-5f12-11eb-99fe-1cbfc0db9238",
"description": null,
"update_date": "2021-01-25T21:35:14.604533+08:00",
"create_date": "2021-01-25T21:35:14.604533+08:00",
"base_status": true,
"op_type": "deploy",
"action_type": "start_status",
"log": "APP_NAME: go-demo is success on running."
},
{
"id": 16,
"server": "192.168.1.211",
"env": "dev",
"release": "20210124230452791843DX",
"create_user": "admin",
"name": "28b15c5d-5f12-11eb-ab19-1cbfc0db9238",
"description": null,
"update_date": "2021-01-25T21:35:16.216333+08:00",
"create_date": "2021-01-25T21:35:16.216333+08:00",
"base_status": true,
"op_type": "deploy",
"action_type": "health_check",
"log": "APP_NAME: go-demo is success health."
},
{
"id": 18,
"server": "192.168.1.211",
"env": "dev",
"release": "20210124230452791843DX",
"create_user": "admin",
"name": "e427c820-5f14-11eb-b529-1cbfc0db9238",
"description": null,
"update_date": "2021-01-25T21:54:49.688088+08:00",
"create_date": "2021-01-25T21:54:49.688088+08:00",
"base_status": true,
"op_type": "deploy",
"action_type": "fetch",
"log": "APP_NAME: go-demo prepare success."
},
{
"id": 20,
"server": "192.168.1.211",
"env": "dev",
"release": "20210124230452791843DX",
"create_user": "admin",
"name": "e6f84fbf-5f14-11eb-8104-1cbfc0db9238",
"description": null,
"update_date": "2021-01-25T21:54:54.412564+08:00",
"create_date": "2021-01-25T21:54:54.412564+08:00",
"base_status": true,
"op_type": "deploy",
"action_type": "stop",
"log": "21044\nAPP_NAME: go-demo is success stop."
},
{
"id": 22,
"server": "192.168.1.211",
"env": "dev",
"release": "20210124230452791843DX",
"create_user": "admin",
"name": "e7f6b410-5f14-11eb-9fa8-1cbfc0db9238",
"description": null,
"update_date": "2021-01-25T21:54:56.094383+08:00",
"create_date": "2021-01-25T21:54:56.094383+08:00",
"base_status": true,
"op_type": "deploy",
"action_type": "stop_status",
"log": "APP_NAME: go-demo is success on stop."
}
]
}
}
网友评论