Django Rest Framework:TypeError - 禁止直接分配给多对多集合的前端
Django Rest Framework: TypeError - Direct assignment to the forward side of a many-to-many set is prohibited
我有一个自定义 User
模型和一个 Group
模型,它们由 UserGroup
通过模型(多对多关系)链接:
models.py
class User(models.Model):
username = models.CharField(primary_key=True, max_length=32, unique=True)
user_email = models.EmailField(max_length=32, unique=False) # Validates an email through predefined regex which checks ‘@’ and a ‘.’
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', # The name to use for the relation from the related object back to this one.
through='UserGroup' # Attaches a Junction table to the Many to Many relationship.
)
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'
)
我正在尝试将多个用户与一个组相关联,使用 PATCH
请求更新组的 members
属性。使用以下 GroupSerializer
,我可以在创建组时将用户关联为组的成员,方法是覆盖序列化程序的 create
函数:
serializers.py
class GroupSerializer(serializers.ModelSerializer):
members = MemberSerializer(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, gets the members list
#print('output: ' + str(members_data[0].items()))
add_remove = self.context['add_remove'] # Comes from the View
if members_data is not None:
if add_remove == 'add':
for member in members_data:
instance.members.add(member['username'])
elif add_remove == 'remove':
for member in members_data:
instance.members.remove(member['username'])
return super().update(instance, validated_data)
覆盖序列化程序的 update
函数时,我无法更新与组关联的成员。从以下 GroupUpdate
视图调用序列化程序:
views.py
class GroupUpdate(generics.UpdateAPIView):
serializer_class = GroupSerializer
def get_object(self):
queryset = Group.objects.all()
group_id = self.kwargs['group_id']
if group_id is not None:
queryset = queryset.filter(group_id=group_id).first()
return queryset
def get_serializer_context(self): # Passes the URL paramters to the GroupSerializer (serializer doesn't have kwargs).
context = super().get_serializer_context()
context['add_remove'] = self.kwargs['add_remove']
print(self.request.data)
return context
def perform_update(self, serializer):
serializer=GroupSerializer(data=self.request.data, partial=True)
serializer.is_valid(raise_exception=True)
return super().perform_update(serializer)
在 GroupUpdate
的 perform_update
函数中,我收到以下内容:TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use members.set() instead.
但我不确定为什么会出现此错误,考虑到我能够关联用户在 create
函数中以几乎相同的方式进行分组。
这是 PATCH 请求作为 JSON 正文的内容:
{
"members": [
{
"username": "small_man"
}
]
}
self.request.data
的输出是{'members': [{'username': 'small_man'}]}
。
您应该在创建序列化程序时指定更新对象的实例,否则序列化程序的保存方法将调用 create
而不是 update
:
def perform_update(self, serializer):
instance = self.get_object()
serializer=GroupSerializer(instance, data=self.request.data, partial=True)
serializer.is_valid(raise_exception=True)
return super().perform_update(serializer)
顺便说一句,perform_update
看起来是多余的,您可以删除它,因为序列化程序验证无需额外修改即可工作。
我有一个自定义 User
模型和一个 Group
模型,它们由 UserGroup
通过模型(多对多关系)链接:
models.py
class User(models.Model):
username = models.CharField(primary_key=True, max_length=32, unique=True)
user_email = models.EmailField(max_length=32, unique=False) # Validates an email through predefined regex which checks ‘@’ and a ‘.’
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', # The name to use for the relation from the related object back to this one.
through='UserGroup' # Attaches a Junction table to the Many to Many relationship.
)
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'
)
我正在尝试将多个用户与一个组相关联,使用 PATCH
请求更新组的 members
属性。使用以下 GroupSerializer
,我可以在创建组时将用户关联为组的成员,方法是覆盖序列化程序的 create
函数:
serializers.py
class GroupSerializer(serializers.ModelSerializer):
members = MemberSerializer(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, gets the members list
#print('output: ' + str(members_data[0].items()))
add_remove = self.context['add_remove'] # Comes from the View
if members_data is not None:
if add_remove == 'add':
for member in members_data:
instance.members.add(member['username'])
elif add_remove == 'remove':
for member in members_data:
instance.members.remove(member['username'])
return super().update(instance, validated_data)
覆盖序列化程序的 update
函数时,我无法更新与组关联的成员。从以下 GroupUpdate
视图调用序列化程序:
views.py
class GroupUpdate(generics.UpdateAPIView):
serializer_class = GroupSerializer
def get_object(self):
queryset = Group.objects.all()
group_id = self.kwargs['group_id']
if group_id is not None:
queryset = queryset.filter(group_id=group_id).first()
return queryset
def get_serializer_context(self): # Passes the URL paramters to the GroupSerializer (serializer doesn't have kwargs).
context = super().get_serializer_context()
context['add_remove'] = self.kwargs['add_remove']
print(self.request.data)
return context
def perform_update(self, serializer):
serializer=GroupSerializer(data=self.request.data, partial=True)
serializer.is_valid(raise_exception=True)
return super().perform_update(serializer)
在 GroupUpdate
的 perform_update
函数中,我收到以下内容:TypeError: Direct assignment to the forward side of a many-to-many set is prohibited. Use members.set() instead.
但我不确定为什么会出现此错误,考虑到我能够关联用户在 create
函数中以几乎相同的方式进行分组。
这是 PATCH 请求作为 JSON 正文的内容:
{
"members": [
{
"username": "small_man"
}
]
}
self.request.data
的输出是{'members': [{'username': 'small_man'}]}
。
您应该在创建序列化程序时指定更新对象的实例,否则序列化程序的保存方法将调用 create
而不是 update
:
def perform_update(self, serializer):
instance = self.get_object()
serializer=GroupSerializer(instance, data=self.request.data, partial=True)
serializer.is_valid(raise_exception=True)
return super().perform_update(serializer)
顺便说一句,perform_update
看起来是多余的,您可以删除它,因为序列化程序验证无需额外修改即可工作。