You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)

问题分析

  1. 唯一约束冲突:project_id设为unique=True,原save方法先空值保存对象,此时空值会触发唯一约束(数据库中空值仅允许存在一条),导致第一次保存就报错。
  2. 视图集方法错误:尝试的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 10:01:46