【问题标题】:Best method to create an object with many to many field using Django RF API使用 Django RF API 创建具有多对多字段的对象的最佳方法
【发布时间】:2019-06-13 01:21:54
【问题描述】:

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

目前有 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 下保存或更新用户时,都会返回一个用户没有名为角色的属性...

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

【问题讨论】:

    标签: django django-models django-rest-framework django-rest-viewsets


    【解决方案1】:

    首先,与您的问题无关,您的角色 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. 的原因是您无法将roles 传递给User 的构造函数。 User.roles 需要在您拥有实例后设置。你应该这样做:

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

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

    【讨论】:

    • 如何使用 Angular 和 FormData 进行 POST 调用?
    猜你喜欢
    • 2011-10-23
    • 1970-01-01
    • 2018-08-09
    • 2013-06-04
    • 2021-05-01
    • 2020-05-28
    • 2021-03-01
    • 1970-01-01
    • 2018-12-19
    相关资源
    最近更新 更多