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

Django Rest Framework序列化器如何实现两字段二选一必填校验

实现方案

第一步:调整字段基础配置

先把两个字段都改为非必填,移除addressid的source配置避免和模型字段映射冲突:

  • 两个字段都设置required=False、allow_null=True,取消默认的必填校验
  • addressid不需要绑定模型字段,作为独立的入参字段使用

第二步:添加全局校验逻辑

重写序列化器的validate方法,实现二选一的条件校验:

  • 校验规则:两个字段不能同时为空,也不能同时传入
  • 不符合规则直接抛出serializers.ValidationError

第三步:重写create方法处理业务逻辑

根据入参情况处理address字段的赋值:

  • 传入addressid时:直接查询对应的地址实例绑定到订单
  • 传入address嵌套数据时:先调用地址序列化器创建新的地址实例,再绑定到订单

修改后完整代码如下:

from rest_framework import serializers
from .models import Order, Address # 注意你原代码中的AdressSerializer拼写可能有误,这里统一为Address

class OrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = Order
        exclude = ['in_calculation','canceled',]
        read_only_fields = ['id','user','status','costs']

    # 调整字段配置,均设为非必填
    address = AddressSerializer(required=False, allow_null=True)
    addressid = serializers.CharField(required=False, allow_null=True)

    def validate(self, attrs):
        # 二选一校验
        has_address = attrs.get('address') is not None
        has_addressid = attrs.get('addressid') is not None
        if not has_address and not has_addressid:
            raise serializers.ValidationError("请传入地址ID或新地址信息")
        if has_address and has_addressid:
            raise serializers.ValidationError("地址ID和新地址信息只能传入其中一个")
        return attrs

    def create(self, validated_data):
        # 移除不需要的addressid字段,避免写入模型报错
        address_id = validated_data.pop('addressid', None)
        address_data = validated_data.pop('address', None)

        # 处理地址逻辑
        if address_id:
            # 传入地址ID的情况,查询已有地址
            address = Address.objects.get(id=address_id)
            validated_data['address'] = address
        else:
            # 传入新地址的情况,先创建地址
            address_serializer = AddressSerializer(data=address_data)
            address_serializer.is_valid(raise_exception=True)
            address = address_serializer.save()
            validated_data['address'] = address
        
        # 正常创建订单
        return super().create(validated_data)

补充说明

如果需要支持PUT更新场景,参照同样的逻辑重写update方法即可。
地址查询的部分可以根据你的业务需求添加权限校验,比如校验地址是否属于当前登录用户。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 18:54:03