測試開發進階(三十六)

項目模塊

list優化

  1. def list(self, request, *args, **kwargs):

  2. queryset = self.filter_queryset(self.get_queryset())

  3. page = self.paginate_queryset(queryset)

  4. if page is not None:

  5. serializer = self.get_serializer(page, many=True)

  6. datas = serializer.data

  7. datas = get_count_by_project(datas)

  8. return self.get_paginated_response(datas)

  9. serializer = self.get_serializer(queryset, many=True)

  10. datas = serializer.data

  11. datas = get_count_by_project(datas)

  12. return Response(datas)

這個 list其實就是拷貝了父類中的 list方法

使用

  1. super().list(request, *args, **kwargs)

調用父類的 list方法

查看返回的 Response對象

所以優化爲:

  1. def list(self, request, *args, **kwargs):

  2. response = super().list(request, *args, **kwargs)

  3. response.data['results'] = get_count_by_project(response.data['results'])

  4. return response

重寫getserializerclass

names中的 serializer使用 serializers.ProjectNameSerializer

爲了讓它可以直接使用 self.get_serializer方法,重寫 get_serializer_class

源碼

  1. def get_serializer_class(self):

  2. """

  3. Return the class to use for the serializer.

  4. Defaults to using `self.serializer_class`.

  5. You may want to override this if you need to provide different

  6. serializations depending on the incoming request.

  7. (Eg. admins get full serialization, others get basic serialization)

  8. """

  9. assert self.serializer_class is not None, (

  10. "'%s' should either include a `serializer_class` attribute, "

  11. "or override the `get_serializer_class()` method."

  12. % self.__class__.__name__

  13. )

  14. return self.serializer_class

重寫

  1. def get_serializer_class(self):

  2. if self.action == 'names':

  3. return serializers.ProjectNameSerializer

  4. else:

  5. return self.serializer_class

報告模塊

序列化器

  1. from datetime import datetime

  2. from rest_framework import serializers

  3. from .models import Reports

  4. class ReportsSerializer(serializers.ModelSerializer):

  5. """

  6. 報告序列化器

  7. """

  8. class Meta:

  9. model = Reports

  10. exclude = ('update_time', 'is_delete')

  11. extra_kwargs = {

  12. 'html': {

  13. 'write_only': True

  14. },

  15. 'create_time': {

  16. 'read_only': True

  17. }

  18. }

  19. def create(self, validated_data):

  20. report_name = validated_data['name']

  21. validated_data['name'] = f"{report_name}_{datetime.strftime(datetime.now(), '%Y%m%d%H%M%S')}"

  22. report = Reports.objects.create(**validated_data)

  23. return report

從數據庫中可以看出其中 html是一串字符串,它需要轉換成html格式纔可以正常展示,所以在接口返回的內容中不應該包含它,設置它爲只寫模式 write_only

create函數進行重定義

下面是數據庫中顯示的內容

  1. name = models.CharField('報告名稱', max_length=200, unique=True, help_text='報告名稱')

查看 models文件可以看到 name字段是唯一的「 unique=True」所以我們在添加的時候需要攜帶上當前的時間信息

視圖

定義一個類 ReportsViewSet還是繼承 ModelViewSet

其他和之前的類似

其中要注意的是一個 download接口

  1. import re

  2. import os

  3. from datetime import datetime

  4. from django.conf import settings

  5. from django.http import StreamingHttpResponse

  6. from rest_framework.viewsets import ModelViewSet

  7. from rest_framework import permissions

  8. from rest_framework.decorators import action

  9. from reports.utils import format_output, get_file_contents

  10. from .models import Reports

  11. from .serializers import ReportsSerializer

  12. class ReportsViewSet(ModelViewSet):

  13. """

  14. list:

  15. 返回測試報告(多個)列表數據

  16. create:

  17. 創建測試報告

  18. retrieve:

  19. 返回測試報告(單個)詳情數據

  20. update:

  21. 更新(全)測試報告

  22. partial_update:

  23. 更新(部分)測試報告

  24. destroy:

  25. 刪除測試報告

  26. """

  27. queryset = Reports.objects.filter(is_delete=False)

  28. serializer_class = ReportsSerializer

  29. permission_classes = (permissions.IsAuthenticated,)

  30. ordering_fields = ('id', 'name')

  31. def perform_destroy(self, instance):

  32. instance.is_delete = True

  33. instance.save()

  34. def list(self, request, *args, **kwargs):

  35. response = super().list(request, *args, **kwargs)

  36. response.data['results'] = format_output(response.data['results'])

  37. return response

  38. @action(detail=True)

  39. def download(self, request, pk=None):

  40. instance = self.get_object()

  41. html = instance.html

  42. name = instance.name

  43. mtch = re.match(r'(.*_)\d+', name)

  44. if mtch:

  45. mtch = mtch.group(1) + datetime.strftime(datetime.now(), '%Y%m%d%H%M%S') + '.html'

  46. report_dir = os.path.join(settings.BASE_DIR, 'reports')

  47. report_path = os.path.join(report_dir, mtch)

  48. with open(report_path, 'w') as f:

  49. f.write(html)

  50. response = StreamingHttpResponse(get_file_contents(report_path))

  51. response['Content-Type'] = "application/octet-stream"

  52. response['Content-Disposition'] = "attachment; filename*=UTF-8''{}".format(name)

  53. return response

每次下載之後我們都會在本地存放一次,然後我們需要以數據流的方式返回html報告

  1. response = StreamingHttpResponse(get_file_contents(report_path))

  1. def get_file_contents(filename, chunk_size=512):

  2. with open(filename,encoding='utf8') as f:

  3. while True:

  4. c = f.read(chunk_size)

  5. if c:

  6. yield c

  7. else:

  8. break

這裏用到了分段的方式,每512字節返回一次,直到全部返回完畢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章