Django REST Framework 请求中的布尔/无值被设置为 False

问题描述 投票:0回答:2

我有一个名为“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

谢谢

django django-rest-framework
2个回答
2
投票

好吧,我刚刚尝试过,实际上模型默认值被忽略,即使您在序列化器中指定它也是如此。似乎当未显式发送该值时,它会被忽略。

我环顾四周,发现了一个错误报告:

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)

0
投票

如果有人仍然遇到这个问题,这里有一个更通用的解决方案(疯狂的是,这仍然是 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]
© www.soinside.com 2019 - 2024. All rights reserved.