我有一个与Django的用户模型有一对一关系的Profile模型,我有另一个名为Permission的模型(与Django的内部权限理念无关), Profile的外键。像这样:(为了简单起见,我已经删除了大部分字段)
from django.db import models
from django.contrib.auth.models import User as DjangoUser
class Account(models.Model):
name = models.CharField(max_length=200, db_index=True)
class Profile(models.Model):
django_user = models.OneToOneField(DjangoUser)
default_account = models.ForeignKey(Account)
class Permission(models.Model):
# Which user has the permission
user = models.ForeignKey(Profile, db_index=True)
# Which account they have the permission on
account = models.ForeignKey(Account, db_index=True)
我想为Permission创建一个序列化程序,它将创建如下对象:
{
"user": "me@example.com",
"account": 123
}
其中" account"的值是帐户的主键(这样很简单,我可以使用PrimaryKeyRelatedField)和" user"是用户的电子邮件地址(这是我尚未弄清楚的部分,因为电子邮件地址不是直接存储在Profile对象上,而是存储在关联的DjangoUser对象上)。另请注意,这不是只读的 - 在创建权限时,它需要能够从电子邮件地址反序列化为Profile对象。
到目前为止我尝试过的一些事情,用于在Permission序列化器上表示用户......
1
user = serializers.RelatedField(read_only=False)
有了这个,如果我将电子邮件地址(或主键或其他任何内容)作为"用户"发布,则会返回400错误{"user": "This field is required."}
,就好像我没有&#39 ; t包括该字段。
2
user = serializers.SlugRelatedField(slug_field='django_user.email')
有了这个,我得到AttributeError: 'Profile' object has no attribute 'django_user.email'
。如果我使用'django_user__email'
,也会发生同样的事情。
有什么想法吗?
答案 0 :(得分:2)
根据Django REST Framework序列化程序引用(http://www.django-rest-framework.org/api-guide/fields/#core-arguments):
将用于填充字段的属性的名称。可能是一个只接受自身参数的方法,例如URLField(source =' get_absolute_url'),或者可以使用点分表示法来遍历属性,例如EmailField(source =' user.email&# 39。)
因此,如果source='user.email'
不起作用,您可以尝试创建一个方法(例如get_user_email
),在source
字段中使用它并使其手动返回用户电子邮件。< / p>
答案 1 :(得分:0)
你可以尝试:user = serializers.SlugRelatedField(slug_field='django_user__email')
吗?有时在Django中,查询的双下划线符号可能很有用。
资料来源:https://docs.djangoproject.com/en/1.8/topics/db/queries/#field-lookups
答案 2 :(得分:0)
我花时间写了一些代码,以便更好地理解你的问题。如果要完全支持PermissionsSerializer
上的CRUD操作,则需要嵌套Profile
对象,以便可以读取其属性。
这些是我建议你实现的序列化器。
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
}
希望这可以帮到你,如果这个方法很有用,你想让它可以写一下(http://www.django-rest-framework.org/api-guide/relations/#nested-relationships)。
答案 3 :(得分:0)
根据docs:
source
将用于填充字段的属性的名称。可以 是一个只接受
self
参数的方法,例如URLField(source='get_absolute_url')
,或者可以使用点分表示法 遍历属性,例如EmailField(source='user.email')
。
然而,在我的项目中,从未有过使用虚线表示法的成功尝试。我总是最终使用实例方法或属性。
最近我潜入ModelSerializer
的{{3}},发现了一些有趣的事情:
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)
可能处理虚线表示法遍历的部分应为elif field_name in info.relations
。
根据我项目的追溯,field_name
可能类似于"django_user.email"
,而info
是具有OrderedDict的relations
属性的NamedTuple。
info.relations
OrderedDict的键是ForeignKey
和ManyToManyField
s的字段名称。
实际上,点缀符号遍历不会由此处理。
最后,点缀符号遍历由return self.build_unknown_field(...)
source code处理。