項目模塊
list優化
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
datas = serializer.data
datas = get_count_by_project(datas)
return self.get_paginated_response(datas)
serializer = self.get_serializer(queryset, many=True)
datas = serializer.data
datas = get_count_by_project(datas)
return Response(datas)
這個 list
其實就是拷貝了父類中的 list
方法
使用
super().list(request, *args, **kwargs)
調用父類的 list
方法
查看返回的 Response
對象
所以優化爲:
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
response.data['results'] = get_count_by_project(response.data['results'])
return response
重寫getserializerclass
names
中的 serializer
使用 serializers.ProjectNameSerializer
爲了讓它可以直接使用 self.get_serializer
方法,重寫 get_serializer_class
源碼
def get_serializer_class(self):
"""
Return the class to use for the serializer.
Defaults to using `self.serializer_class`.
You may want to override this if you need to provide different
serializations depending on the incoming request.
(Eg. admins get full serialization, others get basic serialization)
"""
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
return self.serializer_class
重寫
def get_serializer_class(self):
if self.action == 'names':
return serializers.ProjectNameSerializer
else:
return self.serializer_class
報告模塊
序列化器
from datetime import datetime
from rest_framework import serializers
from .models import Reports
class ReportsSerializer(serializers.ModelSerializer):
"""
報告序列化器
"""
class Meta:
model = Reports
exclude = ('update_time', 'is_delete')
extra_kwargs = {
'html': {
'write_only': True
},
'create_time': {
'read_only': True
}
}
def create(self, validated_data):
report_name = validated_data['name']
validated_data['name'] = f"{report_name}_{datetime.strftime(datetime.now(), '%Y%m%d%H%M%S')}"
report = Reports.objects.create(**validated_data)
return report
從數據庫中可以看出其中 html
是一串字符串,它需要轉換成html格式纔可以正常展示,所以在接口返回的內容中不應該包含它,設置它爲只寫模式 write_only
對 create
函數進行重定義
下面是數據庫中顯示的內容
name = models.CharField('報告名稱', max_length=200, unique=True, help_text='報告名稱')
查看 models
文件可以看到 name
字段是唯一的「 unique=True
」所以我們在添加的時候需要攜帶上當前的時間信息
視圖
定義一個類 ReportsViewSet
還是繼承 ModelViewSet
其他和之前的類似
其中要注意的是一個 download
接口
import re
import os
from datetime import datetime
from django.conf import settings
from django.http import StreamingHttpResponse
from rest_framework.viewsets import ModelViewSet
from rest_framework import permissions
from rest_framework.decorators import action
from reports.utils import format_output, get_file_contents
from .models import Reports
from .serializers import ReportsSerializer
class ReportsViewSet(ModelViewSet):
"""
list:
返回測試報告(多個)列表數據
create:
創建測試報告
retrieve:
返回測試報告(單個)詳情數據
update:
更新(全)測試報告
partial_update:
更新(部分)測試報告
destroy:
刪除測試報告
"""
queryset = Reports.objects.filter(is_delete=False)
serializer_class = ReportsSerializer
permission_classes = (permissions.IsAuthenticated,)
ordering_fields = ('id', 'name')
def perform_destroy(self, instance):
instance.is_delete = True
instance.save()
def list(self, request, *args, **kwargs):
response = super().list(request, *args, **kwargs)
response.data['results'] = format_output(response.data['results'])
return response
@action(detail=True)
def download(self, request, pk=None):
instance = self.get_object()
html = instance.html
name = instance.name
mtch = re.match(r'(.*_)\d+', name)
if mtch:
mtch = mtch.group(1) + datetime.strftime(datetime.now(), '%Y%m%d%H%M%S') + '.html'
report_dir = os.path.join(settings.BASE_DIR, 'reports')
report_path = os.path.join(report_dir, mtch)
with open(report_path, 'w') as f:
f.write(html)
response = StreamingHttpResponse(get_file_contents(report_path))
response['Content-Type'] = "application/octet-stream"
response['Content-Disposition'] = "attachment; filename*=UTF-8''{}".format(name)
return response
每次下載之後我們都會在本地存放一次,然後我們需要以數據流的方式返回html報告
response = StreamingHttpResponse(get_file_contents(report_path))
def get_file_contents(filename, chunk_size=512):
with open(filename,encoding='utf8') as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
break
這裏用到了分段的方式,每512字節返回一次,直到全部返回完畢