【问题标题】:DRF: nested Serializer error on create argument after ** must be a mapping, not strDRF:** 后创建参数的嵌套序列化程序错误必须是映射,而不是 str
【发布时间】:2022-02-08 03:12:23
【问题描述】:

我有一个模型,它通过外键连接学校模型和用户模型,并且在创建是否正在创建学生时,我希望将用户外键设置为实例,并且还希望由以下人员选择学校它的 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 实例

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 当我尝试 many=True 时,字段不显示,当我尝试第二个 sugg 时,它显示 django.db.models.manager.BaseManager._get_queryset_methods.&lt;locals&gt;.create_method.&lt;locals&gt;.manager_method() got multiple values for keyword argument 'user'
    • 你是他们的吗??
    • 好的,我没有注意到您的 StudentSchoolSerializer 中有“用户”。你用吗?如果没有,您可以从序列化程序中删除user = serializers.CharField()。否则,你从applied dict 中删除它
    • 我取出用户字段,Got AttributeError when attempting to get a value for field `applied` on serializer `RegisterSerializerStudent`. The serializer field might be named incorrectly and not match any attribute or key on the `User` instance. Original exception text was: 'User' object has no attribute 'applied'. 出现
    • 那是因为你的应用字段不是只写的。因此,当注册完成时,序列化程序会尝试使用 User 的相关字段填充它并将其作为响应发送。但是没有直接链接到用户表的“应用”字段。因此,如果您不打算渲染它,您可以在 StudentSchoolSerializer 中添加一个 write_only=True 选项
    猜你喜欢
    • 1970-01-01
    • 2016-10-14
    • 1970-01-01
    • 2021-01-27
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    相关资源
    最近更新 更多