Django DRF:使用序列化器从用户那里获取额外输入但不存在于模型中

Django DRF: Take extra input from user using serializer but not present in the model

我有一个 ModelSerializer class 用于用户输入和验证。我将它与 ModelViewset 一起使用,它使用序列化程序自动在数据库中创建一个新条目。现在我想做的是我想在序列化程序中有一个额外的字段,比如 roles ,这将由用户提供。它是一个用户角色数组,但该字段不存在于模型中,我想在 auth_user_groups table 中手动添加此角色条目。所以我这样写了我的序列化器,

class UserCreateSerializer(serializers.ModelSerializer):
    """
    Serializer to create new user
    """
    class Meta:
        model = User
        fields = ["name", "email", "is_active", "roles"]
        read_only_fields = ['roles']
        
    roles = serializers.MultipleChoiceField(choices=[(e.name,e.value) for e in AuthGroup])
        
    
    def validate_roles(self, value):
        
        if not value:
            raise ValidationError(detail=constants.NAMED_FIELD_REQUIRED.format(field="roles"))

我的模型是这样的,

class User(AbstractBaseUser, PermissionsMixin):
    class Meta:
        db_table = "auth_user"
        app_label = "users"

    USERNAME_FIELD = "email"

    REQUIRED_FIELDS = []

    name = models.CharField(max_length=255, null=True)

    email = models.EmailField("email address", unique=True, null=True)

    is_active = models.BooleanField(default=True)

    is_superuser = None

    is_admin = None

    is_verified = models.BooleanField(default=False)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    objects = UserManager()

    def __str__(self):
        return self.name or self.email

    def is_admin(self):
        return self.groups.filter(name=AuthGroup.ADMIN.name).exists()

这是来自用户的请求正文。

{
  "name": "test4",
  "email": "test4@example.com",
  "is_active": true,
  "roles": [
    "ADMIN", "OPERATOR"
  ]
}

所以每当我尝试调用 API,

raise TypeError("%s() got an unexpected keyword argument '%s'" % (cls.name, kwarg)) TypeError: User() got an unexpected keyword argument 'roles'

所以有人知道我该如何解决这个问题或实现我上面所说的吗?任何帮助将不胜感激...

这是因为经过验证的数据正在序列化程序的 create(...) 方法中传递给 QuerySetcreate(...) 方法。所以,你需要在创建操作之前弹出roles字段。

class UserCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ["name", "email", "is_active", "roles"]

    roles = serializers.MultipleChoiceField(
        choices=[(e.name, e.value) for e in AuthGroup],
        required=True,
        write_only=True
    )

    def validate_roles(self, value):
        # do some validations
        return value

    <b>def create(self, validated_data):
        roles = validated_data.pop("roles", None)
        return super().create(validated_data)</b>

备注

  • 您可以使用 required=True 将该字段设置为必填字段,这样您就不必为此进行任何额外的验证
  • read_only_fields 将适用于 在序列化程序中明确定义的那些字段。