Usage
Viewset defined serializers
Serializer class custom configs
1 from audoma.drf import viewsets
2 from audoma.drf import mixins
3 from example_app.serializers import (
4 MyCollectSerializer,
5 MyResultSerializer
6 )
7
8 class MyViewSet(
9 mixins.ActionModelMixin,
10 mixins.ListModelMixin,
11 viewsets.GenericViewSet
12 ):
13 common_collect_serializer_class = MyCollectSerializer
14 common_result_serializer_class = MyResultSerializer
1 from rest_framework.decorators import action
2 from rest_framework.response import Response
3
4 from audoma.drf import viewsets
5 from audoma.drf import mixins
6 from example_app.serializers import (
7 MyCreateSerializer,
8 MyCustomActionSerializer
9 )
10
11 class MyViewSet(
12 mixins.ActionModelMixin,
13 mixins.CreateModelMixin,
14 viewsets.GenericViewSet
15 )::
16 create_serializer_class = MyCreateSerializer
17 custom_action_serializer_class = MyCustomActionSerializer
18
19 @action(detail=True, methods=["post"])
20 def custom_action(self, request):
21 serializer = self.get_serializer(data=request.data)
22 serializer.is_valid(raise_exception=True)
23 serializer.save()
24 return Response(serializer.instance, status_code=200)
1 from audoma.drf import viewsets
2 from audoma.drf import mixins
3 from example_app.serializers import (
4 MyCreateSerializer,
5 MyCustomActionSerializer
6 )
7
8 class MyViewSet(
9 mixins.ActionModelMixin,
10 mixins.ListModelMixin,
11 viewsets.GenericViewSet
12 ):
13 get_list_serializer_class = MyListSerializer
14 post_list_serializer_class = MyBulkCreateSerializer
1 from rest_framework.decorators import action
2 from rest_framework.response import Response
3
4 from audoma.drf import viewsets
5 from example_app.serializers import (
6 MyCreateSerializer,
7 MyCustomActionSerializer
8 )
9
10 class MyViewSet(
11 mixins.ActionModelMixin,
12 viewsets.GenericViewSet
13 ):
14 custom_action_collect_serializer = MyModelCreateSerializer
15 custom_action_result_serializer = MyModelSerializer
16
17 @action(detail=True, methods=["post"])
18 def custom_action(self, request):
19 serializer = self.get_serializer(data=request.data, serializer_type="collect")
20 serializer.is_valid(raise_exception=True)
21 serializer.save()
22 response_serializer = self.get_result_serializer(instance=serializer.instance)
23 return Response(response_serializer.data, status_code=201)
1 from rest_framework.decorators import action
2 from rest_framework.response import Response
3
4 from audoma.drf import viewsets
5 from audoma.drf import mixins
6 from example_app.serializers import (
7 MyListSerializer,
8 MySerializer,
9 MyCreateSerializer
10 )
11
12 class MyViewSet(
13 mixins.ActionModelMixin,
14 mixins.ListModelMixin,
15 viewsets.GenericViewSet
16 ):
17 get_new_action_result_serializer_class = MyListSerializer
18 post_new_action_result_serializer_class = MySerializer
19 post_new_action_collect_serializer_class = MyCreateSerializer
20
21 @action(detail=True, methods=["post", "get"])
22 def new_action(self, request, *args, **kwargs):
23 if request.method == "POST":
24 serializer = self.get_serializer(data=request.data, serializer_type="collect")
25 serializer.is_valid(raise_exception=True)
26 serializer.save()
27 instance = serializer.instance
28 else:
29 instance = self.get_object()
30 response_serializer = self.get_result_serializer(instance=instance)
31 return Response(response_serializer.data, status_code=201)
1 from rest_framework.decorators import action
2 from rest_framework.response import Response
3
4 from audoma.drf import viewsets
5 from example_app.serializers import (
6 MySerachCollectSerializer,
7 MySearchResultSerializer,
8 MyCountCreateSerializer,
9 MyCountUpdateSerializer,
10 MyCountResultSerializer,
11 MyDefaultSerializer
12 )
13 from example_app.models import (
14 MyModel,
15 CountModel
16 )
17
18
19 class MyViewSet(
20 mixins.ActionModelMixin,
21 mixins.CreateModelMixin,
22 mixins.RetrieveModelMixin,
23 mixins.DestroyModelMixin,
24 mixins.ListModelMixin,
25 viewsets.GenericViewSet,
26 ):
27
28 queryset = MyModel.objects.all()
29
30 post_search_collect_serializer_class = MySerachCollectSerializer
31 post_search_result_serializer_class = MySearchResultSerializer
32
33 post_count_collect_serializer_class = MyCountCreateSerializer
34 put_count_collect_serializer_class = MyCountUpdateSerializer
35 count_result_serializer_class = MyCountResultSerializer
36
37 serializer_class = MyDefaultSerializer
38
39 def get_object(self, pk=None):
40 return self.querset.get(pk=pk)
41
42 @action(detail=False, methods=["post"])
43 def search(self, request):
44 serializer = self.get_serializer(data=request.data, serializer_type="collect")
45 serializer.is_valid(raise_exception=True)
46 serializer.save()
47 result_serializer = self.get_result_serializer(instance=serializer.instance)
48 return Response(result_serializer.data, status=201)
49
50 @action(detail=True, methods=["post", "get", "put"])
51 def count(self, request, *args, **kwargs):
52 code = 200
53 if request.method != "GET":
54 serializer = self.get_serializer(data=request.data, serializer_type="collect")
55 serializer.is_valid(raise_exception=True)
56 serializer.save()
57 instance = serializer.instance
58 code = 201 if request.method == "POST"
59 else:
60 instance = CountModel.objects.get_count(slug=kwargs.pop("slug"))
61
62 result_serializer = self.get_result_serializer(instance=instance)
63 return Response(result_serializer.data, status=code)
...
search_collect_serializer_class = MySerachCollectSerializer
search_result_serializer_class = MySearchResultSerializer
...
...
post_count_collect_serializer_class = MyCountCreateSerializer
put_count_collect_serializer_class = MyCountUpdateSerializer
count_serializer_class = MyCountResultSerializer
...
1 from rest_framework.decorators import action
2 from rest_framework.response import Response
3
4 from audoma.drf import viewsets
5 from example_app.serializers import (
6 MySerachCollectSerializer,
7 MySearchResultSerializer,
8 MyCountCreateSerializer,
9 MyCountUpdateSerializer,
10 MyCountResultSerializer,
11 MyDefaultSerializer,
12 MyListSerializer,
13 MyCreateSerializer
14 )
15 from example_app.models import (
16 MyModel,
17 CountModel
18 )
19
20
21 class MyViewSet(
22 mixins.ActionModelMixin,
23 mixins.CreateModelMixin,
24 mixins.RetrieveModelMixin,
25 mixins.DestroyModelMixin,
26 mixins.ListModelMixin,
27 viewsets.GenericViewSet,
28 ):
29
30 queryset = MyModel.objects.all()
31
32 post_search_collect_serializer_class = MySerachCollectSerializer
33 post_search_result_serializer_class = MySearchResultSerializer
34
35 post_count_collect_serializer_class = MyCountCreateSerializer
36 put_count_collect_serializer_class = MyCountUpdateSerializer
37 count_result_serializer_class = MyCountResultSerializer
38
39 list_serializer_class = MyListSerializer
40 create_serializer_class = MyCreateSerializer
41 serializer_class = MyDefaultSerializer
42
43 def get_object(self, pk=None):
44 return self.querset.get(pk=pk)
45
46 @action(detail=False, methods=["post"])
47 def search(self, request):
48 serializer = self.get_serializer(data=request.data, serializer_type="collect")
49 serializer.is_valid(raise_exception=True)
50 serializer.save()
51 result_serializer = self.get_result_serializer(instance=serializer.instance)
52 return Response(result_serializer.data, status=201)
53
54 @action(detail=True, methods=["post", "get", "put"])
55 def count(self, request, *args, **kwargs):
56 code = 200
57 if request.method != "GET":
58 serializer = self.get_serializer(data=request.data, serializer_type="collect")
59 serializer.is_valid(raise_exception=True)
60 serializer.save()
61 instance = serializer.instance
62 code = 201 if request.method == "POST"
63 else:
64 instance = CountModel.objects.get_count(slug=kwargs.pop("slug"))
65
66 result_serializer = self.get_result_serializer(instance=instance)
67 return Response(result_serializer.data, status=code)
Serializer classes name traverse order
{htp_method}_{action_name}_{type}_serializer_class (type can be result or collect)
{action_name}_{type}_serializer_class (type can be result or collect)
{http_method}_{action_name}_serializer_class
{action_name}_serializer_class
common_{type}_serializer_class (type can be result or collect)
serializer_class
Viewset defined headers
1 ...
2 @audoma_action(
3 detail=True,
4 methods=["post"],
5 results=serializers.PerscriptionReadSerializer,
6 errors=[models.Prescription.DoesNotExist],
7 ignore_view_collectors=True,
8 )
9 def make_prescription_invalid(self, request, pk=None):
10 instance = self.get_object()
11 instance.is_valid = False
12 instance.save()
13 return instance, 200
get_{action}_{request_method}_response_headers - return headers for given action and HTTP method
get_{action}_response_headers - return headers for all of given action methods
get_{request_method}_response_headers - return headers for all HTTP request with given method
get_response_headers - return headers for all viewset actions
Permissions
By default, in the drf-spectacular viewset permissions were not documented at all. In audoma, permissions are being documented for each viewset separately.
You don’t have to define anything extra, this is being handled just out of the box. The only thing it is required is to define permissions on your viewset.
Example:
1 from rest_framework.decorators import action
2 from rest_framework.response import Response
3
4 from audoma.drf import viewsets
5 from example_app.serializers import (
6 MySerachCollectSerializer,
7 MySearchResultSerializer,
8 MyCountCreateSerializer,
9 MyCountUpdateSerializer,
10 MyCountResultSerializer,
11 MyDefaultSerializer,
12 MyListSerializer,
13 MyCreateSerializer
14 )
15 from example_app.permissions import (
16 AlternatePermission1,
17 AlternatePermission2,
18 DetailPermission,
19 ViewAndDetailPermission,
20 ViewPermission,
21 )
22 from example_app.models import (
23 MyModel,
24 CountModel
25 )
26
27
28 class MyViewSet(
29 mixins.ActionModelMixin,
30 mixins.CreateModelMixin,
31 mixins.RetrieveModelMixin,
32 mixins.DestroyModelMixin,
33 mixins.ListModelMixin,
34 viewsets.GenericViewSet,
35 ):
36 permission_classes = [
37 IsAuthenticated,
38 ViewAndDetailPermission,
39 DetailPermission,
40 ViewPermission,
41 AlternatePermission1 | AlternatePermission2,
42 ]
43
44 queryset = MyModel.objects.all()
45
46 post_search_collect_serializer_class = MySerachCollectSerializer
47 post_search_result_serializer_class = MySearchResultSerializer
48
49 post_count_collect_serializer_class = MyCountCreateSerializer
50 put_count_collect_serializer_class = MyCountUpdateSerializer
51 count_result_serializer_class = MyCountResultSerializer
52
53 list_serializer_class = MyListSerializer
54 create_serializer_class = MyCreateSerializer
55 serializer_class = MyDefaultSerializer
56
57 def get_object(self, pk=None):
58 return self.querset.get(pk=pk)
59
60 @action(detail=False, methods=["post"])
61 def search(self, request):
62 serializer = self.get_serializer(data=request.data, serializer_type="collect")
63 serializer.is_valid(raise_exception=True)
64 serializer.save()
65 result_serializer = self.get_result_serializer(instance=serializer.instance)
66 return Response(result_serializer.data, status=201)
67
68 @action(detail=True, methods=["post", "get", "put"])
69 def count(self, request, *args, **kwargs):
70 code = 200
71 if request.method != "GET":
72 serializer = self.get_serializer(data=request.data, serializer_type="collect")
73 serializer.is_valid(raise_exception=True)
74 serializer.save()
75 instance = serializer.instance
76 code = 201 if request.method == "POST"
77 else:
78 instance = CountModel.objects.get_count(slug=kwargs.pop("slug"))
79
80 result_serializer = self.get_result_serializer(instance=instance)
81 return Response(result_serializer.data, status=code)
Custom choices
1 from audoma.django.db import models
2 from audoma.choices import make_choices
3
4
5 class CarModel(models.Model):
6
7
8 CAR_BODY_TYPES = make_choices(
9 "BODY_TYPES",
10 (
11 (1, "SEDAN", "Sedan"),
12 (2, "COUPE", "Coupe"),
13 (3, "HATCHBACK", "Hatchback"),
14 (4, "PICKUP", "Pickup Truck"),
15 ),
16 )
17
18 name = models.CharField(max_length=255)
19 body_type = models.IntegerField(choices=CAR_BODY_TYPES.get_choices())
20
21 engine_size = models.FloatField()
22
23 def is_sedan(self):
24 return self.body_type is BODY_TYPE_CHOICES.SEDAN
Filters
Default Filters
1 from rest_framework.filters import SearchFilter
2 from audoma.drf import mixins
3 from audoma.drf import viewsets
4 from django_filters import rest_framework as df_filters
5
6 from example_app.models import CarModel
7 from example_app.serializers import CarModelSerializer
8
9 class CarViewSet(
10 mixins.ActionModelMixin,
11 mixins.RetrieveModelMixin,
12 mixins.ListModelMixin,
13 viewsets.GenericViewSet,
14 ):
15 queryset = CarModel.objects.all()
16 serializer_class = CarModelSerializer
17
18 filter_backends = [SearchFilter, df_filters.DjangoFilterBackend]
19
20 filterset_fields = ["body_type"]
21 search_fields = ["=manufacturer", "name"]
1 from rest_framework.filters import SearchFilter
2 from audoma.drf import mixins
3 from audoma.drf import viewsets
4 from django_filters import rest_framework as df_filters
5
6 from example_app.models import CarModel
7 from example_app.serializers import CarModelSerializer
8
9
10 class CarFilter(df_filters.FilterSet):
11 body_type = df_filters.TypedChoiceFilter(
12 Car.CAR_BODY_TYPES.get_choices(), "body_type",
13 lookup_expr="exact", field_name="body_type"
14 )
15
16 class Meta:
17 model = CarModel
18 fields = [
19 "body_type",
20 ]
21
22
23 class CarViewSet(
24 mixins.ActionModelMixin,
25 mixins.RetrieveModelMixin,
26 mixins.ListModelMixin,
27 viewsets.GenericViewSet,
28 ):
29 queryset = CarModel.objects.all()
30 serializer_class = CarModelSerializer
31
32 filter_backends = [SearchFilter, df_filters.DjangoFilterBackend]
33
34 filterset_class = CarFilter
35 search_fields = ["=manufacturer", "name"]
Validators
ExclusiveFieldsValidator
fields - list or a tuple of field names
message - string message, which will replace the default validator message
required - boolean which determines if any of the fields must be given
message_required - a message which will be displayed if one of the fields is required, and none has been passed
1 from audoma.drf import serializers
2 from audoma.drf.validators import ExclusiveFieldsValidator
3
4
5 class MutuallyExclusiveExampleSerializer(serializers.Serializer):
6 class Meta:
7 validators = [
8 ExclusiveFieldsValidator(
9 fields=[
10 "example_field",
11 "second_example_field",
12 ]
13 ),
14 ]
15
16 example_field = serializers.CharField(required=False)
17 second_example_field = serializers.CharField(required=False)
Decorators
@extend_schema_field
1 from audoma.drf.fields import FloatField
2
3 from drf_spectacular.utils import extend_schema_field
4
5 @extend_schema_field(
6 field={
7 "example": 10.00
8 }
9 )
10 class CustomExampleFloatField(FloatField):
11 pass
@audoma_action
How to use this?
1 from audoma.drf import mixins
2 from audoma.drf import viewsets
3
4 from app.serializers import (
5 CarListSerializer,
6 CarWriteSerializer,
7 CarDetailsSerializer,
8 CarCreateRateSerializer,
9 CarRateSerializer
10 )
11 from app.models import (
12 Car,
13 CarRate
14 )
15
16
17 class CarViewSet(
18 mixins.ActionModelMixin,
19 mixins.CreateModelMixin,
20 mixins.RetrieveModelMixin,
21 mixins.ListModelMixin,
22 viewsets.GenericViewSet,
23 ):
24
25 permission_classes = [
26 IsAuthenticated,
27 ViewAndDetailPermission,
28 DetailPermission,
29 ViewPermission,
30 AlternatePermission1 | AlternatePermission2,
31 ]
32
33 create_collect_serializer_class = CarWriteSerializer
34 create_result_serializer_class = CarDetailsSerializer
35 retrieve_serializer_class = CarDetailsSerializer
36 list_serializer_class = CarListSerializer
37
38 queryset = {}
39 @audoma_action(
40 detail=True,
41 methods=["get", "post"]
42 collectors=CarCreateRateSerializer,
43 results=CarRateSerializer,
44 errors=[CustomCarRateException]
45 )
46 def rate(self, request, pk=None, *args, **kwargs):
47 if request.method == "POST":
48 collect_serializer = kwargs.pop("collect_serializer")
49 instance = collect_serializer.save()
50 else:
51 instance = CarRate.objects.get_random_car_rate(car_pk=pk)
52 return instance, 200
1 from audoma.drf import mixins
2 from audoma.drf import viewsets
3 from rest_framework.exceptions import APIException
4
5 from app.serializers import (
6 CarListSerializer,
7 CarWriteSerializer,
8 CarDetailsSerializer,
9 CarCreateRateSerializer,
10 CarRateSerializer
11 )
12 from app.models import (
13 Car,
14 CarRate
15 )
16
17
18 class CustomCarRateException(APIException):
19 default_detail = "Error during retrieving car rate!"
20 status_code = 500
21
22
23 class CarViewSet(
24 mixins.ActionModelMixin,
25 mixins.CreateModelMixin,
26 mixins.RetrieveModelMixin,
27 mixins.ListModelMixin,
28 viewsets.GenericViewSet,
29 ):
30
31 permission_classes = [
32 IsAuthenticated,
33 ViewAndDetailPermission,
34 DetailPermission,
35 ViewPermission,
36 AlternatePermission1 | AlternatePermission2,
37 ]
38
39 create_collect_serializer_class = CarWriteSerializer
40 create_result_serializer_class = CarDetailsSerializer
41 retrieve_serializer_class = CarDetailsSerializer
42 list_serializer_class = CarListSerializer
43
44 queryset = {}
45
46 @audoma_action(
47 detail=True,
48 methods=["get", "post"]
49 collectors=CarCreateRateSerializer,
50 results=CarRateSerializer,
51 errors=[CustomCarRateException]
52 )
53 def rate(self, request, pk=None, *args, **kwargs):
54 if request.method == "POST":
55 collect_serializer = kwargs.pop("collect_serializer")
56 instance = collect_serializer.save()
57 else:
58 instance = CarRate.objects.get_random_car_rate(car_pk=pk)
59 if not instance:
60 raise CustomCarRateException
61 return instance, 200
1 from audoma.drf import mixins
2 from audoma.drf import viewsets
3 from rest_framework.exceptions import APIException
4
5 from app.serializers import (
6 CarListSerializer,
7 CarWriteSerializer,
8 CarDetailsSerializer,
9 CarCreateRateSerializer,
10 CarRateSerializer
11 )
12 from app.models import (
13 Car,
14 CarRate
15 )
16
17
18 class CustomCarException(APIException):
19 default_detail = "Car can't be found"
20 status_code = 500
21
22
23 class CarViewSet(
24 mixins.ActionModelMixin,
25 mixins.CreateModelMixin,
26 mixins.RetrieveModelMixin,
27 mixins.ListModelMixin,
28 viewsets.GenericViewSet,
29 ):
30
31 permission_classes = [
32 IsAuthenticated,
33 ViewAndDetailPermission,
34 DetailPermission,
35 ViewPermission,
36 AlternatePermission1 | AlternatePermission2,
37 ]
38
39 create_collect_serializer_class = CarWriteSerializer
40 create_result_serializer_class = CarDetailsSerializer
41 retrieve_serializer_class = CarDetailsSerializer
42 list_serializer_class = CarListSerializer
43
44 queryset = {}
45
46 @audoma_action(
47 detail=False,
48 methods=["get", "post"]
49 collectors=CarCreateRateSerializer,
50 results={"post":{201: CarRateSerializer}, "get":{200: CarDetailsSerializer}},
51 errors=[CustomCarException]
52 )
53 def rate(self, request, *args, **kwargs):
54 if request.method == "POST":
55 collect_serializer = kwargs.pop("collect_serializer")
56 instance = collect_serializer.save()
57 return instance. 201
58 else:
59 instance = car.objects.get(pk=pk)
60 if not instance:
61 raise CustomCarException
62 return instance, 200
1 from audoma.drf import mixins
2 from audoma.drf import viewsets
3 from rest_framework.exceptions import APIException
4
5 from app.serializers import (
6 CarListSerializer,
7 CarWriteSerializer,
8 CarDetailsSerializer,
9 CarCreateRateSerializer,
10 CarRateSerializer
11 )
12 from app.models import (
13 Car,
14 CarRate
15 )
16
17
18 class CustomCarException(APIException):
19 default_detail = "Car can't be found"
20 status_code = 500
21
22
23 class CarViewSet(
24 mixins.ActionModelMixin,
25 mixins.CreateModelMixin,
26 mixins.RetrieveModelMixin,
27 mixins.ListModelMixin,
28 viewsets.GenericViewSet,
29 ):
30
31 permission_classes = [
32 IsAuthenticated,
33 ViewAndDetailPermission,
34 DetailPermission,
35 ViewPermission,
36 AlternatePermission1 | AlternatePermission2,
37 ]
38
39 create_collect_serializer_class = CarWriteSerializer
40 create_result_serializer_class = CarDetailsSerializer
41 retrieve_serializer_class = CarDetailsSerializer
42 list_serializer_class = CarListSerializer
43
44 queryset = {}
45
46 @audoma_action(
47 detail=False,
48 methods=["get", "post"]
49 collectors=CarCreateRateSerializer,
50 results={"post":{201: CarRateSerializer}, "get":{200: CarDetailsSerializer}},
51 errors=[CustomCarException]
52 )
53 def rate(self, request, *args, **kwargs):
54 if request.method == "POST":
55 collect_serializer = kwargs.pop("collect_serializer")
56 instance = collect_serializer.save()
57 return instance. 201
58 else:
59 instance = car.objects.get(pk=pk)
60 if not instance:
61 raise CustomCarException
62 return instance, 200
63
64
65 @audoma_action(
66 detail=False,
67 methods=["get"],
68 results="Car is available"
69 )
70 def active(self, request, pk=None):
71 instance = self.get_object(pk=pk)
72 if instance.active:
73 return None, 200
74 return "Car is unavailable", 200
{
"message": "Car is available"
}
1 from audoma.drf import mixins
2 from audoma.drf import viewsets
3 from rest_framework.exceptions import APIException
4 from django.conf import settings
5
6 from app.serializers import (
7 CarListSerializer,
8 CarWriteSerializer,
9 CarDetailsSerializer,
10 CarCreateRateSerializer,
11 CarRateSerializer
12 )
13 from app.models import (
14 Car,
15 CarRate
16 )
17
18
19 class CustomCarException(APIException):
20 default_detail = "Car can't be found"
21 status_code = 500
22
23
24 class CarViewSet(
25 mixins.ActionModelMixin,
26 mixins.CreateModelMixin,
27 mixins.RetrieveModelMixin,
28 mixins.ListModelMixin,
29 viewsets.GenericViewSet,
30 ):
31
32 permission_classes = [
33 IsAuthenticated,
34 ViewAndDetailPermission,
35 DetailPermission,
36 ViewPermission,
37 AlternatePermission1 | AlternatePermission2,
38 ]
39
40 create_collect_serializer_class = CarWriteSerializer
41 create_result_serializer_class = CarDetailsSerializer
42 retrieve_serializer_class = CarDetailsSerializer
43 list_serializer_class = CarListSerializer
44
45 queryset = {}
46
47 @audoma_action(
48 detail=False,
49 methods=["get", "post"]
50 collectors=CarCreateRateSerializer,
51 results={
52 "post":{201: CarRateSerializer},
53 "get":{200: CarDetailsSerializer, 204:"Rate service currently unavailable"}
54 },
55 errors=[CustomCarException]
56 )
57 def rate(self, request, *args, **kwargs):
58 if settings.RATE_AVAILABLE:
59 return None, 204
60
61 if request.method == "POST":
62 collect_serializer = kwargs.pop("collect_serializer")
63 instance = collect_serializer.save()
64 return instance. 201
65 else:
66 instance = car.objects.get(pk=pk)
67 if not instance:
68 raise CustomCarException
69 return instance, 200
70
71
72 @audoma_action(
73 detail=False,
74 methods=["get"],
75 results="Car is available"
76 )
77 def active(self, request, pk=None):
78 instance = self.get_object(pk=pk)
79 if instance.active:
80 return None, 200
81 return "Car is unavailable", 200
Params
collectors
Serializer class which must inherit from serializers.BaseSerializer
@audoma_action( detail=False, methods=["post"], results=ExampleOneFieldSerializer, collectors=ExampleOneFieldSerializer, )A dictionary with HTTP methods as keys and serializer classes as values. This allows defining different collector for each HTTP method.
@audoma_action( detail=True, methods=["post"], collectors={"post": ExampleModelCreateSerializer}, results=ExampleModelSerializer, )
Note
Note
results
Serializer class or which must inherit from serializers.BaseSerializer or string variable In this case, the serializer class passed will be used to produce every response coming from this action.
@audoma_action( detail=True, methods=["put", "patch"], collectors=ExampleModelCreateSerializer, results=ExampleModelSerializer, )A dictionary with HTTP methods as keys and serializer classes or string variables as values. In This case, there will be a different response serializer for each HTTP method.
@audoma_action( detail=False, methods=["get", "post"], collectors={"post": MyCreateSerializer}, results={"post": MySerializer, "get": MyListSerializer} )A dictionary with HTTP methods as keys and dictionaries as values. Those dictionaries have status codes as keys and serializer classes or string variables as values.
@audoma_action( detail=False, methods=["post"], collectors={"post": MyCreateSerializer}, results={"post": {201: MySerializer, 204: MyNoContentSerializer}} )
Note
errors
NotFound
NotAuthenticated
AuthenticationFailed
ParseError
PermissionDenied
COMMON_API_ERRORS = [
myexceptions.SomeException
]
Note
ignore_view_collectors
many
run_get_object
Boolean variable which defines if get_object should be run to retrieve instance. If this has not been passed it’s being set depending on detail param for default action decorator.
Setting this to True for non detail view allows to force run get_object. This will be done in audoma_action, retrieved instance will be passed to collect_serializer
Examples
Define an example for the field
from audom.drf import serializers
class SalesContactSerializer(serializers.Serializer):
phone_number = serializers.PhoneNumberField(example="+48 123 456 789")
name = serializers.CharField(example="John", max_length=255)
Define custom fields with auto-generated examples
from rest_framework import fields
from audoma.mixins import ExampleMixin
from audoma.examples import NumericExample,
class SaleAmountField(ExampleMixin, fields.Field):
audoma_example_class = NumericExample
Define custom example classes
NumericExample
RegexExample
DateExample
TimeExample
DateTimeExample
Base64Example
RangeExample
Example
from audoma.examples import Example
class SaleExample(Example):
def generate_value(self):
return f"{self.amount} $"
Extra Fields
Money Field
from audoma.django.db import models
class SalesmanStats(models.Model):
salesman = models.ForeignKey("sale.Salesman"e, on_delete=models.CASCADE)
earned = models.MoneyField(max_digits=14, decimal_places=2, default_currency="PLN")
stats = SalesmanStats.objects.get(id=20)
# Simply pass the Money object
stats.earned = Money("99900.23", "PLN")
# You may also pass those variables to objects.create separately
sales = Salesman.objects.get(id=1)
stats = SalesmanStats.objects.create(
salesman=sales, earned_amount=120,
earned_courrency="PLN"
)
# In our case we defined the default currency, so it also may be
stats = SalesmanStats.objects.create(
salesman=sales, earned_amount=120
)
# To get the amount we type
print(stats.earned) # this will print 120
print(stats.earned.currency) # will print PLN
PhoneNumberField
from audoma.django.db import models
class SalesmanStats(models.Model):
salesman = models.ForeignKey("sale.Salesman", on_delete=models.CASCADE)
earned = models.MoneyField(max_digits=14, decimal_places=2, default_currency="PLN")
phone_number = models.PhoneNumberField(region="GB")
{
"salesman": 1,
"earned": 500,
"phone_number": "+44 20 7894 5678",
}
SerializerMethodField
class DoctorWriteSerializer(PersonBaseSerializer):
specialization = serializers.SerializerMethodField(
field=serializers.ListField(child=serializers.IntegerField()), writable=True
)
def get_specialization(self, doctor):
return doctor.specialization.values_list("id", flat=True)
class Meta:
model = api_models.Doctor
fields = ["name", "surname", "contact_data", "specialization", "salary"]
Note
It is not possible to define writable SerializerMethodField with no child field passed. Such behaviour will cause an exception.
Postgres fields
Django has defined in itself postgres specific fields. Since 0.6.0 audoma fully support those fields, it supports documentation and automatic behaviours for those fields.
To support those fields audoma uses external package: drf-extra-fields Audoma extends those package basic functionalities by adding automatic field mapping for ModelSerializer. And providing specific examples generated for each fields, which makes docs more readable.
Serializer Field links
from audoma.drf import serializers
from app.models import Car
class CarModelSerializer(serializers.ModelSerializer):
choices_options_links = {
"manufacturer": {
"viewname": "manufacturer_viewset-list",
"value_field": "id",
"display_field": "name",
}
}
manufacturer = serializers.IntegerField()
class Meta:
model = Car
fields = "__all__"
viewname - the name of a view from which variables should be retrieved
value_field - field name from which value should be retrieved
display_field - field name from which display value should be retrieved
Schema Extensions
x-choices
{
"x-choices": {
"choices": {
"value1": "displayValue1",
"value2": "displayValue2",
"value3": "displayValue3",
"value4": "displayValue4",
}
}
}
{
"x-choices": {
"operationRef": "#/paths/manufacturer_viewset~1",
"value": "$response.body#results/*/id",
"display": "$response.body#results/*/name"
}
}