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

如何在Django views.py中触发模态弹窗判断运单记录是否存在?

Django实现运单ID存在性校验与模态弹窗确认流程

需求概述

用户在运单表单的第一个字段输入shpid后,系统需自动校验该运单是否存在:

  • 若不存在,用户可继续填写剩余表单完成新增
  • 若存在,弹出确认弹窗,用户确认后切换为更新表单并加载已有运单数据

1. 前端实现实时校验与模态弹窗

在tracker/add_shipment.html模板中添加模态框结构,并通过JavaScript监听shpid输入事件,发起AJAX请求校验运单存在性:

<!-- 运单存在确认模态框 -->
<div class="modal fade" id="shipmentExistsModal" tabindex="-1" aria-labelledby="shipmentExistsModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="shipmentExistsModalLabel">运单已存在</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">
        该运单ID已存在,是否切换为更新模式?
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
        <button type="button" class="btn btn-primary" id="confirmUpdate">确认更新</button>
      </div>
    </div>
  </div>
</div>

<!-- 原有表单渲染 -->
{{ form|crispy }}

<script>
document.addEventListener('DOMContentLoaded', function() {
  const shpidInput = document.querySelector('#id_shpid');
  const modal = new bootstrap.Modal(document.getElementById('shipmentExistsModal'));
  let existingShipmentData = null;

  // 监听shpid输入框失焦事件,发起存在性校验
  shpidInput.addEventListener('blur', function() {
    const shpid = this.value.trim();
    if (!shpid) return;

    fetch(`/check-shipment-exists/?shpid=${shpid}`)
      .then(response => response.json())
      .then(data => {
        if (data.exists) {
          existingShipmentData = data.shipment;
          modal.show();
        }
      });
  });

  // 确认更新:填充表单数据并切换为更新模式
  document.getElementById('confirmUpdate').addEventListener('click', function() {
    if (!existingShipmentData) return;

    // 遍历填充所有字段
    Object.keys(existingShipmentData).forEach(key => {
      const field = document.querySelector(`#id_${key}`);
      if (field) {
        if (field.type === 'date') {
          field.value = existingShipmentData[key] ? existingShipmentData[key].split('T')[0] : '';
        } else {
          field.value = existingShipmentData[key];
        }
      }
    });

    // 设置shpid为只读
    shpidInput.setAttribute('readonly', true);
    shpidInput.style.backgroundColor = 'gainsboro';

    // 修改提交按钮文本
    const submitBtn = document.querySelector('button[type="submit"]');
    if (submitBtn) submitBtn.textContent = 'Update Shipment';

    modal.hide();
  });
});
</script>

2. 后端新增运单存在性校验API

在views.py中新增视图函数,处理前端的校验请求,返回JSON格式结果:

from django.http import JsonResponse
from .models import Shipment
from django.views.decorators.http import require_GET

@require_GET
def check_shipment_exists(request):
    shpid = request.GET.get('shpid', '')
    if not shpid:
        return JsonResponse({'exists': False})
    
    try:
        shipment = Shipment.objects.get(shpid=shpid)
        # 序列化运单数据为JSON格式
        shipment_data = {
            'shpid': shipment.shpid,
            'awb': shipment.awb,
            'pod': shipment.pod,
            'coldate': shipment.coldate.isoformat() if shipment.coldate else None,
            'deldate': shipment.deldate.isoformat() if shipment.deldate else None,
            'recipient': shipment.recipient,
            'status': shipment.status,
            'sts_date': shipment.sts_date.isoformat() if shipment.sts_date else None,
            'costs': str(shipment.costs)
        }
        return JsonResponse({'exists': True, 'shipment': shipment_data})
    except Shipment.DoesNotExist:
        return JsonResponse({'exists': False})

在urls.py中添加对应路由:

from django.urls import path
from . import views

urlpatterns = [
    # 原有运单添加/更新路由
    path('add-shipment/<int:pk>/<str:orderid>/', views.add_shipment, name='add_shipment'),
    # 新增运单存在性校验路由
    path('check-shipment-exists/', views.check_shipment_exists, name='check_shipment_exists'),
]

