I have one ModelSerializer
class which is used for user input & validation. I am using it with a ModelViewset which automatically creates a new entry in the database using the serializer. Now what I want to do is that I want to have a extra field in the serializer say roles
which will be given by the user. It is an array of roles for a user but this field is not present in the model & I want to manually add this roles entry in the auth_user_groups
table. So I wrote my serializer like this,
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"))
My model looks like this,
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()
This is the request body which is coming from user.
{
"name": "test4",
"email": "[email protected]",
"is_active": true,
"roles": [
"ADMIN", "OPERATOR"
]
}
So I get this error whenever I try to call the API,
raise TypeError("%s() got an unexpected keyword argument '%s'" % (cls.name, kwarg)) TypeError: User() got an unexpected keyword argument 'roles'
So anyone have any idea how can I solve this or achieve what I have said above? Any help would be appreciated...
CodePudding user response:
This is because the validated data is getting passed to the create(...)
method of QuerySet
inside the create(...)
method of the serializer. So, you need to pop the roles
field before the creation operation.
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
def create(self, validated_data):
roles = validated_data.pop("roles", None)
return super().create(validated_data)
Notes
- You can use
required=True
to set the field as mandatory so that you don't have to do any extra validations for that read_only_fields
will work for those fields which are not defined explicitly in the serializer.