我对 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],
}
]
您可以通过几种方式做到这一点。最好的方法是创建一个包含两个模型中的字段的序列化器。您拥有的内容很接近,但因为您的相关字段名称是关系的“配置文件”一侧的
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
尝试将
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]"
}
}
]
如果您更需要动态获取内容...
模型上的关系字段:
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)
]
]