Django DRF: Принимать дополнительный ввод от пользователя с помощью сериализатора, но не присутствующий в модели

У меня есть один ModelSerializer класс, который используется для пользовательского ввода и валидации. Я использую его с ModelViewset, который автоматически создает новую запись в базе данных с помощью сериализатора. Теперь я хочу сделать следующее: я хочу иметь дополнительное поле в сериализаторе, скажем roles, которое будет задаваться пользователем. Это массив ролей для пользователя, но это поле не присутствует в модели & я хочу вручную добавить эту запись роли в таблицу auth_user_groups. Поэтому я написал свой сериализатор следующим образом,

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() получил неожиданный аргумент ключевого слова '%s'" % (cls.name, kwarg)) TypeError: User() получил неожиданное ключевое слово аргумент 'roles'

У кого-нибудь есть идеи, как я могу решить эту проблему или достичь того, что я сказал выше? Любая помощь будет принята с благодарностью...

Это происходит потому, что проверенные данные передаются в метод create(...) из QuerySet внутри метода create(...) сериализатора. Поэтому необходимо раскрыть поле 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
    )

    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)

Примечания

  • Вы можете использовать required=True для установки поля как обязательного, чтобы не делать никаких дополнительных валидаций для него
  • .
  • read_only_fields будет работать для тех полей, которые не определены явно в сериализаторе.
Вернуться на верх