django - 删除时:ValueError:“" 在使用这种多对多关系之前,"id" 字段需要有一个值
问题描述
我很确定人们会说这个问题已经有了答案,但我找不到任何答案。在其他问题中,在创建具有多对多关系的对象时会出现问题。
就我而言,当我尝试删除记录时会发生这种情况......嗯?!
我有用户模型和组(from django.contrib.auth.models import Group
),它们之间具有标准的多对多关系(django 标准)。
在我在序列化程序中使用 Meta 属性之前,一切正常depth
(顺便说一句,这非常方便!)。
我的用户序列化程序:
from rest_framework import serializers
from ..models.base_user import User
class BaseUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
depth = 1
fields = (
'id',
'username',
'email',
'first_name',
'last_name',
'is_active',
'groups',
)
我的组序列化程序:
from django.contrib.auth.models import Group
from rest_framework import serializers
class BaseGroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
depth = 1
fields = (
'id',
'name',
'user_set',
)
def to_representation(self, instance):
response = super().to_representation(instance)
# By using the 'depth' Meta attribute, the nested User records were serialized
# with their password. By doing this, we remove the 'password' field from the
# representation of the Groups and their nested Users.
for user in response.get("user_set"):
user.pop("password", None)
return response
我的 API 函数视图:
@api_view(http_method_names=["DELETE"])
def user_delete(request, id):
"""
Delete the User that corresponds to 'id'.
"""
user = User.objects.get(id=id)
user.delete()
serializer = BaseUserSerializer(user)
return Response(serializer.data)
错误 :
Internal Server Error: /api/users/45/delete/
Traceback (most recent call last):
File "C:\Program Files\Python37\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
response = get_response(request)
File "C:\Program Files\Python37\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Program Files\Python37\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "C:\Program Files\Python37\lib\site-packages\django\views\generic\base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
raise exc
File "C:\Program Files\Python37\lib\site-packages\rest_framework\views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\decorators.py", line 50, in handler
return func(*args, **kwargs)
File "E:\Documents\Projects\my-project\my-project\backend\base\viewsets\base_user_viewset.py", line 142, in user_delete
return Response(serializer.data)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\serializers.py", line 548, in data
ret = super().data
File "C:\Program Files\Python37\lib\site-packages\rest_framework\serializers.py", line 246, in data
self._data = self.to_representation(self.instance)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\serializers.py", line 502, in to_representation
attribute = field.get_attribute(instance)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\fields.py", line 457, in get_attribute
return get_attribute(instance, self.source_attrs)
File "C:\Program Files\Python37\lib\site-packages\rest_framework\fields.py", line 97, in get_attribute
instance = getattr(instance, attr)
File "C:\Program Files\Python37\lib\site-packages\django\db\models\fields\related_descriptors.py", line 536, in __get__
return self.related_manager_cls(instance)
File "C:\Program Files\Python37\lib\site-packages\django\db\models\fields\related_descriptors.py", line 853, in __init__
(instance, self.pk_field_names[self.source_field_name]))
ValueError: "<User: Test USER (testuser)>" needs to have a value for field
"id" before this many-to-many relationship can be used.
[27/Jan/2021 15:59:58] "DELETE /api/users/45/delete/ HTTP/1.1" 500 133778
如果我depth = 1
从 中删除BaseUserSerializer
,则没有任何错误。我不明白它为什么会发生,以及如何解决它。
注意:用户仍然被有效删除,但由于有 ValueError 而不是正常响应,我的前端没有按预期运行......
任何帮助表示赞赏:)
解决方案
就个人而言,我会避免让DELETE
请求路径返回用户详细信息。相反,它可以根据 HTTP 响应的状态返回 id 或成功/失败。但是,如果您想让您拥有的东西起作用,您需要在删除用户之前生成响应,否则所有这些关系都会被破坏,从而导致您遇到错误。
@api_view(http_method_names=["DELETE"])
def user_delete(request, id):
"""
Delete the User that corresponds to 'id'.
"""
user = User.objects.get(id=id)
# Generate the response before deleting the user and it's relationships.
response = Response(BaseUserSerializer(user).data)
user.delete()
return response
此外,您可以使用以下代码删除 BaseGroupSerializer.to_representation 中的 hack。这将告诉 DRF 具体使用哪个序列化程序,从而限制 BaseUserSerializer 中的可用字段。我实际上建议不要使用depth
,因为当您将模型添加到数据库时,它们会自动添加到您的 API 中。我的直觉是只通过显式更改来更改 API。
class BaseGroupSerializer(serializers.ModelSerializer):
user_set = BaseUserSerializer(many=True)
class Meta:
model = Group
depth = 1
fields = (
'id',
'name',
'user_set',
)
推荐阅读
- typescript - TypeScript - 你如何推断接口泛型参数
- r - 卡方检验失败
- css - CSS - @media 屏幕和(最大宽度:---px)在 Firefox 移动设备上不起作用
- javascript - 如何在异步函数中实现 Promise 的结果?
- android - Android Studio - CMake 错误:CMake 无法找到与“Ninja”对应的构建程序。CMAKE_MAKE_PROGRAM 未设置
- node.js - 为每个用户 nodejs 渲染信息
- c# - Oracle Advanced Queue 的消息状态在使用 ODP.net 出队后未更新
- weka - 显示加权平均的问号。weka中的精度
- for-loop - 为什么循环范围内没有增量,其范围是循环的长度,即使长度在循环内增加?
- mongodb - Mongodb 按功能分组,提供意外数据