DRF:在 ** 之后创建参数时嵌套序列化程序错误必须是映射,而不是 str

DRF: nested Serializer error on create argument after ** must be a mapping, not str

我有一个通过外键连接学校模型和用户模型的模型,如果正在创建学生,我希望将用户外键设置为实例,并将学校设置为由它的 id 选择但是我无法解决这个错误

TypeError at /api/users/student_register/
django.db.models.manager.BaseManager._get_queryset_methods.<locals>.create_method.<locals>.manager_method() argument after ** must be a mapping, not str

class User(AbstractBaseUser, PermissionsMixin):
     ....
    email = models.EmailField(
    is_superuser = models.BooleanField(default=False)
    last_login = models.DateTimeField(
        _("last login"), auto_now=True, auto_now_add=False)


class School(models.Model):

    PROVINCE = (
        ...
    )

    SCHOOLTYPE = (
       ....
    )
    name = models.CharField(_("Name"), max_length=150, blank=False, null=True)
    abbr = models.CharField(
        _("Abbrivation"), max_length=10, blank=False, null=True)
    zone = models.CharField(
        _("Zone"), max_length=50, choices=PROVINCE)
    Schooltype = models.CharField(
        _("School type"), max_length=50, choices=SCHOOLTYPE)
    schoolemail = models.EmailField(
        _("School email"), max_length=254, blank=False, null=True) editable=False)

    def __str__(self):
        return self.name

这个应用模型将用户模型和学生模型连接在一起,这也是我通过嵌套序列化程序创建用户的模型

class Applied(models.Model):
    class TYPES(models.TextChoices):
        STUDENT = "STUDENT", "Student"
        WORKER = "WORKER", "Worker"
    type = models.CharField(_("type"), choices=TYPES.choices,
                            max_length=150, blank=False, null=True)
    user = models.ForeignKey(User, verbose_name=_(
        "useris"), related_name='useris', on_delete=models.PROTECT, blank=True, null=True)
    school = models.ForeignKey(School, verbose_name=_(
        'school'), related_name="applied", on_delete=models.CASCADE, blank=True, null=True)

serializers.py

class StudentSchoolSerializer(serializers.ModelSerializer):
    user = serializers.CharField()
    school = serializers.CharField()
    type = serializers.HiddenField(
        default=Applied.TYPES.STUDENT
    )

    class Meta:
        model = Applied
        fields = ['school', 'type', 'user']


# register a student
class RegisterSerializerStudent(serializers.ModelSerializer):
    applied = StudentSchoolSerializer(required=True)
    password = serializers.CharField(
        write_only=True, required=True, validators=[validate_password])
    firstname = serializers.CharField(required=True)
    middlename = serializers.CharField(required=True)
    lastname = serializers.CharField(required=True)

    class Meta:
        model = User
        fields = ('firstname', 'middlename', 'sex', 'grade', 'image', 'room', 'type', 'lastname', 'age', 'password',
                    'phone', 'applied')
        extra_kwargs = {'password': {'write_only': True},
                        'firstname': {'required': True},
                        'middelname': {'required': True},
                        'lastname': {'required': True},
                        'age': {'min_value': 1, 'max_value': 100}
                        }

    def create(self, validated_data):
        def create_new_id_number():
            S = 10
            not_unique = True
            while not_unique:
                unique_id = ''.join(random.choices(
                    string.ascii_uppercase + string.digits, k=S))
                if not User.objects.filter(student_id=unique_id):
                    not_unique = False
                return unique_id
        applied = validated_data.pop('applied')
        user = User.objects.create(
            student_id=create_new_id_number(),
            firstname=validated_data['firstname'],
            middlename=validated_data['middlename'],
            lastname=validated_data['lastname'],
            age=validated_data['age'],
            phone=validated_data['phone'],
            image=validated_data['image'],
            room=validated_data['room'],
            sex=validated_data['sex'],
            is_active='True',
            type=User.TYPES.STUDENT,
        )
        user.set_password(validated_data['password'])
        user.save()
        for applies in applied:
            Applied.objects.create(**applies, user=user)
        return user

create 方法抛出错误,创建一个 User 实例而不是 Applied 实例

applied = validated_data.pop('applied') 在您的序列化程序中包含“applied”的值。您没有使用 many=true 选项调用 StudentSchoolSerializer。所以当你这样做时

for applies in applied:
    Applied.objects.create(**applies, user=user)

applies 实际上是一个 str,而不是一个 dict。所以你不能使用 **.

如果只发送一个“applied”,可以直接保存 Applied.objects.create(**applied, user=user)