我有一个名为“active”的值,在 Django 模型中默认为“True”。我不想设置此值并允许通过默认操作创建它,但是,在 Django REST Framework 中的某个位置,在访问序列化器中的验证方法之前,它被设置为“False”。如何防止此操作或至少捕获它,以便我可以将不存在的“活动”值设置为“True”?
我只发布相关代码,这是一个复杂的系统,完整的代码会让人不知所措。状态列来自这个抽象类模型。正如您所看到的,只有活动列默认为 True。
class StatusModelMixin(models.Model):
active = models.BooleanField(
verbose_name=_("Active"), default=True,
help_text=_("If checked the record is active."))
soft_delete = models.BooleanField(
verbose_name=_("Hide"), default=False,
help_text=_("If checked the record is removed from all queries."))
purge = models.BooleanField(
verbose_name=_("Purge"), default=False,
help_text=_("If checked the record will be deleted."))
class Meta:
abstract = True
def save(self, *args, **kwargs):
"""
Intercept the save and update the 'purge' and 'soft_delete' objects.
This save will not be called during bulk creates and updates, so the
logic below will need to be duplicated for each object in bulk
operations.
"""
if self.purge: self.soft_delete = True
if self.soft_delete: self.active = False
super(StatusModelMixin, self).save(*args, **kwargs)
这只是受我遇到的问题影响的序列化器类之一。您可以看到我的一些测试代码没有解决问题。
class OrganizationSerializer(serializers.ModelSerializer):
user = serializers.HyperlinkedRelatedField(
view_name='user-detail', read_only=True)
uri = serializers.HyperlinkedIdentityField(
view_name='organization-detail')
#active = serializers.BooleanField(default=True, required=True)
class Meta:
model = Organization
fields = ('id', 'address_01', 'address_02', 'city', 'region',
'postal_code', 'country', 'phone', 'fax', 'active',
'soft_delete', 'purge', 'ctime', 'mtime', 'institution',
'user', 'uri')
exclude = ('purge',)
read_only_fields = ('id', 'ctime', 'mtime',)
depth = 0
#def validate(self, attrs):
# log.debug("attrs: %s", attrs)
# return attrs
谢谢
好吧,我刚刚尝试过,实际上模型默认值被忽略,即使您在序列化器中指定它也是如此。似乎当未显式发送该值时,它会被忽略。
我环顾四周,发现了一个错误报告:
https://github.com/tomchristie/django-rest-framework/issues/1101。
在这个问题得到解决之前,你可以在你的视图集中尝试这个丑陋的黑客:
def get_serializer(self, *args, **kwargs):
# data may be None
data = kwargs['data']
if data is not None:
data = data.copy() # need to make copy because of immutable QueryDict
data.setdefault('active', True)
kwargs['data'] = data
return super(OrganizationViewSet, self).get_serializer(*args, **kwargs)
如果有人仍然遇到这个问题,这里有一个更通用的解决方案(疯狂的是,这仍然是 DRF 中的一个错误)。我创建了一个基本序列化器类,如果用户没有在 PUT 请求中传递它,它会删除
BooleanField
。然后,您可以为所有序列化器继承此类,并高枕无忧。
class BooleanSafeModelSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if "request" in self.context and self.context["request"].method == "PUT" and "data" in kwargs:
fields_to_remove = []
for field_name, field_serializer in self.fields.items():
# There is a bug with DRF where if a boolean field is not sent, it will always default it to False.
# So remove the field if the serializer is a BooleanField and the key name is not sent.
if (
field_name not in kwargs["data"].keys()
and isinstance(field_serializer, serializers.BooleanField)
and not field_serializer.required
):
fields_to_remove.append(field_name)
for field_name in fields_to_remove:
del self.fields[field_name]