我正在尝试使用DRF ListSerializer创建POST端点以创建LogLevel对象的列表。
我尝试使用PrimaryKeyRelatedField序列化外键,但没有成功。
models.py
relevant fields for LogLevel model. note foreign key to node model
#associated node
node = models.ForeignKey(Node, on_delete=models.DO_NOTHING,
related_name="log_levels")
#logger name
name = models.CharField(max_length=32, choices=LOGGERS)
# Current log level
level = models.IntegerField(default=INFO,
choices=LOG_LEVELS)
# Timestamps
created_datetime = models.DateTimeField(auto_now_add=True)
updated_datetime = models.DateTimeField(auto_now=True,
blank=True, null=True)
serializers.py
class LogLevelListSerializer(serializers.ListSerializer):
def create(self, validated_data):
log_levels = [LogLevel(**item) for item in validated_data]
levels = LogLevel.objects.bulk_create(log_levels)
return levels
class LogLevelCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = LogLevel
fields = "__all__"
list_serializer_class = LogLevelListSerializer
LogLevel view
class LogLevelList(MethodSerializerMixin,
generics.ListCreateAPIView):
"""
Log Level list API Endpoint.
"""
method_serializer_classes = {
("POST",): LogLevelCreateUpdateSerializer
}
def get_queryset(self):
"""
Queryset to use for endpoint.
"""
return LogLevel.objects.all()
def get_serializer(self, *args, **kwargs):
"""
Return the serializer instance that should be used for validating and
deserializing input, and for serializing output.
"""
serializer_class = self.get_serializer_class()
kwargs['context'] = self.get_serializer_context()
# check if many is required
if "data" in kwargs:
data = kwargs["data"]
# check if many is required
if isinstance(data, list):
kwargs["many"] = True
return serializer_class(*args, **kwargs)
MethodSerializerMixin
from rest_framework import exceptions
class MethodSerializerMixin(object):
"""
Utility class to apply a different serializer class depending
on the request method.
For example:
method_serializer_classes = {
("GET", ): MyModelListViewSerializer,
("PUT", "PATCH"): MyModelCreateUpdateSerializer
}
"""
method_serializer_classes = None
def get_serializer_class(self):
assert self.method_serializer_classes is not None, (
f"Expected view {self.__class__.__name__} should contain "
f"method_serializer_classes to get right serializer class."
)
for methods, serializer_cls in self.method_serializer_classes.items():
if self.request.method in methods:
return serializer_cls
raise exceptions.MethodNotAllowed(self.request.method)
我在请求中传递了简单对象的json列表。节点是外键ID:
[{
"name": "logger1",
"level": 2,
"node": 1
},
{
"name": "logger2",
"level": 3,
"node": 1
}]
我希望对象可以创建并以成功状态显示给客户端。当前,对象已在数据库中成功创建,但是返回了500: Server Error
,这是我在Django服务器上看到的堆栈跟踪:
Internal Server Error: /api/clustering/loglevel/set/
Traceback (most recent call last):
File "/opt/cisco/env/iris/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/opt/cisco/env/iris/lib/python3.6/site-packages/django/core/handlers/base.py", line 145, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/opt/cisco/env/iris/lib/python3.6/site-packages/django/core/handlers/base.py", line 143, in _get_response
response = response.render()
File "/opt/cisco/env/iris/lib/python3.6/site-packages/django/template/response.py", line 106, in render
self.content = self.rendered_content
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/response.py", line 72, in rendered_content
ret = renderer.render(self.data, accepted_media_type, context)
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/renderers.py", line 724, in render
context = self.get_context(data, accepted_media_type, renderer_context)
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/renderers.py", line 697, in get_context
'post_form': self.get_rendered_html_form(data, view, 'POST', request),
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/renderers.py", line 520, in get_rendered_html_form
return self.render_form_for_serializer(serializer)
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/renderers.py", line 528, in render_form_for_serializer
serializer.data,
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/serializers.py", line 765, in data
ret = super(ListSerializer, self).data
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/serializers.py", line 266, in data
self._data = self.get_initial()
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/serializers.py", line 600, in get_initial
return self.to_representation(self.initial_data)
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/serializers.py", line 683, in to_representation
self.child.to_representation(item) for item in iterable
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/serializers.py", line 683, in <listcomp>
self.child.to_representation(item) for item in iterable
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/serializers.py", line 527, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/opt/cisco/env/iris/lib/python3.6/site-packages/rest_framework/relations.py", line 257, in to_representation
return value.pk
AttributeError: 'int' object has no attribute 'pk'
python==3.6
django==2.2.2
drf==3.8.2
答案 0 :(得分:0)
serializer.data
属性仅在将实例保存到序列化程序时才有效。
在保存之前调用serializer.save()
或使用serializer.validated_data
访问数据。
查看此link以获得更多信息。
答案 1 :(得分:0)
必须通过更新PrimaryKeyRelatedField类上的to_representation方法来处理此错误
class NodePrimaryKeyField(serializers.PrimaryKeyRelatedField):
"""
Custom DRF serializer field for proper handling of
Node Foreign Key by ListSerializer on validation error
"""
def to_representation(self, value):
"""
Return pk value of serialized Node object
if available else return given ID value
"""
if self.pk_field is not None:
return self.pk_field.to_representation(value.pk)
return getattr(value, 'pk', value)