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

Django订单取消表单提交未触发create_cancel视图

Django订单取消表单提交未触发create_cancel视图

我正在Django应用里开发订单取消功能,流程是用cancel_order视图渲染取消表单页面cancel-order.html,提交表单后由create_cancel视图处理更新CartOrder和CartOrderItems的product_status字段。但现在遇到个问题——表单提交后create_cancel视图根本没被触发,既没显示成功/错误提示,数据库里的订单状态也没更新。

相关视图代码

def cancel_order(request, oid):
    sub_category = SubCategory.objects.all()
    categories = Category.objects.prefetch_related('subcategories').order_by('?')[:4]
    wishlist = wishlist_model.objects.filter(user=request.user) if request.user.is_authenticated else None
    nav_category = Category.objects.filter(special_category=True).prefetch_related('subcategories').order_by('?')[:4]
    order = CartOrder.objects.get(user=request.user, id=oid)
    products = CartOrderItems.objects.filter(order=order)

    # Calculate discounts for each product
    total_old_price = 0
    total_price = 0

    for item in products:
        product = item.product  # Assuming a ForeignKey from CartOrderItems to Product
        qty = item.qty  # Assuming a quantity field in CartOrderItems
        total_old_price += (product.old_price or 0) * qty
        total_price += (product.price or 0) * qty

    # Calculate total discount percentage
    if total_old_price > 0:  # Prevent division by zero
        discount_percentage = ((total_old_price - total_price) / total_old_price) * 100
    else:
        discount_percentage = 0

    context = {
        "order": order,
        "products": products,
        "sub_category": sub_category,
        "categories": categories,
        "wishlist": wishlist,
        "nav_category": nav_category,
        "discount_percentage": round(discount_percentage, 2),  # Round to 2 decimal places
    }

    return render(request, 'core/cancel-order.html', context)


def create_cancel(request, oid):
    if request.method == "POST":
        user = request.user

        # Fetch POST data
        reason = request.POST.get('reason')
        description = request.POST.get('description')

        try:
            # Fetch the CartOrder instance
            order_cancel = get_object_or_404(CartOrder, id=oid, user=user)
            order_cancel.product_status = "cancelled"
            order_cancel.save()

            # Fetch related CartOrderItems instances
            order_items = CartOrderItems.objects.filter(order=order_cancel)
            for item in order_items:
                item.product_status = "cancelled"
                item.save()

            # Log the reason and description (if you want to save this somewhere)
            # Example: save to a cancellation model (optional)
            # CancellationReason.objects.create(order=order_cancel, reason=reason, description=description)

            messages.success(request, "Order successfully cancelled.")

        except Exception as e:
            messages.error(request, f"An error occurred: {e}")

        return redirect("core:dashboard")
    else:
        messages.error(request, "Invalid request method.")
        return redirect("core:dashboard")

模板代码(cancel-order.html)

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="shortcut icon" href="{% static './assets/images/logo/favicon.ico'  %}" type="image/x-icon">
    <title>Cancel Order</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: Arial, sans-serif;
        }

        body {
            background-color: #f8f9fa;
            display: flex;
            justify-content: center;
            align-items: center;
            align-items: flex-start; /* Align items at the top to allow vertical scrolling */
            min-height: 100vh;/* Ensure the body covers the viewport */
            padding: 20px;
        }

        .cancel-order-container {
            display: flex;
            align-items: flex-start;
            gap: 20px;
            background: #ffffff;
            width: 100%;
            max-width: 800px;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }

        .cancel-order-container img {
            max-width: 150px;
            height: auto;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }

        .cancel-order-form {
            flex: 1;
        }

        .cancel-order-form h2 {
            margin-bottom: 20px;
            color: #343a40;
        }

        .form-group {
            margin-bottom: 15px;
        }

        .form-group label {
            display: block;
            margin-bottom: 5px;
            color: #495057;
            font-weight: bold;
        }

        .form-group input, .form-group select, .form-group textarea {
            width: 100%;
            padding: 10px;
            border: 1px solid #ced4da;
            border-radius: 4px;
            font-size: 16px;
        }

        .form-group textarea {
            resize: vertical;
            min-height: 100px;
        }

        .form-actions {
            text-align: right;
        }

        .btn {
            display: inline-block;
            padding: 10px 20px;
            font-size: 16px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            transition: background-color 0.3s ease;
        }

        .btn-cancel {
            background-color: #dc3545;
            color: #ffffff;
        }

        .btn-cancel:hover {
            background-color: #c82333;
        }

        .btn-back {
            background-color: #6c757d;
            color: #ffffff;
            margin-right: 10px;
        }

        .btn-back:hover {
            background-color: #5a6268;
        }

        .modal {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            justify-content: center;
            align-items: center;
            z-index: 1000;
        }

        .modal-content {
            background: #ffffff;
            padding: 20px;
            border-radius: 8px;
            text-align: center;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
        }

        .modal-content p {
            margin-bottom: 20px;
            font-size: 18px;
            color: #343a40;
        }

        .modal-buttons {
            display: flex;
            justify-content: center;
            gap: 10px;
        }

        @media (max-width: 576px) {
            .cancel-order-container {
                flex-direction: column;
                align-items: center;
            }

            .cancel-order-container img {
                max-width: 100%;
                margin-bottom: 20px;
            }

            .cancel-order-form {
                width: 100%;
            }

            .btn {
                width: 100%;
                margin-bottom: 10px;
            }

            .btn-back {
                margin-right: 0;
            }

            .form-actions {
                display: flex;
                flex-direction: column;
            }
        }
    </style>
    <script>
        function showConfirmationModal(event) {
            event.preventDefault();
            const modal = document.getElementById('confirmation-modal');
            modal.style.display = 'flex';
        }

        function hideModal() {
            const modal = document.getElementById('confirmation-modal');
            modal.style.display = 'none';
        }

        function confirmAndSubmit() {
            document.querySelector('.cancel-order-form').submit();
        }
    </script>
