Django Rest Framework:重写序列化程序中的 'update' 函数时出现 KeyError
Django Rest Framework: KeyError when Overriding 'update' Function in a Serializer
我有一个 User
模型和一个 Group
模型,如下所示:
class User(models.Model):
username = models.CharField(primary_key=True, max_length=32, unique=True)
user_email = models.EmailField(max_length=32, unique=False)
user_password = models.CharField(max_length=32)
user_avatar_path = models.CharField(max_length=64)
class Group(models.Model):
group_id = models.AutoField(primary_key=True)
group_name = models.CharField(max_length=32, unique=False)
group_admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='my_groups')
members = models.ManyToManyField(User, related_name='groups', through='UserGroup')
每个组可以有多个用户与之关联,每个用户可以关联到多个组,这是用 ManyToManyField
和模型之间的直通模型建模的。当我创建一个组时,创建该组的用户被自动指定为组管理员,因此被添加为该组的成员:
class MemberSerializer(serializers.ModelSerializer): # The nested serializer used within the GroupSerializer
username = serializers.ReadOnlyField(source='user.username')
class Meta:
model = User
fields = ['username']
class GroupSerializer(serializers.ModelSerializer):
members = MemberSerializer(source='user_groups', many=True, required=False)
group_admin = serializers.SlugRelatedField(slug_field='username', queryset=User.objects.all()) # A Group object is related to a User object by username
class Meta:
model = Group
fields = ['group_id', 'group_name', 'group_admin', 'members']
def create(self, validated_data): # Overriden so that when a group is created, the group admin is automatically declared as a member.
group = Group.objects.create(**validated_data)
group_admin_data = validated_data.pop('group_admin')
group.members.add(group_admin_data)
return group
def update(self, instance, validated_data):
members_data = validated_data.pop('members') # Comes from the request body
group_id = self.kwargs['group_id'] # Comes from the URL
add_remove = self.kwargs['add_remove'] # Comes from the URL
group = Group.objects.filter(group_id=group_id).first()
if members_data is not None:
if add_remove == 'add':
for member in members_data:
group.members.add(member['username'])
elif add_remove == 'remove':
for member in members_data:
group.members.remove(member['username'])
return super().update(instance, validated_data)
通过覆盖 GroupSerializer
的 create
方法,然后发出 POST
请求,成功将创建组的用户(组管理员)添加为成员如下所示:
{
"group_name": "Whosebug",
"group_admin": "bigboy"
}
# which then results in the response when the group has been successfully created:
{
"group_id": 1,
"group_name": "Whosebug",
"group_admin": "bigboy",
"members": [
{
"username": "bigboy"
}
]
}
我希望能够通过 PATCH
请求通过添加或删除与组关联的用户来更新组成员。如上所示,我试图通过覆盖 GroupSerializer
的 update
方法来做到这一点。 PATCH
请求如下所示,使用 http://127.0.0.1:8000/group/1/add/update
的 URL 将用户添加到组:
{
"members": [
{
"username": "small_man"
}
]
}
收到的错误:
line 47, in update
members_data = validated_data.pop('members') # Comes from the request body
KeyError: 'members'
我不确定我尝试将用户添加到群组的方法是否简单甚至有效,但 KeyError
令人困惑,因为我假设经过验证的数据确实包含members
列表。
编辑
上面的错误已经解决。
我覆盖了 GroupUpdate
视图的 perform_update
方法,如下所示,以了解为什么我的请求数据无法验证:
def perform_update(self, serializer):
serializer=GroupSerializer(data=self.request.data, partial=True)
serializer.is_valid(raise_exception=True)
return super().perform_update(serializer)
出现的更详细的错误是:
TypeError: Direct assignment to the reverse side of a related set is prohibited. Use user_groups.set() instead.
作为参考,user_groups 是 UserGroup
through 模型的 related_name
:
class UserGroup(models.Model): # Manually specified Junction table for User and Group
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='user_groups'
)
group = models.ForeignKey(
Group,
on_delete=models.CASCADE,
related_name='user_groups'
)
当您使用 source
参数时,您可以使用源值作为键来访问您的数据,试试这个:
def update(self, instance, validated_data):
members_data = validated_data.pop('user_groups')
我有一个 User
模型和一个 Group
模型,如下所示:
class User(models.Model):
username = models.CharField(primary_key=True, max_length=32, unique=True)
user_email = models.EmailField(max_length=32, unique=False)
user_password = models.CharField(max_length=32)
user_avatar_path = models.CharField(max_length=64)
class Group(models.Model):
group_id = models.AutoField(primary_key=True)
group_name = models.CharField(max_length=32, unique=False)
group_admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='my_groups')
members = models.ManyToManyField(User, related_name='groups', through='UserGroup')
每个组可以有多个用户与之关联,每个用户可以关联到多个组,这是用 ManyToManyField
和模型之间的直通模型建模的。当我创建一个组时,创建该组的用户被自动指定为组管理员,因此被添加为该组的成员:
class MemberSerializer(serializers.ModelSerializer): # The nested serializer used within the GroupSerializer
username = serializers.ReadOnlyField(source='user.username')
class Meta:
model = User
fields = ['username']
class GroupSerializer(serializers.ModelSerializer):
members = MemberSerializer(source='user_groups', many=True, required=False)
group_admin = serializers.SlugRelatedField(slug_field='username', queryset=User.objects.all()) # A Group object is related to a User object by username
class Meta:
model = Group
fields = ['group_id', 'group_name', 'group_admin', 'members']
def create(self, validated_data): # Overriden so that when a group is created, the group admin is automatically declared as a member.
group = Group.objects.create(**validated_data)
group_admin_data = validated_data.pop('group_admin')
group.members.add(group_admin_data)
return group
def update(self, instance, validated_data):
members_data = validated_data.pop('members') # Comes from the request body
group_id = self.kwargs['group_id'] # Comes from the URL
add_remove = self.kwargs['add_remove'] # Comes from the URL
group = Group.objects.filter(group_id=group_id).first()
if members_data is not None:
if add_remove == 'add':
for member in members_data:
group.members.add(member['username'])
elif add_remove == 'remove':
for member in members_data:
group.members.remove(member['username'])
return super().update(instance, validated_data)
通过覆盖 GroupSerializer
的 create
方法,然后发出 POST
请求,成功将创建组的用户(组管理员)添加为成员如下所示:
{
"group_name": "Whosebug",
"group_admin": "bigboy"
}
# which then results in the response when the group has been successfully created:
{
"group_id": 1,
"group_name": "Whosebug",
"group_admin": "bigboy",
"members": [
{
"username": "bigboy"
}
]
}
我希望能够通过 PATCH
请求通过添加或删除与组关联的用户来更新组成员。如上所示,我试图通过覆盖 GroupSerializer
的 update
方法来做到这一点。 PATCH
请求如下所示,使用 http://127.0.0.1:8000/group/1/add/update
的 URL 将用户添加到组:
{
"members": [
{
"username": "small_man"
}
]
}
收到的错误:
line 47, in update
members_data = validated_data.pop('members') # Comes from the request body
KeyError: 'members'
我不确定我尝试将用户添加到群组的方法是否简单甚至有效,但 KeyError
令人困惑,因为我假设经过验证的数据确实包含members
列表。
编辑
上面的错误已经解决。
我覆盖了 GroupUpdate
视图的 perform_update
方法,如下所示,以了解为什么我的请求数据无法验证:
def perform_update(self, serializer):
serializer=GroupSerializer(data=self.request.data, partial=True)
serializer.is_valid(raise_exception=True)
return super().perform_update(serializer)
出现的更详细的错误是:
TypeError: Direct assignment to the reverse side of a related set is prohibited. Use user_groups.set() instead.
作为参考,user_groups 是 UserGroup
through 模型的 related_name
:
class UserGroup(models.Model): # Manually specified Junction table for User and Group
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='user_groups'
)
group = models.ForeignKey(
Group,
on_delete=models.CASCADE,
related_name='user_groups'
)
当您使用 source
参数时,您可以使用源值作为键来访问您的数据,试试这个:
def update(self, instance, validated_data):
members_data = validated_data.pop('user_groups')