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

Django Oscar中重写ShippingMethodView的get()方法失效问题排查

Django Oscar重写ShippingMethodView的get()方法未生效问题

问题描述

已成功重写Django Oscar的ShippingMethodView类,但重写的get()方法未生效。需求背景:当仅存在1种配送方式时,系统默认跳转到支付页面,需强制展示配送方式页面,让客户查看配送费用后再进入支付环节。

相关代码如下:

apps.py

import oscar.apps.checkout.apps as apps
from oscar.core.loading import get_class
from django.urls import path

class CheckoutConfig(apps.CheckoutConfig):
    name = 'apps.checkout'
    
    def ready(self):
        self.shipping_method_view = get_class('checkout.views', 'ShippingMethodViewOverwritten')
        super().ready()

    def get_urls(self):
        urls = super(CheckoutConfig, self).get_urls()
        urls += [
            path('shipping-method/',
                self.shipping_method_view.as_view(), name='shipping-method'),
        ]
        return urls

views.py

from oscar.apps.checkout import views
from oscar.core.loading import get_class
ShippingAddressForm, ShippingMethodForm, GatewayForm \
    = get_classes('checkout.forms', ['ShippingAddressForm', 'ShippingMethodForm', 'GatewayForm'])
from django.contrib import messages
Repository = get_class('shipping.repository', 'Repository')

class ShippingMethodViewOverwritten(views.ShippingMethodView):
    template_name = 'oscar/checkout/shipping_methods.html'
    form_class = ShippingMethodForm
    pre_conditions = ['check_basket_is_not_empty',
                      'check_basket_is_valid',
                      'check_user_email_is_captured']
    success_url = reverse_lazy('checkout:payment-method')

    def get(self, request, *args, **kwargs):

        if not request.basket.is_shipping_required():
            self.checkout_session.use_shipping_method(
                NoShippingRequired().code)
            return self.get_success_response()

        if not self.checkout_session.is_shipping_address_set():
            messages.error(request, _("Please choose a shipping address"))
            return redirect('checkout:shipping-address')

        self._methods = self.get_available_shipping_methods()
        if len(self._methods) == 0:
            # No shipping methods available for given address
            messages.warning(request, _(
                "Shipping is unavailable for your chosen address - please "
                "choose another"))
            return redirect('checkout:shipping-address')
        elif len(self._methods) == 1:
            # Only one shipping method - set this and redirect onto the next
            # step
            self.checkout_session.use_shipping_method(self._methods[0].code)
            return self.get_success_response()

        return super().get(request, *args, **kwargs)

    def get_available_shipping_methods(self):
        return Repository().get_shipping_methods(basket=self.request.basket, 
        user=self.request.user,shipping_addr=self.get_shipping_address(self.request.basket), 
        request=self.request)

问题原因及解决方案

1. apps.py配置错误

错误点:

  • ready方法执行顺序颠倒:先获取自定义视图再调用父类ready(),但Oscar的ready()会初始化核心加载逻辑,未执行父类方法就调用get_class可能导致视图加载异常。
  • URL追加顺序错误:自定义路由被追加到原有URL列表末尾,而Oscar默认已经注册了shipping-method路由,原有路由会优先匹配,导致自定义视图无法触发。

修正后的apps.py:

import oscar.apps.checkout.apps as apps
from oscar.core.loading import get_class
from django.urls import path

class CheckoutConfig(apps.CheckoutConfig):
    name = 'apps.checkout'
    
    def ready(self):
        # 先执行父类ready方法,初始化核心加载逻辑
        super().ready()
        self.shipping_method_view = get_class('checkout.views', 'ShippingMethodViewOverwritten')

    def get_urls(self):
        urls = super(CheckoutConfig, self).get_urls()
        # 将自定义路由插入到原有URL列表前面,确保优先匹配
        custom_urls = [
            path('shipping-method/',
                self.shipping_method_view.as_view(), name='shipping-method'),
        ]
        return custom_urls + urls

2. views.py逻辑错误及缺失导入

错误点:

  • 核心逻辑矛盾:重写的get()方法中,当只有1种配送方式时仍执行跳转支付页面的逻辑,和需求完全相反。
  • 缺失必要导入:代码中使用了NoShippingRequired但未导入,会导致运行时错误。

修正后的views.py:

from oscar.apps.checkout import views
from oscar.core.loading import get_class, get_classes
from django.contrib import messages
from django.urls import reverse_lazy
# 补充导入NoShippingRequired
NoShippingRequired = get_class('shipping.methods', 'NoShippingRequired')

ShippingAddressForm, ShippingMethodForm, GatewayForm \
    = get_classes('checkout.forms', ['ShippingAddressForm', 'ShippingMethodForm', 'GatewayForm'])
Repository = get_class('shipping.repository', 'Repository')

class ShippingMethodViewOverwritten(views.ShippingMethodView):
    template_name = 'oscar/checkout/shipping_methods.html'
    form_class = ShippingMethodForm
    pre_conditions = ['check_basket_is_not_empty',
                      'check_basket_is_valid',
                      'check_user_email_is_captured']
    success_url = reverse_lazy('checkout:payment-method')

    def get(self, request, *args, **kwargs):

        if not request.basket.is_shipping_required():
            self.checkout_session.use_shipping_method(
                NoShippingRequired().code)
            return self.get_success_response()

        if not self.checkout_session.is_shipping_address_set():
            messages.error(request, _("Please choose a shipping address"))
            return redirect('checkout:shipping-address')

        self._methods = self.get_available_shipping_methods()
        if len(self._methods) == 0:
            messages.warning(request, _(
                "Shipping is unavailable for your chosen address - please "
                "choose another"))
            return redirect('checkout:shipping-address')
        # 删除原有跳转逻辑,强制渲染配送方式页面
        # elif len(self._methods) == 1:
        #     self.checkout_session.use_shipping_method(self._methods[0].code)
        #     return self.get_success_response()

        return super().get(request, *args, **kwargs)

    def get_available_shipping_methods(self):
        return Repository().get_shipping_methods(
            basket=self.request.basket, 
            user=self.request.user,
            shipping_addr=self.get_shipping_address(self.request.basket), 
            request=self.request
        )

内容的提问来源于stack exchange,提问作者César Augusto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 16:17:04