DRF中POST请求创建对象时自定义project_id不生成的问题
问题解决:Django API POST请求无法自动生成project_id的问题
问题描述
开发Django后端+Vue前端项目时,通过Django模板保存对象正常,但POST请求调用API时,模型重写的save方法无法生成自定义project_id,触发IntegrityError: UNIQUE constraint failed错误。尝试在视图集添加create方法修改project_id,又报错AttributeError: 'DevProjectViewSet' object has no attribute 'id',需要解决POST请求时自动生成project_id的问题。
现有代码
models.py
class DevProjects(models.Model): PROJECT_TYPE = [ ('New Application', 'New Application'), ('Update Application', 'Update Application'), ('Bug Fixes', 'Bug Fixes') ] PROJECT_STATUS = [ ('New', 'New'), ('In Progress', 'In Progress'), ('Complete', 'Complete'), ] project_id = models.CharField(max_length=15, editable=False, unique=True) project_title = models.CharField(max_length=100) project_desc = models.CharField(max_length=500) project_category = models.CharField(max_length=25, choices=PROJECT_TYPE, null=True, blank=True) project_status = models.CharField(max_length=25, choices=PROJECT_STATUS, default='New') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateField(auto_now=True) created_by = models.ForeignKey(User, related_name='projects', on_delete=models.CASCADE) def save(self, *args, **kwargs): super(DevProjects, self).save(**kwargs) self.project_id = 'PROJ-' + str(self.id) super(DevProjects, self).save(**kwargs) def __str__(self): return self.project_title
serializers.py
class DevProjectSerializer(serializers.ModelSerializer): class Meta: model = DevProjects fields = ("project_id", "project_title", "project_desc", "project_category", "project_status")
views.py
class DevProjectViewSet(viewsets.ModelViewSet): serializer_class = DevProjectSerializer queryset = DevProjects.objects.all() def perform_create(self, serializer): serializer.save(created_by=self.request.user)
错误尝试的代码
def create(self, *args, **kwargs): self.project_id = 'PROJ-' + str(self.id) super(DevProjectViewSet, self).save(**kwargs)
问题分析
- 唯一约束冲突:
project_id设为unique=True,原save方法先空值保存对象,此时空值会触发唯一约束(数据库中空值仅允许存在一条),导致第一次保存就报错。 - 视图集方法错误:尝试的
create方法错误访问视图集实例的id属性,而id是模型实例的属性,因此触发AttributeError。
解决方案
方案1:修正序列化器,标记project_id为只读
由于project_id是自动生成的,不需要前端传入,在序列化器中标记该字段为只读,避免序列化器将其设为None:
class DevProjectSerializer(serializers.ModelSerializer): class Meta: model = DevProjects fields = ("project_id", "project_title", "project_desc", "project_category", "project_status") read_only_fields = ('project_id',) # 新增此行
方案2:优化模型save方法逻辑
仅在新对象创建时生成project_id,减少不必要的数据库操作,同时避免空值触发约束:
def save(self, *args, **kwargs): # 仅新创建对象(无主键)时生成project_id if not self.pk: super().save(*args, **kwargs) self.project_id = f'PROJ-{self.id}' # 仅更新project_id字段,避免重复保存其他数据 super().save(update_fields=['project_id'], *args, **kwargs) else: super().save(*args, **kwargs)
方案3:在视图集perform_create中生成project_id
如果不想修改模型或序列化器,可在视图集的创建逻辑中手动生成并设置:
def perform_create(self, serializer): # 先保存对象获取实例 instance = serializer.save(created_by=self.request.user) # 生成并保存project_id instance.project_id = f'PROJ-{instance.id}' instance.save(update_fields=['project_id'])
验证
修改后发送POST请求,project_id会自动生成,不再触发唯一约束错误或属性错误。
内容的提问来源于stack exchange,提问作者ckcAdmin
相关产品推荐
相关产品推荐