3. 调整原有视图逻辑

修改add_shipment视图,支持新增和更新两种场景,处理用户确认更新后的表单提交:

from .forms import AddShpForm, UpdateShpForm
from django.contrib import messages
from django.shortcuts import redirect, render, get_object_or_404

def add_shipment(request, pk, orderid):
    order = get_object_or_404(Order, pk=pk)
    
    if request.method == 'POST':
        shpid = request.POST.get('shpid')
        try:
            # 运单存在,使用更新表单处理
            shipment = Shipment.objects.get(shpid=shpid)
            form = UpdateShpForm(request.POST, instance=shipment)
            if form.is_valid():
                form.save()
                order.shipment = shipment
                order.save()
                messages.success(request, f'Shipment: {shpid} - updated and attached to Order: {order.orderid}')
                return redirect('tracker:list_orders', 'open')
        except Shipment.DoesNotExist:
            # 运单不存在,使用新增表单处理
            form = AddShpForm(request.POST)
            if form.is_valid():
                shipment = form.save()
                order.shipment = shipment
                order.save()
                messages.success(request, f'Shipment: {shpid} - saved and attached to Order: {order.orderid}')
                return redirect('tracker:list_orders', 'open')
        
        # 表单验证失败,返回当前表单
        return render(request, 'tracker/add_shipment.html', {'form': form})
    else:
        # GET请求默认返回新增表单
        form = AddShpForm()
        return render(request, 'tracker/add_shipment.html', {'form': form})

4. 完善UpdateShpForm定义

确保UpdateShpForm正确继承并设置shpid为只读:

from django.forms import ModelForm, TextInput, DateInput
from .models import Shipment
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Row, Column, Field, ButtonHolder, Submit

class UpdateShpForm(ModelForm):
    class Meta:
        model = Shipment
        fields = '__all__'
        widgets = {
            "shpid": TextInput(attrs={'readonly': True, 'style': 'max-width:120px; background-color:gainsboro'}),
            "costs": TextInput(attrs={'style': 'max-width:200px'}),
            "coldate": DateInput(attrs={'type': 'date', 'style': 'max-width:180px'}),
            "deldate": DateInput(attrs={'type': 'date', 'style': 'max-width:180px'}),
            "sts_date": DateInput(attrs={'type': 'date', 'style': 'max-width:180px'}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 统一字段标签和布局
        self.fields['shpid'].label = "Shipment ID"
        self.fields['awb'].label = "AWB"
        self.fields['pod'].label = "POD"
        self.fields['coldate'].label = "Collection Date"
        self.fields['deldate'].label = "Delivery Date"
        self.fields['recipient'].label = "Recipient"
        self.fields['status'].label = "Status"
        self.fields['sts_date'].label = "Status Date"
        self.fields['costs'].label = "Costs"

        self.helper = FormHelper()
        self.form_method = 'post'
        self.helper.layout = Layout(
            Row (
                Column('shpid', css_class='form-group col-md-2 mb-0 pe-4'),
                Column('status', css_class='form-group col-md-4 mb-0 ps-2 pe-2'),
                Column('sts_date', css_class='form-group col-md-4 mb-0 ps-4'),
            ),
            Row(
                Column('awb', css_class='form-group col-md-6 mb-0 pe-4'),
                Column('pod', css_class='form-group col-md-6 mb-0 pe-4'),
            ),
            Row(
                Column('coldate', css_class='form-group col-md-3 mb-0 pe-4'),
                Column('deldate', css_class='form-group col-md-3 mb-0 ps-2 pe-2'),
                Column('recipient', css_class='form-group col-md-6 mb-0 ps-4 pe-4'),
            ),
            Field('costs'),
            ButtonHolder(
                Submit('submit', 'Update Shipment', css_class='ml-n2 btn-lg fw-bolder'),
                css_class='center'
            )
        )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 21:19:55