django - --View 处的 ValueError 未返回 HttpResponse 对象。它返回 None 而不是
问题描述
提交表单时出现此错误。
/en/checkout/ 处的 ValueError 视图 core.views.EnCheckoutView 未返回 HttpResponse 对象。它返回 None 代替。
我仔细检查了views.py
有时删除数据库文件(db.sqlite3)后:它使用相同的views.py和html模板正常工作,但重新启动计算机后,同样的错误再次出现。
这是它的views.py
class EnCheckoutView(View):
def get(self, *args, **kwargs):
try:
order = Order.objects.get(user=self.request.user, ordered=False)
form = CheckoutForm()
context = {
'form': form,
'couponform': CouponForm(),
'order': order,
'DISPLAY_COUPON_FORM': True
}
shipping_address_qs = Address.objects.filter(user=self.request.user, address_type='S', default=True)
if shipping_address_qs.exists():
context.update({
'default_shipping_address': shipping_address_qs[0]
})
billing_address_qs = Address.objects.filter(user=self.request.user, address_type='B', default=True)
if billing_address_qs.exists():
context.update({
'default_billing_address': billing_address_qs[0]
})
return render(self.request, 'en-checkout-page.html', context)
except ObjectDoesNotExist:
messages.info(self.request, 'You do not have an active order.')
return redirect('core:en-checkout')
def post(self, *args, **kwargs):
form = CheckoutForm(self.request.POST or None)
try:
order = Order.objects.get(user=self.request.user, ordered=False)
if form.is_valid():
use_default_shipping = form.cleaned_data.get("use_default_shipping")
if use_default_shipping:
print('Using the default shipping address')
address_qs = Address.objects.filter(user=self.request.user, address_type='S', customer_name=customer_name, phone=phone, email=email, default=True)
if address_qs.exists():
shipping_address = address_qs[0]
order.shipping_address = shipping_address
order.save()
else:
messages.info(self.request, 'No default shipping address available')
return redirect('core:en-checkout')
else:
print('User is entering a new shipping address')
customer_name = form.cleaned_data.get('customer_name')
phone = form.cleaned_data.get('phone')
email = form.cleaned_data.get('email')
shipping_address1 = form.cleaned_data.get('shipping_address')
shipping_address2 = form.cleaned_data.get('shipping_address2')
shipping_country = form.cleaned_data.get('shipping_country')
shipping_zip = form.cleaned_data.get("shipping_zip")
if is_valid_form([shipping_address1, shipping_country, shipping_zip]):
shipping_address = Address(
user=self.request.user,
customer_name=customer_name,
phone=phone,
email=email,
street_address=shipping_address1,
apartment_address=shipping_address2,
country=shipping_country,
zip=shipping_zip,
address_type='S'
)
shipping_address.save()
order.shipping_address = shipping_address
order.save()
set_default_shipping = form.cleaned_data.get('set_default_shipping')
if set_default_shipping:
shipping_address.default = True
shipping_address.save()
else:
messages.info(self.request, 'Please fill in the required shipping address fields')
use_default_billing = form.cleaned_data.get('use_default_billing')
same_billing_address = form.cleaned_data.get('same_billing_address')
if same_billing_address:
billing_address = shipping_address
billing_address.pk = None
billing_address.save()
billing_address.address_type = 'B'
billing_address.save()
order.billing_address = billing_address
order.save()
elif use_default_billing:
print('Using the default billing address')
address_qs = Address.objects.filter(
user=self.request.user,
address_type='B',
default=True
)
if address_qs.exists():
billing_address = address_qs[0]
order.billing_address = billing_address
order.save()
else:
messages.info(self.request, 'No default billing address')
return redirect('core:checkout')
else:
print('User is entering a new billing address')
billing_address1 = form.cleaned_data.get('billing_address')
billing_address2 = form.cleaned_data.get('billing_address2')
billing_country = form.cleaned_data.get('billing_country')
billing_zip = form.cleaned_data.get('billing_zip')
if is_valid_form([billing_address1, billing_country, billing_zip]):
billing_address = Address(
user=self.request.user,
street_address=billing_address1,
apartment_address=billing_address2,
country=billing_country,
zip=billing_zip,
address_type='B'
)
billing_address.save()
order.billing_address = billing_address
order.save()
set_default_billing = form.cleaned_data.get('set_default_billing')
if set_default_billing:
billing_address.default = True
billing_address.save()
else:
messages.info(self.request, 'Please fill in the required billing address fields')
payment_option = form.cleaned_data.get('payment_option')
if payment_option == 'S':
return redirect('core:payment', payment_option='stripe')
elif payment_option == 'P':
return redirect('core:payment', payment_option='paypal')
else:
messages.warning(self.request, 'Invalid payment option selected')
return redirect('core:checkout')
except ObjectDoesNotExist:
messages.warning(self.request, 'You do not have an active order')
return redirect('core:en-order-summary')
我很感激任何帮助!
解决方案
您的方法中有太多代码post()
- 您应该将所有逻辑提取到表单的保存方法中,使用适当的表单验证(尽可能使用模型表单),并将其拆分为简单、可读和可测试的方法。
话虽这么说,只要您提取下所有代码,您的问题就很明显了if form.is_valid()
- 没有else
分支。因此,如果您的表单未通过验证,则该函数确实会返回None
。
编辑
我将在 except.... 之前添加 else ,对吗?
你必须将它添加到与if form.is_valid()
- 现在它最终出现在这盘意大利面中的位置,这超出了我的阅读能力,老实说:-/
作为一般规则,请考虑如果函数中有超过 20 行和 2 级缩进,那么可能是时候重构代码了。第一个明显的重构是移动事物以减少缩进级别。在您的情况下,您已经可以通过将except
子句移动到唯一有意义的位置之后开始:
def post(self, *args, **kwargs):
try:
order = Order.objects.get(user=self.request.user, ordered=False)
except Order.DoesNotExist:
messages.warning(self.request, 'You do not have an active order')
return redirect('core:en-order-summary')
form = CheckoutForm(self.request.POST or None)
if form.is_valid():
# etc....
您已经获得了一级缩进(并将您的 try 块减少到严格的最小值,因此如果它出现在您正在调用的某些代码中,它将无法捕获另一个意外的 DoesNotExist 异常)。
然后正确使用表单验证 - 例如:
if address_qs.exists():
shipping_address = address_qs[0]
order.shipping_address = shipping_address
order.save()
else:
messages.info(self.request, 'No default shipping address available')
return redirect('core:en-checkout')
这对您的用户来说是完全错误的并且非常粗鲁,他们将不得不再次重新输入所有内容。表单本身应该验证这一点。事实上,如果用户还没有默认送货地址,它甚至不应该显示“使用默认送货”选项。
实际上,您的视图代码应该看起来像:
def post(self, *args, **kwargs):
try:
order = Order.objects.get(user=self.request.user, ordered=False)
except Order.DoesNotExist:
messages.warning(self.request, 'You do not have an active order')
return redirect('core:en-order-summary')
form = CheckoutForm(self.request.POST, order=order)
if form.is_valid():
form.save()
# this is supposed to has been validated by the form too
payment_option = form.get_payment_option()
return redirect('core:payment', payment_option=payment_option)
# factor out all the common code creating the context
# for both get and post in a get_context_data method
context = self.get_context_data()
context["form"] = form
return render(self.request, 'en-checkout-page.html', context)
其他一切都应该在您的表单的验证和save()
方法中。
推荐阅读
- polymer - 将 HTML5+CSS+JS 项目转换为 Polymer(作为 PWA)
- tensorflow - TypeError:“Conv2DTranspose”类型的对象没有 len()
- sql - 使用正则表达式自定义 postgreSQL 域以接受一组字符串
- node.js - 升级到 Babel 7 后,无法分配给对象 ERROR 的只读属性“exports”
- ms-access-2010 - 更改打印对话框
- directory - 有什么办法可以欺骗 System.DirectoryServices.ActiveDirectory 的值?
- java - 为什么 Java 在 break 语句后不重置内部循环的值?
- ruby-on-rails - 如何在 simple_form_for 中创建具有 2 个嵌套属性和复选框的表
- react-admin - 'GET_LIST' 的响应必须像 { data : [...] },但接收到的数据不是数组
- python - 3D 中 > 100 万个点的散点图