Python Django REST框架:间接相关属性的SlugRelatedField?
我有一个配置文件模型,它与Django的用户模型有一对一的关系,我还有另一个模型,叫做权限(与Django内部的权限概念无关),它有一个外键来配置文件。这样:(为了简单起见,我删除了这里的大部分字段) 我想为权限创建一个序列化程序,它将创建如下对象:Python Django REST框架:间接相关属性的SlugRelatedField?,python,django,serialization,django-rest-framework,Python,Django,Serialization,Django Rest Framework,我有一个配置文件模型,它与Django的用户模型有一对一的关系,我还有另一个模型,叫做权限(与Django内部的权限概念无关),它有一个外键来配置文件。这样:(为了简单起见,我删除了这里的大部分字段) 我想为权限创建一个序列化程序,它将创建如下对象: { "user": "me@example.com", "account": 123 } 其中,“account”的值是帐户的主键(这样很容易,我可以使用PrimaryKeyRelatedField),而“user”的值是用户的电子邮件地
{
"user": "me@example.com",
"account": 123
}
其中,“account”的值是帐户的主键(这样很容易,我可以使用PrimaryKeyRelatedField),而“user”的值是用户的电子邮件地址(这是我还没有弄清楚的部分,因为电子邮件地址不是直接存储在Profile对象上的,而是存储在关联的DjangoUser对象上)。还请注意,这不是只读的-创建权限时,它确实需要能够从电子邮件地址反序列化到配置文件对象
到目前为止,我已经尝试了一些方法,用于在权限序列化程序上表示用户
一,
对于这一个,如果我发布一个电子邮件地址(或主键或任何其他内容)作为“用户”,它会返回一个400错误,说{“user”:“此字段是必需的。”}
,好像我根本没有包含此字段
二,
有了这个,我得到了AttributeError:“Profile”对象没有属性“django\u user.email”。如果我使用“django\u用户\u电子邮件”
,也会发生同样的情况
有什么想法吗?你能试试:
user=serializers.SlugRelatedField(slug\u field='django\u user\u email')
?有时在Django中,查询的双下划线表示法可能很有用。
来源:为了更好地理解您的问题,我花时间编写了一些代码。如果希望在
权限序列化程序
上完全支持CRUD操作,则需要嵌套配置文件
对象,以便读取其属性。
这些是我建议您实现的序列化程序
from django.contrib.auth.models import User
from rest_framework import serializers
from .models import Permission, Profile, Account
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'email',)
class ProfileSerializer(serializers.ModelSerializer):
django_user = UserSerializer(many=False)
class Meta:
model = Profile
fields = ('django_user',)
class PermissionSerializer(serializers.ModelSerializer):
user = ProfileSerializer(many=False)
class Meta:
model = Permission
fields = ('user', 'account')
输出为:
{
"user": {
"django_user": {
"username": "admin",
"email": "admin@mail.com"
}
},
"account": 1
}
希望这能帮助您,如果这是一种有用的方法,并且您想让它成为可写的look at()。根据Django REST Framework序列化程序参考(): 将用于填充字段的属性的名称。可以是只接受自参数的方法,例如URLField(source='get_absolute_url'),也可以使用点符号遍历属性,例如EmailField(source='user.email') 因此,如果
source='user.email'
不起作用,您可以尝试创建一个方法(例如get\u user\u email
),在source
字段中使用该方法,并使其手动返回用户电子邮件。:
来源
将用于填充字段的属性的名称。也许
是只接受self
参数的方法,例如
URLField(source='get\u absolute\u url')
,也可以使用虚线表示法
遍历属性,例如EmailField(source='user.email')
然而,在我的项目中从未有过使用点符号的成功尝试。我总是使用实例方法或属性来代替。
最近,我深入研究了ModelSerializer
,发现了一些有趣的东西:
def build_field(self, field_name, info, model_class, nested_depth):
"""
Return a two tuple of (cls, kwargs) to build a serializer field with.
"""
if field_name in info.fields_and_pk:
model_field = info.fields_and_pk[field_name]
return self.build_standard_field(field_name, model_field)
elif field_name in info.relations:
relation_info = info.relations[field_name]
if not nested_depth:
return self.build_relational_field(field_name, relation_info)
else:
return self.build_nested_field(field_name, relation_info, nested_depth)
elif hasattr(model_class, field_name):
return self.build_property_field(field_name, model_class)
elif field_name == self.url_field_name:
return self.build_url_field(field_name, model_class)
return self.build_unknown_field(field_name, model_class)
可能处理点符号遍历的部分应该是info.relations中的elif field\u name
- 根据我的项目回溯,
可能类似于字段名
,而“django\u user.email”
是带有OrderedDict的信息
属性的命名偶关系
- 而
OrderedDict的键是info.relations
s和ForeignKey
s的字段名ManyToManyField
- 所以实际上,点符号遍历不会由这个来处理
最后,点符号遍历由
返回self.build\u unknown\u field(…)
处理。问题明确指出,这会导致AttributeError。如原始问题中所述,该字段不是只读的。它需要能够反序列化,而不仅仅是序列化。使用source
并不意味着它是只读的。当您尝试反序列化时会发生什么?
from django.contrib.auth.models import User
from rest_framework import serializers
from .models import Permission, Profile, Account
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'email',)
class ProfileSerializer(serializers.ModelSerializer):
django_user = UserSerializer(many=False)
class Meta:
model = Profile
fields = ('django_user',)
class PermissionSerializer(serializers.ModelSerializer):
user = ProfileSerializer(many=False)
class Meta:
model = Permission
fields = ('user', 'account')
{
"user": {
"django_user": {
"username": "admin",
"email": "admin@mail.com"
}
},
"account": 1
}
def build_field(self, field_name, info, model_class, nested_depth):
"""
Return a two tuple of (cls, kwargs) to build a serializer field with.
"""
if field_name in info.fields_and_pk:
model_field = info.fields_and_pk[field_name]
return self.build_standard_field(field_name, model_field)
elif field_name in info.relations:
relation_info = info.relations[field_name]
if not nested_depth:
return self.build_relational_field(field_name, relation_info)
else:
return self.build_nested_field(field_name, relation_info, nested_depth)
elif hasattr(model_class, field_name):
return self.build_property_field(field_name, model_class)
elif field_name == self.url_field_name:
return self.build_url_field(field_name, model_class)
return self.build_unknown_field(field_name, model_class)