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

如何在DRF序列化器中添加owner外键与transaction一对一字段创建实体

解决序列化器添加外键与一对一字段的问题

1. 处理owner外键字段(关联当前登录用户)

由于owner关联的是当前登录用户,不需要前端传递该字段,我们可以将其设为只读字段,在保存时直接从请求对象中获取登录用户赋值:

修改序列化器:

class CreateAppoinmentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Appoinment
        fields = [
            'applicant_name', 'submission_date', 'appoinment_date',
            'care_of', 'phone', 'appoinment_time', 'pass_seva_username',
            'pass_seva_password', 'office', 'agency', 'paid', 'net_amount',  # 补全未写完的字段名
            'owner', 'transaction'  # 新增两个字段
        ]
        read_only_fields = ['owner']  # 标记owner为只读,无需前端传值

修改视图代码:

在调用save()方法时,直接传入owner参数,值为当前登录用户:

@permission_classes([IsAuthenticated])
@api_view(["POST"])
def createAppoinment(req):
    appoinment = CreateAppoinmentSerializer(data=req.data)
    if appoinment.is_valid():
        # 传入当前登录用户作为owner字段的值
        appoinment.save(owner=req.user)
        return Response(appoinment.data, status=status.HTTP_201_CREATED)
    # 注意:验证失败应返回400错误,而非404
    return Response(appoinment.errors, status=status.HTTP_400_BAD_REQUEST)

2. 处理transaction一对一字段

分两种场景处理:

场景一:前端传递已存在的Transaction主键ID

如果前端会提供关联的Transaction的ID,在序列化器中显式定义该字段,指定查询集:

class CreateAppoinmentSerializer(serializers.ModelSerializer):
    # 显式定义transaction字段,允许前端传主键ID
    transaction = serializers.PrimaryKeyRelatedField(queryset=Transaction.objects.all())
    
    class Meta:
        model = Appoinment
        fields = [
            # 其他字段...
            'owner', 'transaction'
        ]
        read_only_fields = ['owner']

此时前端只需在请求体中传入transaction: 1(对应Transaction的ID)即可完成关联。

场景二:后台自动创建Transaction并关联

如果需要在创建Appointment时自动生成关联的Transaction实例,可以重写序列化器的create方法,或者在视图中处理:

方式一:重写序列化器的create方法
class CreateAppoinmentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Appoinment
        fields = [
            # 其他字段...
            'owner', 'transaction'
        ]
        read_only_fields = ['owner', 'transaction']  # transaction也设为只读

    def create(self, validated_data):
        # 先创建Transaction实例(按需传入字段值)
        transaction = Transaction.objects.create()
        # 创建Appointment并关联transaction
        appointment = Appoinment.objects.create(transaction=transaction, **validated_data)
        return appointment
方式二:在视图中处理
@permission_classes([IsAuthenticated])
@api_view(["POST"])
def createAppoinment(req):
    appoinment = CreateAppoinmentSerializer(data=req.data)
    if appoinment.is_valid():
        # 先创建Transaction实例
        transaction = Transaction.objects.create()
        # 同时传入owner和transaction
        appoinment.save(owner=req.user, transaction=transaction)
        return Response(appoinment.data, status=status.HTTP_201_CREATED)
    return Response(appoinment.errors, status=status.HTTP_400_BAD_REQUEST)

注意事项

  • 原视图中验证失败返回HTTP_404_NOT_FOUND是错误的,应改为HTTP_400_BAD_REQUEST,因为404表示资源不存在,而请求数据无效属于客户端错误,对应400状态码。
  • 确保Appoinment模型中owner字段的定义正确,例如:owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name="appointments")。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 21:00:21