【问题标题】:How to get foreign key value using Serializer() class DRF如何使用 Serializer() 类 DRF 获取外键值
【发布时间】:2020-06-19 07:53:16
【问题描述】:

我有模型UserRole。用户模型具有来自模型Role 的外键role,如下所示。

用户模型

class User(model.Model):

    first_name = models.CharField(max_length=255, blank=False)
    role = models.ForeignKey(Role, on_delete=models.CASCADE, blank=False)

榜样

class Role(models.Model):
    
    role_name = models.CharField(max_length=255, blank=False, unique=True)

我为模型User写了一个序列化器。

class User(serializers.Serializer):

    id = serializers.IntegerField(read_only=True)
    role = serializers.IntegerField(required=True)

我正在使用APIView 来获取所有用户的列表。我希望 APIVIewget() 方法返回所有使用 role_name 的用户的返回列表,而不是像这样的 role_id -

[
    {
        "first_name":"Name",
        "role": "Admin"
    },
    {
        "first_name":"Name",
        "role": "Merchant"
    }
]

views.py

class ListUsers(APIView):

    def get(self, request, formate=None):

        admin_users = User.objects.all().values('first_name', 'role')


        return Response(admin_users)

我的ListUsers(APIView) 类返回这样的列表 -

[
    {
        "first_name":"Name",
        "role":1
    },
    {
        "first_name":"Name",
        "role":2
    }
]

我希望我的 APIView 返回用户列表,并且每个对象都应该有 role_name 而不是 role_id。我不想使用ModelSerializer。另外,我有一个APIView() 类,它为模型User 创建一个对象,它使用相同的序列化程序。我想要一个不会影响创建用户功能的解决方案。

【问题讨论】:

  • 我不确定我是否理解正确。在创建过程中会扮演什么样的角色——即当客户端发送数据时?名字还是身份证?

标签: django-rest-framework


【解决方案1】:

首先,您没有使用序列化程序。为了使用您的序列化器,您必须使用ListAPIView 而不是APIView 并将其serailizer_class 设置为您已实现的序列化器并设置其queryset 或实现其get_queryset。列表列表是由于您的代码将对象嵌套在集合中:

    return Response({admin_users})

但至于返回角色名称而不是角色 ID,请查看专门针对您的用例的 SlugRelatedField

【讨论】:

  • 它是否会影响为User 模型创建对象,因为我使用相同的序列化程序来创建和列出用户。
  • 是的。您还必须在创建用户时使用角色名称。幸运的是,您的 role_name 字段已经是唯一的,因此在创建用户时查找不会失败。
  • 因此,在创建用户时,我必须像这样发送 JSON - {"first_name":"Name", "role_name", 1} 而不是 {"first_name":"Name", "role", 1}。我说的对吗?
  • 我猜你的意思是{"first_name":"Name", "role_name", "Merchant"}。是的,如果您要将与 slug 相关的字段命名为 role_name
  • 数据库级别的数据变化不大。这里 DRF 提供了一个在 role_name 和 role_id 之间来回转换的层。
【解决方案2】:

首先,请不要使用“id”作为字段名,这样是错误的!

答案 1:简单的方法:

class ListUsers(APIView):

    def get(self, request, formate=None):
        users = Userdrf.objects.all().values('first_name', 'role__role_name')
        return Response(users)

输出

[
{'first_name': 'asd', 'role__role_name': 'admin'},
 {'first_name': 'asd', 'role__role_name': 'not_admin'}
]

答案 2:另一种方法是将序列化程序连接到视图并使用以下内容对其进行一些修改:

class User(serializers.Serializer):

    id = serializers.IntegerField(read_only=True)
    my_role = serializers.SerializerMethodField()
    class Meta:
        model = User
    fields = (
        'id',
        'my_role'
        )

def get_my_role(self, obj):
    
    return {
        'role': obj.user.role.role_name,
        }

顺便说一句-

【讨论】:

    【解决方案3】:

    使用下面的序列化程序获取您需要的输出。

    此序列化程序也可用于创建,但您必须在角色字段中发送角色名称,而不是发送角色 ID。

    您没有指定 POST 数据的结构,所以我假设它与输出相同。

    class User(serializers.Serializer):
    
        first_name = serializers.CharField(max_length=255, allow_blank=False)
        role = serializers.CharField(max_length=255, allow_blank=False)
    
        def create(self, validated_data):
            role = get_object_or_404(Role.objects.all(), role_name=validated_data['role'])
            user = User.objects.create(first_name=validated_data['first_name'], role=role)
            return user  
    
        def update(self, instance, validated_data):
            role = get_object_or_404(Role.objects.all(), role_name=validated_data['role'])
            instance.first_name = validated_data['first_name']
            instance.role = role
            instance.save()
            return instance
    
        def to_representation(self, instance):
            ret = {
                "first_name": instance.first_name,
                "role": instance.role.role_name,
            } 
            return ret       
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-09
      • 2019-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多