Coverage for audoma_api/views.py: 94%

1 from datetime import (

2 date,

3 datetime,

4 time,

5 timedelta,

6)

7 from decimal import Decimal

8

9 from audoma_api.exceptions import (

10 CustomBadRequestException,

11 CustomConflictException,

12)

13 from audoma_api.models import (

14 Car,

15 ExampleFileModel,

16 ExampleModel,

17 ExamplePerson,

18 Manufacturer,

19)

20 from audoma_api.permissions import (

21 AlternatePermission1,

22 AlternatePermission2,

23 DetailPermission,

24 ViewAndDetailPermission,

25 ViewPermission,

26)

27 from audoma_api.serializers import (

28 CarModelSerializer,

29 ExampleFileModelSerializer,

30 ExampleModelCreateSerializer,

31 ExampleModelSerializer,

32 ExampleOneFieldSerializer,

33 ExamplePersonModelSerializer,

34 ExampleSerializer,

35 ManufacturerModelSerializer,

36 MutuallyExclusiveExampleSerializer,

37)

38 from django_filters import rest_framework as df_filters

39 from rest_framework.decorators import action

40 from rest_framework.exceptions import NotFound

41 from rest_framework.filters import SearchFilter

42 from rest_framework.parsers import MultiPartParser

43 from rest_framework.permissions import IsAuthenticated

44 from rest_framework.response import Response

45

46 from audoma.decorators import audoma_action

47 from audoma.drf import (

48 mixins,

49 viewsets,

50)

51 from audoma.drf.filters import DocumentedTypedChoiceFilter

52

53

54 class ExampleViewSet(

55 mixins.ActionModelMixin,

56 mixins.CreateModelMixin,

57 mixins.RetrieveModelMixin,

58 mixins.DestroyModelMixin,

59 mixins.ListModelMixin,

60 viewsets.GenericViewSet,

61):

62 permission_classes = [

63 IsAuthenticated,

64 ViewAndDetailPermission,

65 DetailPermission,

66 ViewPermission,

67 AlternatePermission1 | AlternatePermission2,

68 ]

69

70 serializer_class = ExampleSerializer

71 queryset = {}

72

73 @action(detail=True, methods=["post"])

74 def detail_action(self, request, pk=None):

75 return Response({}) # wrong

76

77 @action(detail=False, methods=["post"])

78 def non_detail_action(self, request):

79 return Response({}) # wrong

80

81

82 example_choice = DocumentedTypedChoiceFilter(

83 ExampleModel.EXAMPLE_CHOICES, "choice", lookup_expr="exact", field_name="choices"

84)

85

86

87 class ExampleChoiceFilter(df_filters.FilterSet):

88 choice = example_choice

89

90 class Meta:

91 model = ExampleModel

92 fields = [

93 "choice",

94 ]

95

96

97 class ExampleModelViewSet(

98 mixins.ActionModelMixin,

99 mixins.CreateModelMixin,

100 mixins.RetrieveModelMixin,

101 mixins.DestroyModelMixin,

102 mixins.ListModelMixin,

103 viewsets.GenericViewSet,

104):

105

106 permission_classes = [

107 IsAuthenticated,

108 ViewAndDetailPermission,

109 DetailPermission,

110 ViewPermission,

111 AlternatePermission1 | AlternatePermission2,

112 ]

113

114 filterset_class = ExampleChoiceFilter

115 serializer_class = ExampleModelSerializer

116 queryset = ExampleModel.objects.all()

117

118 @audoma_action(

119 detail=True,

120 methods=["get"],

121 results={"get": "GET method is not allowed"},

122 collectors=None,

123 )

124 def detail_action(self, request, pk=None):

125 return Response({}) # wrong

126

127 @action(detail=False, methods=["post"])

128 def non_detail_action(self, request):

129 return Response({}) # wron

130

131

132 class ExamplePersonModelViewSet(

133 mixins.ActionModelMixin,

134 mixins.CreateModelMixin,

135 mixins.RetrieveModelMixin,

136 mixins.DestroyModelMixin,

137 mixins.ListModelMixin,

138 viewsets.GenericViewSet,

139):

140 permission_classes = [

141 IsAuthenticated,

142 ViewAndDetailPermission,

143 DetailPermission,

144 ViewPermission,

145 ]

146

147 serializer_class = ExamplePersonModelSerializer

148 queryset = ExamplePerson.objects.all()

149

150 @action(detail=True, methods=["post"])

151 def detail_action(self, request, pk=None):

152 return Response({})

153

154 @action(detail=False, methods=["post"])

155 def non_detail_action(self, request):

156 return Response({})

157

158

159 class ExampleFileUploadViewSet(

160 mixins.ActionModelMixin,

161 mixins.CreateModelMixin,

162 viewsets.GenericViewSet,

163):

