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

Django自定义手机号用户模型外键关联时User匹配查询不存在报错

Django自定义用户模型外键关联报错解决方案

报错核心原因排查与解决

    1. 视图逻辑顺序错误,未校验用户存在就直接查询
      当前代码先执行User.objects.get(phone_number=phone_number),虽然提前做了number_exists存在性判断,但完全没有处理不存在的分支,只要传入的手机号无对应用户就会直接抛出DoesNotExist错误。
      修复方法:优先做参数校验,再用try-except捕获不存在的情况,返回友好响应。
    1. 直接取未校验的请求参数,值不符合预期
      从request.data直接拿参数,未经过序列化器校验,可能出现phone_number为空、拼写错误、携带多余空格/国家码的情况,和数据库存储的格式不匹配导致查不到用户。
      修复方法:把serializer.is_valid(raise_exception=True)放到参数取值前,从校验后的serializer.validated_data里取值,同时对手机号做去空格处理。
    1. 交易模型外键默认值配置错误
      TransactionModel中关联用户的外键设置了default=1,但你指定了to_field="phone_number",关联字段是手机号,默认值1不是合法的手机号,保存交易记录时如果没传入用户值,会自动查询phone_number=1的用户,直接触发报错。
      修复方法:删除错误的default配置,要么设置null=True, blank=True允许外键为空,要么保存序列化器时主动传入关联的用户对象。
    1. 自定义用户模型缺失必要配置
      继承AbstractBaseUser的自定义用户模型必须指定USERNAME_FIELD为你用来做唯一标识的字段,否则Django默认会用username作为用户标识,可能引发隐式查询错误。
      修复方法:在User模型中添加配置项:
USERNAME_FIELD = 'phone_number'

修正后参考代码

调整后的用户模型

class User(AbstractBaseUser, PermissionsMixin):
    phone_number = models.CharField("Phone number", max_length=100, unique=True, error_messages={
            'unique': "number_existsssss",
        })
    name = models.TextField("Name")
    time_stamp = models.DateTimeField("Time-Date", auto_now=True)
    # 补全原代码缺失的右括号
    request_type = models.CharField(max_length=100, default="check")
    is_staff = models.BooleanField(verbose_name='staff status', default=False)
    is_active = models.BooleanField(verbose_name='active', default=True)
    # 补充余额字段(原视图用到但未定义)
    current_balance = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    # 声明唯一标识字段
    USERNAME_FIELD = 'phone_number'

调整后的交易模型

class TransactionModel(models.Model):
    trxID = models.CharField(max_length=15, null=True, unique=True)
    # 删除错误的default=1,根据业务需要选择是否允许为空,字段名改用小写蛇形避免和类名混淆
    user = models.ForeignKey(
        to=User, 
        to_field="phone_number", 
        related_name='transactions', 
        on_delete=models.DO_NOTHING,
        null=True,
        blank=True
    )
    time = models.DateTimeField(auto_now=True, null=True)
    amount = models.CharField(max_length=5, null=True)
    pay_method = models.CharField(max_length=10, null=True)
    amountReceivedFrom = models.CharField(max_length=26, null=True)
    transactionStatus = models.CharField(max_length=15, null=True, default='False')

调整后的视图代码

class BkashCashinView(APIView):
    @transaction.atomic
    def post(self, request, *args, **kwargs):
        HEADERS = {
            "Access-Control-Allow-Origin": "*"
        }
        # 优先做参数校验
        serializer = BkashCashinSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        req = serializer.validated_data
        
        trx_id = req.get('trxID')
        # 去空格避免多余字符导致查询失败
        phone_number = req.get('phone_number', '').strip()
        recharge_amount = float(req.get('amount'))

        # 捕获用户不存在的情况
        try:
            current_user_data = User.objects.select_for_update().get(phone_number=phone_number)
        except User.DoesNotExist:
            return Response({
                "status": "fail",
                "msg": "对应用户不存在"
            }, status=400, headers=HEADERS)
        
        # 更新余额
        current_user_data.current_balance += recharge_amount
        current_user_data.save()

        # 保存交易时主动传入关联用户,避免触发默认值查询
        serializer.save(user=current_user_data)
        
        context = {
            "current_balance": current_user_data.current_balance,
            "status": "success"
        }
        return Response(context, headers=HEADERS)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 11:30:04