我有一个序列化器:
class CompanyProfileCreateSerializer(serializers.ModelSerializer):
class Meta:
model = CompanyProfile
exclude = ["id", "company"]
class CompanyCreateSerializer(serializers.ModelSerializer):
company_profile = CompanyProfileCreateSerializer(required=True)
password = serializers.CharField(write_only=True)
class Meta:
model = Company
fields = ["id", "email", "password", "company_profile"]
extra_kwargs = {
"password": {"write_only": True, "style": {"input_type": "password"}}
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Define custom error messages for all fields dynamically
for field_name, field in self.fields.items():
field.error_messages.update({
"required": f"{field_name.replace('_', ' ').capitalize()} is required.",
"null": f"{field_name.replace('_', ' ').capitalize()} cannot be null.",
"invalid": f"Invalid value for {field_name.replace('_', ' ').capitalize()}."
})
def create(self, validated_data):
company_profile_data = validated_data.pop("company_profile")
company = Company.objects.create(**validated_data, **company_profile_data)
return company
我根据另一个问题的
this答案添加了
__init__()
方法。但我遇到了一个问题。
如果我发送以下请求:
{
"email": "[email protected]",
"password": "password123",
"company_profile": {
"name": "Company Test Register1"
}
}
我得到的回应是:
{
"field": "email",
"detail": "user with this email already exists."
}
这是正确的。该响应与 DRF 的默认错误响应不同,因为我使用的是自定义异常处理程序。
但问题是,当我将请求更改为:
{
"password": "password123",
"company_profile": {
"name": "Company Test Register1"
}
}
我仍然收到相同的错误响应。在服务器重新加载之前,错误响应是相同的。事实上,错误响应应该是:
{
"field": "email",
"detail": "Email is required"
}
但是,如果我在请求中发送正确的信息而不重新加载服务器,它将按预期创建公司。
这里还有一些代码以了解更多上下文:
查看:
@extend_schema(tags=["company"])
class CompanyView(
GenericViewSet,
CreateModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
):
"""View to create/retrieve/update a company."""
queryset = Company.objects.all()
lookup_field = "id"
parser_classes = [JSONParser, MultiPartParser, FormParser]
def get_serializer_class(self):
serializer_action_classes = {
"create": CompanyCreateSerializer,
"retrieve": CompanyRetrieveSerializer,
"update": CompanyUpdateSerializer,
"partial_update": CompanyUpdateSerializer,
}
if self.action in serializer_action_classes:
return serializer_action_classes[self.action]
else:
raise ValidationError({"detail": "Method Not Allowed."})
def get_permissions(self):
permission_action_classes = {
"create": [AllowAny()],
"retrieve": [IsAuthenticated(), IsOwner()],
"update": [IsAuthenticated(), IsOwner()],
"partial_update": [IsAuthenticated(), IsOwner()],
}
if self.action in permission_action_classes:
return permission_action_classes[self.action]
else:
return [NotAllowed()]
def get_serializer_context(self):
context = super().get_serializer_context()
if self.action in ["update", "partial_update"]:
context["instance"] = self.get_object()
return context
@extend_schema(description="Create a new company")
def create(self, request, *args, **kwargs):
return super().create(request, *args, **kwargs)
@extend_schema(description="Retrieve a single company by User ID")
def retrieve(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs)
@extend_schema(description="Update a single company by User ID")
def update(self, request, *args, **kwargs):
return super().update(request, *args, **kwargs)
@extend_schema(description="Partially Update a single company by User ID")
def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
instance = serializer.update(
instance=Company.objects.get(pk=kwargs["id"]),
validated_data=serializer.validated_data,
)
output_serializer = CompanyRetrieveSerializer(
instance, context={"request": request}
)
return Response(output_serializer.data)
自定义异常处理函数:
from rest_framework.views import exception_handler
from rest_framework.response import Response
def get_last_value(dictionary: dict, values = []) -> list[list[str]]:
"""
Get the last values from a nested dictionary.
"""
for key, item in dictionary.items():
if isinstance(item, dict):
get_last_value(item, values)
else:
values.append(item)
return values
def custom_exception_handler(exc, context):
"""
Custom exception handler.
Format of exception:
{
"field": "Field name",
"detail": "Error message"
}
"""
response = exception_handler(exc, context)
if response is not None:
if isinstance(response.data, dict):
field = next(iter(response.data))
error_message = get_last_value(response.data)[0][0]
error_response = Response({
"field": field,
"detail": error_message
}, status=response.status_code)
return error_response
else:
error_message = str(response.data)
error_response = Response({
"field": "non_field_errors",
"detail": error_message
}, status=response.status_code)
return error_response
return response
为什么会发生这种情况以及如何解决这个问题?
我找到了答案。这是因为
values
函数中的 get_last_value
参数在请求之间没有重置。
我将其更改为以下内容:
def get_last_value(dictionary: dict) -> list[dict]:
"""
Get the last values from a nested dictionary.
"""
values = []
for key, item in dictionary.items():
if isinstance(item, dict):
values.extend(get_last_value(item))
else:
values.append({key: item})
return values
现在可以了。花了太长时间才弄清楚这一点。