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

Django嵌套函数功能正常但验证器触发时同时显示错误与成功消息问题

问题根源分析

你遇到的问题核心在于:工具函数add_flight_function中的重定向操作并不会终止视图函数add_new_flight的执行流程。当验证失败时,工具函数虽然添加了错误消息并重定向,但它只是自己返回了一个HttpResponseRedirect对象,而视图函数里调用add_flight_function()后,并没有处理这个返回值,而是直接继续执行messages.success(...),然后又发起了一次重定向。这就导致两个消息(错误+成功)都被添加到了消息队列中,最终在页面上一起显示。

而且工具函数里的一些数据库操作(比如FunctionType.objects.get)如果出错,会直接抛出异常,被视图里的except捕获,添加"Failed to Add New Flight"的错误消息,但这和验证器的错误消息是不同场景的问题,需要区分处理。

解决方案

我们需要让工具函数向视图函数反馈执行结果,然后由视图函数来决定后续的消息添加和重定向逻辑。具体修改如下:

1. 修改utils.py中的add_flight_function

让函数返回一个布尔值,表示航班是否成功添加;同时,把验证失败时的重定向逻辑移到视图函数中,工具函数只负责业务逻辑和错误消息的添加:

def add_flight_function(request):
    try:
        aircraft_maintenance_type = AircraftMaintenanceType.objects.first()
    except:
        aircraft_maintenance_type = None
    aircraft = request.POST.get('aircraft')
    adep = request.POST.get('adep')
    ades = request.POST.get('ades')
    date = request.POST.get('date')
    atd = request.POST.get('atd')
    ata = request.POST.get('ata')
    function_type_id = request.POST.get('function_type')
    
    # 处理FunctionType获取异常,避免直接抛出
    try:
        function_type_obj = FunctionType.objects.get(id=function_type_id)
    except FunctionType.DoesNotExist:
        messages.error(request, "Invalid function type selected")
        return False
    
    operational_condition = request.POST.get('operational_condition')
    student = request.POST.get('student')
    instructor = request.POST.get('instructor')
    night = request.POST.get('night')
    note = request.POST.get('note')
    
    # 处理Aircraft获取异常
    try:
        aircraft_obj = Aircraft.objects.get(id=aircraft)
        aircraft_type = aircraft_obj.aircraft_type.abbreviation
    except Aircraft.DoesNotExist:
        messages.error(request, "Invalid aircraft selected")
        return False

    # 转速表验证逻辑
    if aircraft_maintenance_type and aircraft_maintenance_type.is_tacho:
        atd_tacho = request.POST.get('atd_tacho')
        ata_tacho = request.POST.get('ata_tacho')
        if not atd_tacho or not ata_tacho:
            messages.error(request, "Tacho values are required")
            return False
        try:
            if float(ata_tacho) <= float(atd_tacho):
                messages.error(request, "ATA Tacho cannot be lower than ATD Tacho")
                return False
        except ValueError:
            messages.error(request, "Tacho values must be numbers")
            return False
    
    # 通用航班验证
    is_valid_flight, error_message = flight_validator(request, ata, atd, function_type_obj.name, instructor)
    if not is_valid_flight:
        messages.error(request, error_message)
        return False

    # 开始创建航班记录
    try:
        log_entry = LogEntry.objects.create(
            aircraft_id=aircraft, 
            adep_id=adep, 
            ades_id=ades, 
            date=date, 
            atd=atd, 
            ata=ata, 
            function_type_id=function_type_obj.id, 
            student_id=student, 
            instructor_id=instructor, 
            operational_condition_id=operational_condition, 
            note=note
        )
        if night == 'on':
            log_entry.night_flight = True
        if function_type_obj.name == 'Single Pilot':
            log_entry.solo_flight = True
        if aircraft_type == 'SIM':
            log_entry.sim_flight = True
        elif aircraft_type == 'MEP':
            log_entry.mep_flight = True
        log_entry.save()

        # 维护时间记录逻辑
        if not aircraft_maintenance_type or not aircraft_maintenance_type.is_tacho:
            try:
                ata_obj = parse(ata)
                atd_obj = parse(atd)
                if (ata_obj - atd_obj).total_seconds() > 600:  # 10分钟=600秒
                    maintenance_eet = (ata_obj - atd_obj) - timedelta(minutes=10)
                else:
                    maintenance_eet = ata_obj - atd_obj
                AircraftFlightTime.objects.create(
                    aircraft_id=aircraft, 
                    log_entry=log_entry, 
                    maintenance_eet=maintenance_eet
                )
            except Exception as e:
                messages.error(request, f"Error calculating maintenance time: {str(e)}")
                log_entry.delete()  # 回滚已创建的日志
                return False
        else:
            try:
                ata_obj = float(ata_tacho)
                atd_obj = float(atd_tacho)
                maint_eet_obj = (ata_obj - atd_obj) * 60
                maintenance_eet = timedelta(minutes=maint_eet_obj)
                AircraftFlightTime.objects.create(
                    aircraft_id=aircraft, 
                    log_entry=log_entry, 
                    maintenance_eet=maintenance_eet, 
                    atd_tacho=atd_tacho, 
                    ata_tacho=ata_tacho
                )
            except ValueError:
                messages.error(request, "Invalid tacho values for maintenance")
                log_entry.delete()
                return False
    except Exception as e:
        messages.error(request, f"Error saving flight data: {str(e)}")
        return False

    return True