164 serializer_class = ExampleFileModelSerializer

165 queryset = ExampleFileModel.objects.all()

166

167 parser_classes = [MultiPartParser]

168

169

170 class ManufacturerViewSet(

171 mixins.ActionModelMixin,

172 mixins.BulkCreateModelMixin,

173 mixins.UpdateModelMixin,

174 mixins.ListModelMixin,

175 mixins.DestroyModelMixin,

176 mixins.BulkUpdateModelMixin,

177 mixins.RetrieveModelMixin,

178 viewsets.GenericViewSet,

179):

180 queryset = Manufacturer.objects.all()

181 serializer_class = ManufacturerModelSerializer

182

183

184 class CarViewSet(

185 mixins.ActionModelMixin,

186 mixins.RetrieveModelMixin,

187 mixins.ListModelMixin,

188 viewsets.GenericViewSet,

189):

190 queryset = Car.objects.none()

191 serializer_class = CarModelSerializer

192

193 filter_backends = [SearchFilter, df_filters.DjangoFilterBackend]

194

195 filterset_fields = ["engine_type"]

196 search_fields = ["=manufacturer", "name"]

197

198

199 class MutuallyExclusiveViewSet(

200 mixins.ActionModelMixin,

201 mixins.CreateModelMixin,

202 mixins.ListModelMixin,

203 viewsets.GenericViewSet,

204):

205 serializer_class = MutuallyExclusiveExampleSerializer

206

207

208 class ExampleModelPermissionLessViewSet(

209 mixins.ActionModelMixin, viewsets.GenericViewSet

210):

211 serializer_class = ExampleModelSerializer

212 queryset = ExampleModel.objects.all()

213

214 @audoma_action(

215 detail=True,

216 methods=["post"],

217 collectors={"post": ExampleModelCreateSerializer},

218 results={"post": {201: ExampleModelSerializer, 202: ExampleOneFieldSerializer}},

219 )

220 def detail_action(self, request, collect_serializer, pk=None):

221 if request.data.pop("usertype", None):

222 return collect_serializer.save(), 201

223 return {"rate": ExampleOneFieldSerializer.RATES.LIKE}, 202

224

225 @audoma_action(

226 detail=False,

227 methods=["get"],

228 results={"get": {200: "This is a test view", 404: "Not found"}},

229 )

230 def non_detail_action(self, request):

231 return None, 200

232

233 @audoma_action(

234 detail=False,

235 methods=["post"],

236 results=ExampleOneFieldSerializer,

237 collectors=ExampleOneFieldSerializer,

238 )

239 def rate_create_action(self, request, collect_serializer):

240 return collect_serializer.save(), 201

241

242 @audoma_action(detail=True, methods=["get"], results=ExampleOneFieldSerializer)

243 def specific_rate(self, request, pk=None):

244 return {"rate": ExampleOneFieldSerializer.RATES.DISLIKIE}, 200

245

246 @audoma_action(

247 detail=False,

248 methods=["get"],

249 results=ExampleOneFieldSerializer,

250 errors=[CustomBadRequestException(), CustomConflictException],

251 )

252 def properly_defined_exception_example(self, request):

253 raise CustomConflictException("Some custom message, that should be accepted")

254

255 @audoma_action(detail=False, methods=["get"])

256 def proper_usage_of_common_errors(self, request):

257 raise NotFound

258

259 @audoma_action(

260 detail=False,

261 methods=["get"],

262 results=ExampleOneFieldSerializer,

263 )

264 def improperly_defined_exception_example(self, request):

265 raise CustomBadRequestException

266

267 def get_object(self):

268 return ExampleModel(

269 char_field="TESTChar",

270 phone_number="+18888888822",

271 email="test@iteo.com",

272 url="http://localhost:8000/redoc/",

273 boolean=False,

274 nullboolean=None,

275 mac_adress="96:82:2E:6B:F5:49",

276 slug="tst",

277 uuid="14aefe15-7c96-49b6-9637-7019c58c25d2",

278 ip_address="192.168.10.1",

279 integer=16,

280 _float=12.2,

281 decimal=Decimal("13.23"),

282 datetime=datetime(2009, 11, 13, 10, 39, 35),

283 date=date(2009, 11, 13),

284 time=time(10, 39, 35),

285 duration=timedelta(days=1),

286 choices=1,

287 json="",

288 )

289

290 @audoma_action(

291 detail=True,

292 methods=["put", "patch"],

293 collectors=ExampleModelCreateSerializer,

294 results=ExampleModelSerializer,

295 )

296 def example_update_action(self, request, collect_serializer, pk=None):

297 return collect_serializer.save(), 201