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

Django填充MRZ表时出现400 Bad Request错误排查求助

问题排查:Flutter填充Django MRZ表时400 Bad Request错误

问题描述

在用Flutter移动端填充Django后端的MRZ表时,遇到400 Bad Request错误。所有属性从Flutter获取,仅ccp_account从后端获取(打印无输出)。服务器日志显示各参数已正常获取,但仍返回400错误。

相关代码与日志

MRZ模型代码

class MRZ(models.Model):
    id_mrz = models.AutoField(primary_key=True)
    FK_compte_ccp = models.OneToOneField(CompteCcp, on_delete=models.CASCADE)
    photo_passport = models.ImageField(upload_to='mrz_photos/')
    birthDate = models.DateField(null=True, blank=True)
    documentNumber = models.CharField(max_length=100, null=True, blank=True)
    expiryDate = models.DateField(null=True, blank=True)

视图代码

def remplir_mrz(request):
    if request.method == 'POST':
        try:
            # 从请求头获取JWT token
            token = request.headers.get('Authorization').split(' ')[1]
            
            print("Données reçues :", request.POST)
            print("Token JWT récupéré :", token)

            if token:
                # 解码JWT获取用户ID
                decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
                print("Token JWT decoder :", decoded_token)
                user_id = decoded_token['user_id']
                print("user id :", user_id)

                # 获取关联的CCP账户
                compte_ccp = get_object_or_404(CompteCcp, FK_compte_app=user_id)                
                if 'photo_passport' in request.FILES:
                    image_file = request.FILES['photo_passport']

                    # 创建用户专属文件夹
                    user_folder = os.path.join(settings.MEDIA_ROOT, str(user_id))
                    if not os.path.exists(user_folder):
                        os.makedirs(user_folder)

                    # 构造文件路径
                    filename = "MRZ.jpg"
                    filepath = os.path.join(user_folder, filename)

                    # 保存上传的图片
                    with default_storage.open(filepath, 'wb+') as destination:
                        for chunk in image_file.chunks():
                            destination.write(chunk)

                    # 处理前端传入的MRZ数据
                    document_number = request.POST.get('document_number')
                    birth_datetime_str = request.POST.get('birth_date')
                    expiry_datetime_str = request.POST.get('expiry_date')

                    # 转换日期格式
                    birth_datetime = datetime.strptime(birth_datetime_str, "%Y-%m-%dT%H:%M:%S.%f")
                    expiry_datetime = datetime.strptime(expiry_datetime_str, "%Y-%m-%dT%H:%M:%S.%f")
                    birth_date = birth_datetime.date()
                    expiry_date = expiry_datetime.date()
                    
                    print("documebt_number",document_number)
                    print("birth_date",birth_date)
                    print("expiry_date",expiry_date)
                    print("file path",filepath)
                    print("compte_ccp",compte_ccp)

                    # 保存MRZ数据到数据库
                    mrz = MRZ.objects.create(
                        FK_compte_ccp=compte_ccp,
                        photo_passport=filepath,
                        document_number=document_number,
                        birth_date=birth_date,
                        expiry_date=expiry_date
                    )

                    print("MRZ enregistrée avec succès.")
                    return JsonResponse({'message': 'MRZ enregistrée avec succès'}, status=201)
                else:
                    return JsonResponse({'message': 'Aucune image reçue'}, status=403)
            else:
                return JsonResponse({'message': 'Token JWT manquant'}, status=404)
        except jwt.ExpiredSignatureError:
            return JsonResponse({'message': 'Token JWT expiré'}, status=401)
        except jwt.InvalidTokenError:
            return JsonResponse({'message': 'Token JWT invalide'}, status=401)
        except CompteCcp.DoesNotExist:
            return JsonResponse({'message': 'Aucun compte CCP trouvé pour cet utilisateur'}, status=404)
        except Exception as e:
            # 添加打印查看具体异常信息
            print("Erreur détaillée :", str(e))
            return JsonResponse({'message': str(e)}, status=400)
    else:
        return JsonResponse({'message': 'Méthode HTTP non autorisée'}, status=405)

服务器日志

Données reçues : <QueryDict: {'document_number': ['308491574'], 'birth_date': ['2001-08-27T00:00:00.000'], 'expiry_date': ['2033-01-08T00:00:00.000']}>
Token JWT récupéré : eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMCwidXNlcm5hbWUiOiJyaXNlMkBnbWFpbC5jb20iLCJleHAiOjE3MTQ4MjQ2MDMsImVtYWlsIjoicmlzZTJAZ21haWwuY29tIn0.38Afbpt0HNAbkY_PdXZ5sPN1ObtjFoa5JtkLmGfVwhw
Token JWT decoder : {'user_id': 10, 'username': 'rise2@gmail.com', 'exp': 1714824603, 'email': 'rise2@gmail.com'}
user id : 10
documebt_number 308491574
birth_date 2001-08-27
expiry_date 2033-01-08
file path C:\Users\morsi\Documents\python\Poste_Projet\media\10\MRZ.jpg
Bad Request: /compte/api/remplir_mrz/
[04/May/2024 12:11:17] "POST /compte/api/remplir_mrz/ HTTP/1.1" 400 63

排查与解决方案

1. 模型字段名与视图传入字段不匹配

MRZ模型中日期和文档编号字段为驼峰命名:birthDate、documentNumber、expiryDate,但视图创建对象时使用下划线命名:birth_date、document_number、expiry_date。Django ORM会严格匹配字段名,这会导致字段无法赋值,触发验证错误。

解决方法:

  • 方案一:修改模型字段为下划线命名(符合Django惯例):
    birth_date = models.DateField(null=True, blank=True)
    document_number = models.CharField(max_length=100, null=True, blank=True)
    expiry_date = models.DateField(null=True, blank=True)
    
  • 方案二:视图创建对象时使用模型的驼峰字段名:
    mrz = MRZ.objects.create(
        FK_compte_ccp=compte_ccp,
        photo_passport=photo_relative_path,
        documentNumber=document_number,
        birthDate=birth_date,
        expiryDate=expiry_date
    )
    

2. ImageField赋值错误

模型中photo_passport是ImageField,需传入相对MEDIA_ROOT的路径或UploadedFile对象,视图中传入的本地绝对路径filepath会导致Django无法正确处理文件存储,触发字段验证错误。

解决方法:
直接使用上传的文件对象(推荐),或构造相对路径:

# 直接传入UploadedFile对象
mrz = MRZ.objects.create(
    FK_compte_ccp=compte_ccp,
    photo_passport=image_file,
    documentNumber=document_number,
    birthDate=birth_date,
    expiryDate=expiry_date
)

如果需要自定义存储路径,可修改模型的upload_to为动态路径:

def user_mrz_path(instance, filename):
    return f'{instance.FK_compte_ccp.FK_compte_app.id}/MRZ.jpg'

class MRZ(models.Model):
    # ...其他字段
    photo_passport = models.ImageField(upload_to=user_mrz_path)

3. 查看具体异常信息

当前视图的全局异常捕获仅返回错误信息,但未打印具体内容。建议在except Exception as e块中添加打印语句,快速定位错误点:

except Exception as e:
    print("Erreur détaillée :", str(e))
    return JsonResponse({'message': str(e)}, status=400)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 19:47:07