2. 修改views.py中的add_new_flight视图

根据工具函数的返回值来决定添加成功还是错误消息,并统一处理重定向:

def add_new_flight(request):
    aircrafts = Aircraft.objects.all()
    aerodromes = Aerodrome.objects.filter(is_base=False)
    base_aerodrome = Aerodrome.objects.get(is_base=True)
    function_type = FunctionType.objects.all()
    students = Student.objects.filter(is_active=True).order_by('last_name')
    instructors = Instructor.objects.filter(is_active=True).order_by('last_name')
    operational_conditions = OperationalCondition.objects.all()
    today = dt.today().date()
    try:
        aircraft_maintenance_type = AircraftMaintenanceType.objects.first()
    except:
        aircraft_maintenance_type = None
    context = {
        'aircrafts': aircrafts,
        'aerodromes': aerodromes,
        'function_type': function_type,
        'students': students,
        'instructors': instructors,
        'today': today,
        'operational_conditions': operational_conditions,
        'base_aerodrome': base_aerodrome,
        'aircraft_maintenance_type': aircraft_maintenance_type,
    }
    if request.method == 'POST':
        success = add_flight_function(request)
        if success:
            messages.success(request, "New Flight Inserted Successfully")
            return HttpResponseRedirect(reverse('flight:flight_list'))
        else:
            # 工具函数已经添加了具体的错误消息,这里不需要再添加通用错误
            return HttpResponseRedirect(request.META.get('HTTP_REFERER') or reverse('flight:add_new_flight'))
    return render(request, 'flight/add_new_flight.html', context)

关键修改点说明

  • 工具函数返回执行状态:通过返回True/False,让视图函数明确知道航班是否成功添加,避免了之前不管结果都添加成功消息的问题。
  • 异常本地化处理:在工具函数中处理数据库查询、数据转换的异常,返回具体的错误消息,而不是让异常冒泡到视图的通用except块,这样错误提示更精准。
  • 移除工具函数中的重定向:把重定向逻辑统一交给视图函数处理,避免多次重定向导致的消息队列混乱。
  • 数据回滚:在创建日志记录后,如果后续的维护时间记录保存失败,会删除已创建的日志,保证数据一致性。

这样修改后,当验证失败时,只会显示对应的错误消息,不会再出现成功消息;只有当所有流程都执行成功时,才会显示成功提示并跳转到航班列表页。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 01:07:47