我有一个包含可选字段的对象。我用这种方式定义了我的序列化器:
class ProductSerializer(serializers.Serializer):
code = serializers.Field(source="Code")
classification = serializers.CharField(source="Classification", required=False)
如果不存在,我thought required=False
将绕过该字段。但是,文档中提到这会影响反序列化而不是序列化。
我收到以下错误:
'Product' object has no attribute 'Classification'
当我尝试访问序列化实例的.data
时会发生这种情况。 (这是不是意味着反序列化提高了这个?)
对于没有Classification
的实例,会发生这种情况。如果我从序列化程序类中省略Classification
,它就可以正常工作。
我该如何正确地做到这一点?使用可选字段序列化对象,即。
答案 0 :(得分:22)
Django REST Framework 3.0 +
现在支持动态字段,请参阅http://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fields - 此方法定义序列化程序中的所有字段,然后允许您有选择地删除您不想要的字段。
或者你也可以为Model Serializer做这样的事情,在那里你搞乱了序列化程序init中的Meta.fields:
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('code',)
def __init__(self, *args, **kwargs):
if SHOW_CLASSIFICATION: # add logic here for optional viewing
self.Meta.fields = list(self.Meta.fields)
self.Meta.fields.append('classification')
super(ProductSerializer, self).__init__(*args, **kwargs)
如果这是“正确的方式”,你必须问问汤姆。因为它可能不符合长期计划。
Django REST框架< 3.0 强>
尝试这样的事情:
class ProductSerializer(serializers.Serializer):
...
classification = serializers.SerializerMethodField('get_classification')
def get_classification(self, obj):
return getattr(obj, 'classification', None)
多个序列化程序
另一种方法是创建具有不同字段集的多个序列化器。一个序列化程序继承自另一个,并添加其他字段。然后,您可以使用get_serializer_class
方法在视图中选择适当的序列化程序。这是一个实际示例,说明如果用户对象与请求用户相同,我使用此方法调用不同的序列化程序来显示不同的用户数据。
def get_serializer_class(self):
""" An authenticated user looking at their own user object gets more data """
if self.get_object() == self.request.user:
return SelfUserSerializer
return UserSerializer
从代表处删除字段
我在安全上下文中使用的另一种方法是删除to_representation
方法中的字段。定义类似
def remove_fields_from_representation(self, representation, remove_fields):
""" Removes fields from representation of instance. Call from
.to_representation() to apply field-level security.
* remove_fields: a list of fields to remove
"""
for remove_field in remove_fields:
try:
representation.pop(remove_field)
except KeyError:
# Ignore missing key -- a child serializer could inherit a "to_representation" method
# from its parent serializer that applies security to a field not present on
# the child serializer.
pass
然后在你的序列化程序中,调用该方法,如
def to_representation(self, instance):
""" Apply field level security by removing fields for unauthorized users"""
representation = super(ProductSerializer, self).to_representation(instance)
if not permission_granted: # REPLACE WITH PERMISSION LOGIC
remove_fields = ('classification', )
self.remove_fields_from_representation(representation, remove_fields)
return representation
这种方法简单明了,但是以序列化有时不显示的字段为代价。但那可能还可以。
答案 1 :(得分:11)
序列化程序是故意设计为使用一组固定的字段,因此您不能轻易地删除其中一个键。
如果字段不存在,您可以使用SerializerMethodField返回字段值或None
,或者根本不能使用序列化程序,只需编写一个直接返回响应的视图
可以在实例化的序列化程序上修改REST框架3.0的更新 serializer.fields
。当需要动态序列化程序类时,我可能建议使用自定义Serializer.__init__()
方法更改字段。
答案 2 :(得分:3)
下面描述的方法为我做了工作。 非常简单,容易并为我工作。
使用的DRF版本= djangorestframework(3.1.0)
class test(serializers.Serializer):
id= serializers.IntegerField()
name=serializers.CharField(required=False,default='some_default_value')
答案 3 :(得分:0)
来自"它是一个糟糕的黑客,依赖于DRF和Django的具体实现细节,但它起作用(至少目前为止)"文件,这里的方法我用来在"创建"的响应中包含一些额外的调试数据。序列化器上的方法实现:
def create(self, validated_data)
# Actual model instance creation happens here...
self.fields["debug_info"] = serializers.DictField(read_only=True)
my_model.debug_info = extra_data
return my_model
这是一种临时方法,可让我使用可浏览的API显示在创建过程中从特定远程服务接收的一些原始响应数据。在将来,我倾向于保留此功能,但将其隐藏在报告调试信息后面。在创建请求中标记,而不是默认返回较低级别的信息。
答案 4 :(得分:0)
为此,序列化程序具有partial
参数。如果初始化序列化程序,则可以传递partial=True
。如果您使用的是泛型或mixins,则可以覆盖get_serializer
函数,如下所示:
def get_serializer(self, *args, **kwargs):
kwargs['partial'] = True
return super(YOUR_CLASS, self).get_serializer(*args, **kwargs)
这就行了。
注意:这允许所有字段都是可选字段,而不仅仅是特定字段。如果您只想要细节,可以覆盖方法(即更新)并为各种字段添加存在的验证。
答案 5 :(得分:0)
DynamicSerializer (用于DRF 3),它允许动态指定在序列化程序中将使用哪些字段,哪些将被排除,以及可选地哪些是必填项!
class DynamicSerializerMixin:
"""
A Serializer that takes an additional `fields` argument that
controls which fields should be used.
"""
def __init__(self, *args, **kwargs):
# Don't pass the 'fields' arg up to the superclass
fields = kwargs.pop("fields", None)
excluded_fields = kwargs.pop("excluded_fields", None)
required_fields = kwargs.pop("required_fields", None)
# Instantiate the superclass normally
super().__init__(*args, **kwargs)
if fields is not None:
# Drop any fields that are not specified in the `fields` argument.
allowed = set(fields)
existing = set(self.fields)
for field_name in existing - allowed:
self.fields.pop(field_name)
if isinstance(fields, dict):
for field, config in fields.items():
set_attrs(self.fields[field], config)
if excluded_fields is not None:
# Drop any fields that are not specified in the `fields` argument.
for field_name in excluded_fields:
self.fields.pop(field_name)
if required_fields is not None:
for field_name in required_fields:
self.fields[field_name].required = True
class UserProfileSerializer(DynamicSerializerMixin, serializers.ModelSerializer):
class Meta:
model = User
fields = (
"id",
'first_name', 'last_name'
"email",
"is_staff",
)
class RoleInvitationSerializer(serializers.ModelSerializer):
invited_by = UserProfileSerializer(fields=['id', 'first_name', 'last_name'])
或实用api
@action(detail=True, serializer_class=YourSerialzierClass)
def teams_roles(self, request, pk=None):
user = self.get_object()
queryset = user.roles.all()
serializer = self.get_serializer(queryset, many=True, excluded_fields=['user'])
return Response(data=serializer.data)
答案 6 :(得分:0)
序列化器 Charfield
方法有一个属性 allow_blank
默认设置为 False。
将其设置为 True
将允许您在“序列化”期间将该字段标记为可选。
这是你应该写的代码
classification = serializers.CharField(source="Classification", allow_blank=True)
注意:required
属性用于反序列化。