DRF 获取 OneToOne 模型的所有字段

问题描述 投票:0回答:3

我对 DRF 还比较陌生,目前遇到了一个问题。经过多次尝试,我尝试环顾四周,但找不到我想要的东西。如果这个问题已经得到解答,请引导我回到原来的问题。预先感谢您的帮助!

问题: 我有一个与用户模型具有一对一关系的配置文件模型。当我创建新的用户对象时,配置文件对象会按预期自动创建。我想创建一个 API,这样当我像

api/profile/
那样执行它时,除了返回配置文件模型字段之外,它还应该返回用户模型中的所有字段,即
first_name
last_name
username
email 
等等...

class Profile(models.Model):
    rater = models.OneToOneField(User, on_delete=models.CASCADE, related_name='approval')
    certified = models.ManyToManyField(Protocol, blank=True, default=None, related_name='trained')
    is_approved = models.BooleanField(default=False)

我的ProfileSerializer如下:

class ProfileSerializer(serializers.ModelSerializer):
    approval = UserSerializer(read_only=True)

    class Meta:
        model = Profile
        fields = '__all__'

当我运行 API 时,我收到以下响应:

[
    {
        "id": 1,
        "rater": 3,
        "certified": [],
        "is_approved": false
    }
]

我怎样才能得到以下回复:

[
    {
        "id": 1,
        "rater": 3,
        "certified": [],
        "is_approved": false,
        "first_name": xyz,
        "last_name": abc,
        "username": 123,
        "email": [email protected],
    }
]
python django django-rest-framework django-serializer
3个回答
3
投票

您可以通过几种方式做到这一点。最好的方法是创建一个包含两个模型中的字段的序列化器。您拥有的内容很接近,但因为您的相关字段名称是关系的“配置文件”一侧的

rater
。 (例如,您使用
profile.rater.email
,而不是
profile.approval

您应该使用名称

rater
或指定
source
关键字参数。

class ProfileSerializer(serializers.ModelSerializer):
    approval = UserSerializer(read_only=True, source='rater')
    class Meta:
        model = Profile
        fields = '__all__'

如果您希望结果是扁平的,而不是嵌套的,您可以指定一个

to_representation
方法。

    def to_representation(self, instance):
        # get the usual response as a dictionary
        representation = super().to_representation(instance)
        # pop the nested field and flatten
        user_details = representation.pop('approval')
        representation.update(user_details)
        return representation

您也可以“作弊”并直接从

to_representation
方法中完成此操作,尽管它需要更多的冗长,并且您无法从 UserSerializer 中获得所有定义的优势。但如果您没有序列化器并且由于某种原因不想制作序列化器,这可能会很有用。

   def to_representation(self, instance):
       representation = super().to_representation(instance)
       user = instance.rater
       representation.update({'email': user.email,
                              'first_name', user.first_name,
                              ...
                              })
       return representation

1
投票

尝试将

approval
更改为
rater

class ProfileSerializer(serializers.ModelSerializer):
    rater = UserSerializer(read_only=True)

    class Meta:
        model = Profile
        fields = '__all__'

这将自动从

rater
获取
Profile
字段并将其传递给
UserSerializer

这样你最终会得到:

[
    {
        "id": 1,
        "certified": [],
        "is_approved": false,
        "rater": {
            "id": 3,
            "first_name": "xyz",
            "last_name": "abc",
            "username": "123",
            "email": "[email protected]"
        }
    }
]

0
投票

如果您更需要动态获取内容...

模型上的关系字段:

from django.db.models import ForeignKey
relational_fields = [f.name for f in MyModel._meta.fields if isinstance(f, ForeignKey)]
模型上的

OneToOne
字段:

from django.db.models import OneToOneField
one2one_fields = [f.name for f in MyModel._meta.fields if isinstance(OneToOneField)]

反转模型上的关系字段:

rev_related_field_names = [
    attr
    for attr in dir(model_cls)
    if isinstance(getattr(model_cls, attr).field, ForeignKey)
]```

reverse `OneToOneField`s:
```python
from django.db.models import OneToOneRel
rev_one2one_field_names = [
    attr
    for attr in dir(model_cls)
    if isinstance(getattr(model_cls, attr).field, OneToOneField)
]

]
© www.soinside.com 2019 - 2024. All rights reserved.