- 首先说明一下遇到的问题,我创建了三个模型,具体关系如下:
class Device(models.Model):
device_name = models.CharField(max_length=20, verbose_name='设备名称', db_index=True)
device_ip = models.GenericIPAddressField(verbose_name='IP地址',max_length=255,db_index=True)
device_username = models.CharField(verbose_name='用户名',max_length=20,blank=True,null=True)
device_password = models.CharField(verbose_name='登录密码',max_length=10,blank=True,null=True)
device_port = models.IntegerField(verbose_name='端口号')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')
user = models.ForeignKey(UserInfo,verbose_name='添加人',on_delete=models.CASCADE,blank=True)
class Meta:
verbose_name_plural = verbose_name = '设备管理'
class Soft(models.Model):
soft_name = models.CharField(verbose_name='软件包名称', max_length=50, db_index=True)
soft_version = models.CharField(verbose_name='软件包版本',unique=True,db_index=True,max_length=255)
create_time = models.DateTimeField(auto_now_add=True,verbose_name='添加时间')
class Meta:
verbose_name_plural = verbose_name = '软件信息'
class Project(models.Model):
project_name = models.CharField(max_length=50, verbose_name='项目名称', db_index=True)
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
user = models.ForeignKey(UserInfo, verbose_name='创建者', related_name='project_user',on_delete=models.CASCADE,blank=True)
device = models.ForeignKey(Device,verbose_name='测试设备',related_name='project_device',on_delete=models.CASCADE,blank=True)
soft = models.ForeignKey(Soft,verbose_name='测试软件',related_name='project_soft',on_delete=models.CASCADE,blank=True)
class Meta:
verbose_name_plural = verbose_name = '项目管理'
- 在序列化过程中,根据官方文档,当我想嵌套显示外键数据时,使用了官网上推荐的做法:
class ProjectSerializer(serializers.ModelSerializer):
soft = SoftSerializer(read_only=True)
device = DeviceSerializer(read_only=True)
user = UserSerializer(read_only=True)
- 上图中的三个字段对应模型中的三个外键,在该设置下,*当进行序列化输出时,可以正常显示,但是当使用post新建时,会出现
device_id cannot be null
的错误提示,我相信soft会出现同样的问题。 - 简单说一下为什么会出现上面的问题,使用当我们在调用
serializer.save()
方法时,需要相应的数据已经创建,但是ID
字段应该是需要当对象创建后才会生成,所以导致无法保存。可参考下面的两个链接。 - https://github.com/encode/django-rest-framework/issues/2964)
- https://stackoverflow.com/questions/46805662/collections-ordereddict-object-has-no-attribute-pk-django-rest-framework
- 知道了问题的原因,基本可以锁定是在序列化器中
def create(self, validated_data):
方法出了问题。 - 解决方法:
try:
'''
第一个 try 方法解决了嵌套序列化的创建问题
'''
soft_id = self.initial_data.get('device', None)
device_id = self.initial_data.get('soft',None)
soft = Soft.objects.get(id=soft_id)
device = Device.objects.get(id=device_id)
except Soft.DoesNotExist or Device.DoesNotExist:
raise serializers.ValidationError('软件包或设备不存在,请重新确认')
validated_data.update(user=request.user,device=device,soft=soft)
instance = super(ProjectSerializer, self).create(validated_data)
return instance
- 首先,我不知道为什么当我通过表单传递
device,soft
参数时,
soft = SoftSerializer(read_only=True)
device = DeviceSerializer(read_only=True)
user = UserSerializer(read_only=True)
,validated_data
中为什么会导致数据不见,当我把上面的三个序列化器注释掉时,参数则会显示出来,有知道的小伙伴可以在评论区说一下,先谢过了,但是我们仍然可以通过self.initial_data
取到前端传入的初始数据,通过这种方式我们手动到数据库中取到相应的对象,并更新validated_data
,之后再创建就不会出现问题了。