0

我开始了一个项目,其想法超出了我的理解范围,但是嘿……我们中的一些人以愚蠢的方式学习对吗?

目前有 2 个模型:User使用AbstractUser类的模型,然后我有一个Role模型,它提供了许多可能随时间变化的角色,所以我需要它是动态的。

这就是我的api/models.py样子:

from django.db import models
from django.contrib.auth.models import AbstractUser
from django import forms    

class Role(models.Model):
    '''
    The Role entries are managed by the system,
    automatically created via a Django data migration.
    '''
    CABLER = 1
    CLIENT = 2
    ENGINEER = 3
    PROJECTMANAGER = 4
    SALES = 5
    PARTNER = 6
    ADMIN = 6

    ROLE_CHOICES = (
        (CABLER, 'cabler'),
        (CLIENT, 'client'),
        (ENGINEER, 'engineer'),
        (PROJECTMANAGER, 'project manager'),
        (SALES, 'sales'),
        (PARTNER, 'partner'),
        (ADMIN, 'admin'),

    )

    id = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, primary_key=True)

    def __str__(self):
        return self.get_id_display()   

class User(AbstractUser):
    roles = models.ManyToManyField(Role, related_name='roles')

我遇到了几个问题,但目前当我使用邮递员或 DRF API 视图时,我无法创建有角色或没有角色的用户。

尝试角色:

Direct assignment to the forward side of a many-to-many set is prohibited. Use roles.set() instead.

尝试无角色:

{
    "roles": [
        "This list may not be empty."
    ]
}

现在,我知道我必须先创建用户然后分配角色,但是,我似乎无法通过 API 找到方法。

这是我的UserSerializer课:

class UserSerializer(serializers.ModelSerializer):
    # roles = serializers.CharField(source='get_roles_display', )
    # roles = RoleSerializer(many=True, read_only=False, )

    class Meta:
        model = User
        fields = ('url', 'username', 'password', 'email', 'roles')

        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        password = validated_data.pop('password')
        instance = User(**validated_data)
        if password is not None:
            instance.set_password(password)
            instance.save()

        return instance

我已经看到了创建form.py文件和添加保存方法的建议,但我不确定它是否适用,因为这将严格地作为我的后端的 API,并将为我的前端实现 AngularJS。

此外,每当我尝试在序列化程序下保存或更新用户时,User.roles.id都会返回一个用户没有名为角色的属性...

所以我希望有人可以提供帮助。谢谢。

4

1 回答 1

2

首先,与您的问题无关,您的角色 m2m 字段应更新为:

roles = models.ManyToManyField(Role, related_name='users')

related_name 是您如何从传递给 ManyToManyField (Role) 的模型中引用当前模型 (User)。根据我的建议,您应该写Role.objects.first().users而不是Role.objects.first().roles.

其次,如果可能的话,我建议将角色传递给创建/更新用户作为主键列表。即使这意味着创建第二个仅用于写入的序列化程序属性。例如:

class UserSerializer(serializers.ModelSerializer):
    roles = RoleSerializer(many=True, read_only=True)
    role_ids = serializers.PrimaryKeyRelatedField(
        queryset=Role.objects.all(),
        many=True, write_only=True)

    class Meta:
        model = User
        fields = ('url', 'username', 'password', 'email', 'roles', 'role_ids')
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        password = validated_data.pop('password')
        # Allow the serializer to handle the creation. Don't do it yourself.
        instance = super().create(**validated_data)
        if password is not None:
            instance.set_password(password)
            instance.save()

        return instance

当您的 API 吐出用户时,它应该如下所示:

{
    'url': '...',
    'username': '...',
    'email': '...',
    'roles': [{'id': 1, 'name': 'client'}],
}

当您发布到它时,您应该使用:

{
    'url': '...',
    'username': '...',
    'email': '...',
    'password': '...',
    'role_ids': [1, 2],
}

顺便说一句,您收到错误的原因User does not have an attribute named roles.是因为您无法传递rolesUser' 的构造函数。User.roles有实例后需要设置。你应该这样做:

user = User(**validated_data)
user.roles.set(roles) # If you need to re-write the entire list.

虽然在我的脑海中,但我不确定它是否会起作用。您可能必须事先保存它。这就是为什么我建议你super().create改用。

于 2019-01-18T20:01:52.453 回答