Django Rest框架插入和更新可写嵌套序列化程序
我试图使用Django Rest框架插入和更新一个可写的嵌套序列化程序,如下示例所示。但它不起作用,因为在我执行serializer.is\u valid之后,它会丢失serializer.validated\u数据的引用,就像从未发送一样 我做错了什么 我的模型Django Rest框架插入和更新可写嵌套序列化程序,django,django-rest-framework,Django,Django Rest Framework,我试图使用Django Rest框架插入和更新一个可写的嵌套序列化程序,如下示例所示。但它不起作用,因为在我执行serializer.is\u valid之后,它会丢失serializer.validated\u数据的引用,就像从未发送一样 我做错了什么 我的模型 class User(AbstractUser): institution = models.ForeignKey(Institution, on_delete=None, null=True, blank=True)
class User(AbstractUser):
institution = models.ForeignKey(Institution, on_delete=None, null=True, blank=True)
class Meta:
db_table = 'User'
managed = True
verbose_name = 'Users'
verbose_name_plural = 'Users'
ordering = ['id']
def __str__(self):
return self.email
class Institution(models.Model):
id = models.AutoField(db_column='id', primary_key=True)
name = models.CharField(db_column='name', max_length=255, null=False)
country = models.CharField(db_column='country', max_length=255, null=False)
class Meta:
db_table = 'Institution'
managed = True
verbose_name = 'Institutions'
verbose_name_plural = 'Institutions'
ordering = ['id']
def __str__(self):
return self.name
我的序列化程序
class InstitutionSerializer(serializers.ModelSerializer):
class Meta:
model = Institution
fields = '__all__'
datatables_always_serialize = ('id', 'name', 'country')
class UserSerializer(serializers.HyperlinkedModelSerializer):
institution = InstitutionSerializer()
def create(self, validated_data):
return User.objects.create_user(**validated_data)
def update(self, instance, validated_data):
institution_data = validated_data['institution']
instance.institution = Institution.objects.get(pk=institution_data['id'])
return instance
class Meta:
model = User
fields = (
'id',
'username',
'first_name',
'last_name',
'email',
'password',
'is_active',
'institution',
)
datatables_always_serialize = (
'id',
'username',
'first_name',
'last_name',
'email',
'is_active',
'institution',
)
我的看法
class UserViewSet(ModelViewSet):
serializer_class = UserSerializer
permission_classes = (IsSuperUserPermission,)
def list(self, request, **kwargs):
params = Q()
if 'search[value]' in request.GET and request.GET['search[value]'] != '':
params = Q(username__icontains=request.GET['search[value]']) |\
Q(first_name__icontains=request.GET['search[value]']) |\
Q(last_name__icontains=request.GET['search[value]']) |\
Q(email__icontains=request.GET['search[value]']) |\
Q(institution__name__icontains=request.GET['search[value]'])
queryset = User.objects.filter(params).select_related().order_by('id')
serializer = self.serializer_class(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, *args, **kwargs):
queryset = User.objects.filter(pk=request.GET['pk']).select_related()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
def get_permissions(self):
if self.action in ('create',):
self.permission_classes = [AllowAny, ]
return super(self.__class__, self).get_permissions()
def create(self, request, *args, **kwargs):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
serializer.create(serializer.validated_data)
return Response(serializer.data)
else:
return Response(serializer.errors, status.HTTP_500_INTERNAL_SERVER_ERROR)
def partial_update(self, request, *args, **kwargs):
user = User.objects.get(pk=request.data['id'])
serializer = UserSerializer(instance=user, data=request.data, partial=True)
if serializer.is_valid():
if 'password' in serializer.validated_data:
serializer.validated_data['password'] = make_password(serializer.validated_data['password'])
serializer.update(user, serializer.validated_data)
return Response(serializer.data)
else:
return Response(serializer.errors, status.HTTP_500_INTERNAL_SERVER_ERROR)
编辑
我提交的数据如下:
{
"username": "BLA",
"email": "BLA@BLA.com",
"first_name": "BLA",
"last_name": "BLA",
"institution": 1,
"is_active": true,
"password": "bla12345"
}
为什么会出现这个问题?
在更新有效负载中,您将机构数据作为代表PK的整数提供。但您也在UserSerializer类中定义了嵌套的序列化程序InstitutionSerializer。所以,DRF期望一个类似dict的对象,DRF这样说可能会引起一些错误。我不知道为什么在这种情况下没有发生
解决办法是什么?
由于您正在传递机构id,我假定,您只需要在HTTP GET请求上使用嵌套输出。因此,重写UserSerializer类的_uinit__uuu方法,并将嵌套序列化程序的使用限制为仅HTTP GET请求
这是密码
class UserSerializer(serializers.HyperlinkedModelSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.context['request'].method == 'GET':
self.fields['institution'] = InstitutionSerializer()
institution = InstitutionSerializer() # remove this
def create(self, validated_data):
return User.objects.create_user(**validated_data)
def update(self, instance, validated_data):
institution_data = validated_data['institution']
instance.institution = Institution.objects.get(pk=institution_data['id'])
return instance
class Meta:
model = User
fields = (
'id',
'username',
'first_name',
'last_name',
'email',
'password',
'is_active',
'institution',
)
datatables_always_serialize = (
'id',
'username',
'first_name',
'last_name',
'email',
'is_active',
'institution',
)
为什么会出现这个问题?
在更新有效负载中,您将机构数据作为代表PK的整数提供。但您也在UserSerializer类中定义了嵌套的序列化程序InstitutionSerializer。所以,DRF期望一个类似dict的对象,DRF这样说可能会引起一些错误。我不知道为什么在这种情况下没有发生
解决办法是什么?
由于您正在传递机构id,我假定,您只需要在HTTP GET请求上使用嵌套输出。因此,重写UserSerializer类的_uinit__uuu方法,并将嵌套序列化程序的使用限制为仅HTTP GET请求
这是密码
class UserSerializer(serializers.HyperlinkedModelSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.context['request'].method == 'GET':
self.fields['institution'] = InstitutionSerializer()
institution = InstitutionSerializer() # remove this
def create(self, validated_data):
return User.objects.create_user(**validated_data)
def update(self, instance, validated_data):
institution_data = validated_data['institution']
instance.institution = Institution.objects.get(pk=institution_data['id'])
return instance
class Meta:
model = User
fields = (
'id',
'username',
'first_name',
'last_name',
'email',
'password',
'is_active',
'institution',
)
datatables_always_serialize = (
'id',
'username',
'first_name',
'last_name',
'email',
'is_active',
'institution',
)
我找到了一个解决问题的方法,使用JPG的想法。我只是使用PrimaryKeyRelatedField添加了一个else,以允许序列化程序从id获取模型引用。 可能还有另一个解决方案,但这个方案比多个序列化程序更有效,看起来也更好
class UserSerializer(serializers.HyperlinkedModelSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.context['request'].method == 'GET':
self.fields['institution'] = InstitutionSerializer()
else:
self.fields['institution'] = serializers.PrimaryKeyRelatedField(queryset=Institution.objects.all())
我找到了一个解决问题的方法,使用JPG的想法。我只是使用PrimaryKeyRelatedField添加了一个else,以允许序列化程序从id获取模型引用。 可能还有另一个解决方案,但这个方案比多个序列化程序更有效,看起来也更好
class UserSerializer(serializers.HyperlinkedModelSerializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.context['request'].method == 'GET':
self.fields['institution'] = InstitutionSerializer()
else:
self.fields['institution'] = serializers.PrimaryKeyRelatedField(queryset=Institution.objects.all())
您是否收到任何错误?没有错误,只是没有更新字段创建时出现任何问题?实际上,它只是在创建后清除字段。是否有效,然后不更改Instance的值,没有任何其他错误或异常您收到任何错误吗?没有错误,它只是不更新字段创建时有任何问题吗?实际上它只是在.u有效后清除字段,然后不更改Instant的值,没有任何其他错误或异常它返回一个错误:if self.context['request'].method='GET':keyrerror:'request'构造函数中没有请求或某些更改,我现在有一个响应{institution:[无效的超链接-没有URL匹配。]}我已经解释了为什么已验证的_数据不包含institution部分,以适当的方式重写uuu init_uuu方法是另一个解决方案。我不确定我的解决方案为什么不起作用。它返回一个错误:if self.context['request'].method='GET':KeyError:'request'构造函数中没有请求某些更改,我现在有一个响应{institution:[无效的超链接-没有URL匹配。]}我已经解释了为什么验证的_数据不包含机构部分,另一种解决方案是以适当的方式重写_init__方法。我不知道为什么我的解决方案不起作用。