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

Django REST API中serializer.save()设partner1为null致完整性错误

Django序列化器保存时partner1字段为null的问题分析及解决

问题场景

在Django项目中定义了business模型、对应序列化器及视图,GET请求功能正常,但执行POST创建数据时,明明验证后的validated_data包含partner1的有效值john,调用serialized_business.save()后该字段却被设为null,触发数据库非空约束错误。


1. 模型定义

class business(models.Model):
    business_category = models.ForeignKey(businessCategory, related_name='businesss', on_delete=models.CASCADE)
    partner1 = models.CharField(max_length=255)  # 非空约束,未开启blank/null
    partner1_is_creator = models.BooleanField(default=True)
    partner2 = models.CharField(max_length=255)
    creator = models.ForeignKey(User, related_name='businesss', on_delete=models.CASCADE, null=True)
    name = models.CharField(max_length=255)
    setting = models.CharField(max_length=255)
    estimated_budget = models.FloatField()
    location = models.CharField(max_length=255)
    date_created = models.DateTimeField(auto_now_add=True)
    business_start_date = models.DateTimeField(null=True, editable=True, default=django.utils.timezone.now)
    business_end_date = models.DateTimeField(null=True, editable=True, default=django.utils.timezone.now)

2. 序列化器代码

class BusinessCreator(serializers.ModelSerializer):
    class Meta:
        model = business
        fields = ['business_category', 'name', 'partner1', 'partner2', 'partner1_is_creator', 'business_start_date',
                  'location', 'setting', 'estimated_budget']

3. 视图代码

class BusinessList(APIView):
    @method_decorator(login_required, name='dispatch')
    def get(self, request):
        created_user = request.user
        businesss = Business.objects.filter(creator=created_user)
        serializer = BusinessSummary(businesss, many=True)
        return Response(serializer.data)

    @method_decorator(login_required, name='dispatch')
    def post(self, request):
        new_business = request.data.get('business')
        serialized_business = BusinessCreator(data=new_business)
        if serialized_business.is_valid(raise_exception=True):
            print(serialized_business.validated_data)
            serialized_business.save()
            return Response(serialized_business.data, status=201)
        return Response(serialized_business.errors, status=400)

4. POST请求数据

{
"business":{
    "business_category": 3,
    "name": "business1",
    "partner1": "john",
    "partner2": "smith",
    "partner1_is_owner": true,
    "business_start_date": "2024-09-18T08:03:00Z",
    "location": "CA",
    "setting": "club",
    "estimated_budget": 121.0
}
}

5. 报错信息

IntegrityError at /business/businessviewall/
NOT NULL constraint failed: business_business.partner1

6. 验证后的数据输出

{'business_category': <BusinessCategory: food>, 'name': 'business1', 'partner1': 'john', 'partner2': 'smith', 'partner1_is_creator': True, 'business_start_date': datetime.datetime(2024, 9, 18, 8, 3, tzinfo=zoneinfo.ZoneInfo(key='UTC')), 'location': 'CA', 'setting': 'club', 'estimated_budget': 121.0}

问题原因

  1. 模型类名大小写不统一:
    模型定义为小写的business,但视图GET方法中查询用了大写的Business,这会导致Django ORM的模型映射混淆——要么项目中存在另一个Business模型,要么ORM无法正确匹配序列化器绑定的模型,最终保存时字段映射错误,partner1未被正确写入。
  2. 请求字段名不匹配:
    请求中传递的是partner1_is_owner,但模型和序列化器中字段为partner1_is_creator,虽然后者有默认值不影响验证,但属于数据传递的不规范问题。

解决方法

  1. 统一模型类命名规范:
    按照Django约定,模型类使用大驼峰命名,修改模型类名并同步所有引用:
    # 模型修改
    class Business(models.Model):
        # 字段定义保持不变
    
    # 序列化器修改
    class BusinessCreator(serializers.ModelSerializer):
        class Meta:
            model = Business  # 同步改为大写
            fields = ['business_category', 'name', 'partner1', 'partner2', 'partner1_is_creator', 'business_start_date',
                      'location', 'setting', 'estimated_budget']
    
  2. 修正请求字段名:
    将POST请求中的partner1_is_owner改为partner1_is_creator,避免依赖默认值,确保数据传递准确。
  3. 同步数据库结构:
    执行python manage.py makemigrations和python manage.py migrate,确保数据库表结构与当前模型一致,清理可能存在的重复表。

内容的提问来源于stack exchange,提问作者Nht_e0

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 17:20:58