add: core.utils.get_context_field is added which can be used with drf serializer contexts, documentation is added
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
from rest_framework import serializers # type: ignore
|
from rest_framework import serializers # type: ignore
|
||||||
|
|
||||||
from core.apps.companies.models import CompanyFolderModel
|
from core.apps.companies.models import CompanyFolderModel
|
||||||
|
from core.utils.misc import get_context_field
|
||||||
|
|
||||||
|
|
||||||
class BaseCompanyFolderSerializer(serializers.ModelSerializer):
|
class BaseCompanyFolderSerializer(serializers.ModelSerializer):
|
||||||
@@ -38,7 +39,7 @@ class CreateCompanyFolderSerializer(BaseCompanyFolderSerializer):
|
|||||||
class Meta(BaseCompanyFolderSerializer.Meta): ...
|
class Meta(BaseCompanyFolderSerializer.Meta): ...
|
||||||
|
|
||||||
|
|
||||||
class CreateCompanyFolderFromCompanySerializer(CreateCompanyFolderSerializer):
|
class CreateFolderForCompanySerializer(CreateCompanyFolderSerializer):
|
||||||
class Meta(CreateCompanyFolderSerializer.Meta):
|
class Meta(CreateCompanyFolderSerializer.Meta):
|
||||||
read_only_fields = (
|
read_only_fields = (
|
||||||
*CreateCompanyFolderSerializer.Meta.read_only_fields,
|
*CreateCompanyFolderSerializer.Meta.read_only_fields,
|
||||||
@@ -46,6 +47,6 @@ class CreateCompanyFolderFromCompanySerializer(CreateCompanyFolderSerializer):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create(self, validated_data: dict[str, object]) -> Meta.model:
|
def create(self, validated_data: dict[str, object]) -> Meta.model:
|
||||||
validated_data["company_id"] = self.context["company_id"]
|
context_data = get_context_field("company", self.context)
|
||||||
return super().create(validated_data) # type: ignore
|
return super().create(validated_data | context_data) # type: ignore
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ from core.apps.companies.serializers import (
|
|||||||
CreateCompanyFolderSerializer,
|
CreateCompanyFolderSerializer,
|
||||||
BaseCompanyAccountSerializer,
|
BaseCompanyAccountSerializer,
|
||||||
|
|
||||||
CreateCompanyFolderFromCompanySerializer
|
CreateFolderForCompanySerializer
|
||||||
)
|
)
|
||||||
|
|
||||||
from core.apps.contracts.serializers import (
|
from core.apps.contracts.serializers import (
|
||||||
@@ -50,6 +50,9 @@ from core.apps.contracts.models import (
|
|||||||
UserModel = get_user_model()
|
UserModel = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# View Only For Company CRUD That Belongs To Admin.
|
||||||
|
######################################################################
|
||||||
@extend_schema(tags=["Company"])
|
@extend_schema(tags=["Company"])
|
||||||
class CompanyView(BaseViewSetMixin, ModelViewSet):
|
class CompanyView(BaseViewSetMixin, ModelViewSet):
|
||||||
queryset = CompanyModel.objects.all()
|
queryset = CompanyModel.objects.all()
|
||||||
@@ -72,6 +75,9 @@ class CompanyView(BaseViewSetMixin, ModelViewSet):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# company/<uuid:pk>/contract Views
|
||||||
|
######################################################################
|
||||||
class CompanyContractViewSet(BaseViewSetMixin, GenericViewSet):
|
class CompanyContractViewSet(BaseViewSetMixin, GenericViewSet):
|
||||||
queryset = CompanyModel.objects.all()
|
queryset = CompanyModel.objects.all()
|
||||||
permission_classes = [AllowAny]
|
permission_classes = [AllowAny]
|
||||||
@@ -110,6 +116,9 @@ class CompanyContractViewSet(BaseViewSetMixin, GenericViewSet):
|
|||||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# company/<uuid:pk>/accounts Views
|
||||||
|
######################################################################
|
||||||
class CompanyAccountViewSet(BaseViewSetMixin, GenericViewSet):
|
class CompanyAccountViewSet(BaseViewSetMixin, GenericViewSet):
|
||||||
queryset = CompanyModel.objects.all()
|
queryset = CompanyModel.objects.all()
|
||||||
serializer_class = BaseCompanyAccountSerializer
|
serializer_class = BaseCompanyAccountSerializer
|
||||||
@@ -130,7 +139,6 @@ class CompanyAccountViewSet(BaseViewSetMixin, GenericViewSet):
|
|||||||
def list_account(
|
def list_account(
|
||||||
self,
|
self,
|
||||||
request: HttpRequest,
|
request: HttpRequest,
|
||||||
pk: uuid.UUID,
|
|
||||||
*args: object,
|
*args: object,
|
||||||
**kwargs: object,
|
**kwargs: object,
|
||||||
) -> Response:
|
) -> Response:
|
||||||
@@ -140,10 +148,12 @@ class CompanyAccountViewSet(BaseViewSetMixin, GenericViewSet):
|
|||||||
return Response(data=ser.data, status=status.HTTP_200_OK)
|
return Response(data=ser.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# company/<uuid:pk>/folders Views
|
||||||
|
######################################################################
|
||||||
class CompanyFolderViewSet(BaseViewSetMixin, GenericViewSet):
|
class CompanyFolderViewSet(BaseViewSetMixin, GenericViewSet):
|
||||||
queryset = CompanyModel.objects.all()
|
queryset = CompanyModel.objects.all()
|
||||||
permission_classes = [AllowAny]
|
permission_classes = [AllowAny]
|
||||||
# serializer_class = BaseCompanyFolderSerializer
|
|
||||||
|
|
||||||
action_permission_classes = {
|
action_permission_classes = {
|
||||||
"list_folder": [IsCompanyAccount],
|
"list_folder": [IsCompanyAccount],
|
||||||
@@ -151,7 +161,7 @@ class CompanyFolderViewSet(BaseViewSetMixin, GenericViewSet):
|
|||||||
}
|
}
|
||||||
action_serializer_class = { # type: ignore
|
action_serializer_class = { # type: ignore
|
||||||
"list_folder": RetrieveCompanyFolderSerializer,
|
"list_folder": RetrieveCompanyFolderSerializer,
|
||||||
"create_folder": CreateCompanyFolderFromCompanySerializer,
|
"create_folder": CreateFolderForCompanySerializer,
|
||||||
}
|
}
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
@@ -159,15 +169,12 @@ class CompanyFolderViewSet(BaseViewSetMixin, GenericViewSet):
|
|||||||
description="List Company Folders"
|
description="List Company Folders"
|
||||||
)
|
)
|
||||||
@action(methods=["GET"], detail=True, url_path="folders")
|
@action(methods=["GET"], detail=True, url_path="folders")
|
||||||
def list_folder(
|
def list_folder(self, *args: object, **kwargs: object) -> Response:
|
||||||
self,
|
|
||||||
request: HttpRequest,
|
|
||||||
*args: object,
|
|
||||||
**kwargs: object,
|
|
||||||
) -> Response:
|
|
||||||
company = self.get_object()
|
company = self.get_object()
|
||||||
folders = CompanyFolderModel.objects.filter(company=company)
|
folders = CompanyFolderModel.objects.filter(company=company)
|
||||||
ser = self.get_serializer(instance=folders, many=True, context={"company_id": company.pk}) # type: ignore
|
ser = self.get_serializer(
|
||||||
|
instance=folders, many=True, context={"company_id": company.pk}
|
||||||
|
) # type: ignore
|
||||||
return Response(data=ser.data, status=status.HTTP_200_OK)
|
return Response(data=ser.data, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
@@ -175,15 +182,9 @@ class CompanyFolderViewSet(BaseViewSetMixin, GenericViewSet):
|
|||||||
description="Create Folder for company",
|
description="Create Folder for company",
|
||||||
)
|
)
|
||||||
@action(url_path="folders", detail=True, methods=["POST"])
|
@action(url_path="folders", detail=True, methods=["POST"])
|
||||||
def create_folder(
|
def create_folder(self, request: HttpRequest, *args: object, **kwargs: object) -> Response:
|
||||||
self,
|
|
||||||
request: HttpRequest,
|
|
||||||
pk: uuid.UUID,
|
|
||||||
*args: object,
|
|
||||||
**kwargs: object,
|
|
||||||
) -> Response:
|
|
||||||
company = self.get_object()
|
company = self.get_object()
|
||||||
data = request.data.copy() | dict(company=company.id) # type: ignore
|
data = request.data.copy() | dict(company=company.id) # type: ignore
|
||||||
ser = CreateCompanyFolderSerializer(data=data) # type: ignore
|
ser = self.get_serializer(data=data) # type: ignore
|
||||||
ser.is_valid(raise_exception=True)
|
ser.is_valid(raise_exception=True)
|
||||||
return Response(data=ser.data, status=status.HTTP_201_CREATED)
|
return Response(data=ser.data, status=status.HTTP_201_CREATED)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from rest_framework.generics import get_object_or_404 # type: ignore
|
|||||||
|
|
||||||
from core.apps.contracts.models import (
|
from core.apps.contracts.models import (
|
||||||
ContractOwnerModel,
|
ContractOwnerModel,
|
||||||
ContractAttachedFileModel
|
ContractAttachedFileModel,
|
||||||
)
|
)
|
||||||
from core.apps.contracts.serializers import (
|
from core.apps.contracts.serializers import (
|
||||||
CreateContractOwnerSerializer,
|
CreateContractOwnerSerializer,
|
||||||
|
|||||||
65
core/utils/misc.py
Normal file
65
core/utils/misc.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
from rest_framework.exceptions import ValidationError # type: ignore # noqa
|
||||||
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
|
||||||
|
def get_context_field(field_name: str, data: dict[str, object]) -> dict[str, object]:
|
||||||
|
"""
|
||||||
|
Extracts a specified field or its ID variant from a DRF context-like data dictionary.
|
||||||
|
|
||||||
|
This utility function is intended to simplify extraction of contextual values (typically
|
||||||
|
passed through DRF serializer `context`) and enforce that at least one of the required
|
||||||
|
keys is present:
|
||||||
|
- `<field_name>`
|
||||||
|
- `<field_name>_id`
|
||||||
|
|
||||||
|
The function returns a dictionary containing whichever key is found. If neither key is
|
||||||
|
present in the given data, a `ValidationError` is raised with an informative message.
|
||||||
|
|
||||||
|
This is especially useful in DRF serializers or views where context-dependent values
|
||||||
|
are passed and must be validated before use.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
----------
|
||||||
|
field_name : str
|
||||||
|
The base name of the expected field (e.g., "user", "contract", etc.).
|
||||||
|
data : dict[str, object]
|
||||||
|
A dictionary representing the context or other data source to extract from.
|
||||||
|
Typically, this would be `self.context` from a DRF serializer.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
-------
|
||||||
|
dict[str, object]
|
||||||
|
A dictionary containing one of the following key-value pairs:
|
||||||
|
{field_name: data[field_name]}
|
||||||
|
or
|
||||||
|
{field_name + "_id": data[field_name + "_id"]}
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
------
|
||||||
|
rest_framework.exceptions.ValidationError
|
||||||
|
If neither `{field_name}` nor `{field_name}_id` is found in the provided data.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
-------
|
||||||
|
>>> get_context_field("user", {"user": user_instance})
|
||||||
|
{'user': <User object>}
|
||||||
|
|
||||||
|
>>> get_context_field("organization", {"organization_id": 42})
|
||||||
|
{'organization_id': 42}
|
||||||
|
|
||||||
|
>>> get_context_field("group", {})
|
||||||
|
ValidationError: Missing required context key: either 'group' or 'group_id'
|
||||||
|
"""
|
||||||
|
|
||||||
|
if field_name in data:
|
||||||
|
return {field_name: data[field_name]}
|
||||||
|
|
||||||
|
field_id = f"{field_name}_id"
|
||||||
|
if field_id in data:
|
||||||
|
return {field_id: data[field_id]}
|
||||||
|
|
||||||
|
raise ValidationError(
|
||||||
|
_(
|
||||||
|
"Missing required context key: either '{field_name}' or '{field_id}'"
|
||||||
|
).format(field_name=field_name, field_id=field_id)
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user