</head>
<body>
    <div class="cancel-order-container">
        <img src="{{order.images}}" alt="Product Image">
        <form class="cancel-order-form" action="{% url 'core:create_cancel' oid=order.id %}" enctype="multipart/form-data" onsubmit="showConfirmationModal(event)" method="POST">
            {% csrf_token %}
            <h2>Cancel Your Order</h2>
            <div class="form-group">
                <label for="order-number">Order Number</label>
                <input type="text" id="order-number" name="order-number" value="{{order.oid}}" readonly>
            </div>
            <div class="form-group">
                <label for="product-name">Product Name</label>
                <input type="text" id="product-name" name="product-name" value="{{order.title}}" readonly>
            </div>
            <div class="form-group">
                <label for="product-price">Product Price</label>
                <input type="text" id="product-price" name="product-price" value="{{order.total}}" readonly>
            </div>
            <div class="form-group">
                <label for="reason">Cancellation Reason</label>
                <select id="reason" name="reason" required>
                    <option value="">Select a reason</option>
                    <option value="wrong_item">Ordered the wrong item</option>
                    <option value="late_delivery">Late delivery</option>
                    <option value="changed_mind">Changed my mind</option>
                    <option value="damaged_item">Damaged item</option>
                    <option value="other">Other</option>
                </select>
            </div>
            <div class="form-group">
                <label for="description">Additional Description (Optional)</label>
                <textarea id="description" name="description" placeholder="Enter any additional details..."></textarea>
            </div>
            <div class="form-actions">
                <a href="{% url 'core:dashboard' %}" class="btn btn-back">Back to Dashboard</a>
                <button type="submit" class="btn btn-cancel">Cancel Order</button>
            </div>
        </form>
    </div>

    <!-- Confirmation Modal -->
    <div id="confirmation-modal" class="modal">
        <div class="modal-content">
            <p>Are you sure you want to cancel this order?</p>
            <div class="modal-buttons">
                <button class="btn btn-cancel" onclick="confirmAndSubmit()">Yes, Cancel Order</button>
                <button class="btn btn-back" onclick="hideModal()">No, Keep Order</button>
            </div>
        </div>
    </div>
</body>
</html>

问题排查与解决思路

我帮你梳理几个最可能导致视图没触发的关键点,你可以逐一检查:

1. 模态框确认按钮的绑定问题

这大概率是核心问题!你的表单用onsubmit="showConfirmationModal(event)"阻止了默认提交,然后依赖confirmAndSubmit()函数手动提交表单。要确认模态框里的确认按钮是否正确绑定了这个函数——如果按钮没加onclick="confirmAndSubmit()",点击后只会隐藏模态框,根本不会提交表单,自然触发不了create_cancel视图。

2. URL路由配置是否正确

检查core应用下的urls.py是否正确配置了create_cancel的路由,并且命名空间匹配:

from django.urls import path
from . import views

app_name = 'core'

urlpatterns = [
    # 其他路由...
    path('cancel-order/<int:oid>/', views.cancel_order, name='cancel_order'),
    path('create-cancel/<int:oid>/', views.create_cancel, name='create_cancel'),
]

可以查看页面源码里form的action属性,确认URL是否正确生成。

3. 浏览器开发者工具排查请求状态

打开浏览器开发者工具(F12),切换到Network标签:

  • 点击提交按钮后,确认是否有POST请求发送到create_cancel的URL;
  • 如果请求状态是403,说明CSRF令牌验证失败——检查模板里的{% csrf_token %}是否正确渲染(查看页面源码,确认存在<input type="hidden" name="csrfmiddlewaretoken" value="xxx">);
  • 如果没有任何请求发送,切换到Console标签查看是否有JS报错。

4. 订单ID传递是否有效

在模板里临时添加{{ order.id }}打印订单ID,确保它不是空值或错误数值,否则URL会生成错误,导致请求无法到达视图。

备注:内容来源于stack exchange,提问作者Google User

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 17:59:36