【问题标题】:Django 1.11 TypeError context must be a dict rather than ContextDjango 1.11 TypeError 上下文必须是 dict 而不是 Context
【发布时间】:2017-10-02 22:01:18
【问题描述】:

刚刚在我的一个表单上收到了 Sentry 错误 TypeError context must be a dict rather than Context.。我知道它与 Django 1.11 有关,但我不确定要更改什么来修复它。

违规行

message = get_template('email_forms/direct_donation_form_email.html').render(Context(ctx))

整个视图

def donation_application(request):
    if request.method == 'POST':
        form = DirectDonationForm(data=request.POST)
        if form.is_valid():
            stripe.api_key = settings.STRIPE_SECRET_KEY
            name = request.POST.get('name', '')
            address = request.POST.get('address', '')
            city = request.POST.get('city', '')
            state = request.POST.get('state', '')
            zip = request.POST.get('zip', '')
            phone_number = request.POST.get('phone_number', '')
            support = request.POST.get('support', '')
            agree = request.POST.get('agree', '')
            email_address = request.POST.get('email_address', '')
            number = request.POST.get('number', '')
            cvc = request.POST.get('cvc', '')
            exp = request.POST.get('exp', '')
            # token = form.cleaned_data['stripe_token'],
            # exp_m = int(request.POST.get('exp_month', ''))
            # exp_y = int(request.POST.get('exp_year', ''))

            exp_month = exp[0:2]
            exp_year = exp[5:9]

            subject = 'New Donation'
            from_email = settings.DEFAULT_FROM_EMAIL
            recipient_list = ['deniselarkins@/////\\\\\.com',
                              'charles@/////\\\\\.net',
                              'marcmunic@/////\\\\\.com',
                              ]

            token = stripe.Token.create(
                card={
                    'number': number,
                    'exp_month': exp_month,
                    'exp_year': exp_year,
                    'cvc': cvc
                },
            )

            customer = stripe.Customer.create(
                email=email_address,
                source=token,
            )

            total_support = decimal.Decimal(support) / 100
            total_charge = decimal.Decimal(int(support)) / 100

            # Charge the user's card:
            charge = stripe.Charge.create(
                amount=total_charge,
                currency='usd',
                description='Donation',
                customer=customer.id
            )

            ctx = {
                'name': name,
                'address': address,
                'city': city,
                'state': state,
                'zip': zip,
                'phone_number': phone_number,
                'email_address': email_address,
                'agree': agree,
                'charge': charge,
                'customer': customer,
                'total_support': total_support,
                'total_charge': total_charge
            }

            message = get_template('email_forms/direct_donation_form_email.html').render(Context(ctx))
            msg = EmailMessage(subject, message, from_email=from_email, to=recipient_list)
            msg.content_subtype = 'html'
            msg.send(fail_silently=True)

            return redirect(
                '/contribute/donation-support-thank-you/?name=' + name +
                '&address=' + address +
                '&state=' + state +
                '&city=' + city +
                '&zip=' + zip +
                '&phone_number=' + phone_number +
                '&email_address=' + email_address +
                '&total_support=' + str(total_support) +
                '&total_charge=' + str(total_charge)
            )
    context = {
        'title': 'Donation Pledge',
    }

    return render(request, 'contribute/_donation-application.html', context)

【问题讨论】:

标签: python django django-views


【解决方案1】:

Django 1.8+ 中,模板的render 方法采用context 参数的字典。支持传递Context 实例is deprecated,并在Django 1.10+ 中报错。

在您的情况下,只需使用常规 dict 而不是 Context 实例:

message = get_template('email_forms/direct_donation_form_email.html').render(ctx)

您可能更喜欢使用render_to_string 快捷方式:

from django.template.loader import render_to_string

message = render_to_string('email_forms/direct_donation_form_email.html', ctx)

如果您使用RequestContext 而不是Context,那么您也可以将request 传递给这些方法,以便上下文处理器运行。

message = get_template('email_forms/direct_donation_form_email.html').render(ctx, request=request)
message = render_to_string('email_forms/direct_donation_form_email.html', ctx, request=request)

【讨论】:

  • 这仅适用于您在模板中加载的情况吗?我很好奇,因为我在 shell 中创建了一个测试模板,然后尝试只传递一个 dict 但它抱怨它不是一个上下文,这对我来说似乎很奇怪,这将是一种方式但不同的方式为对方
  • @DavidTorrey 如果你手动构造了一个django.template.Template,那么你仍然需要传递一个Context 实例。根据您使用template = Template(...) 还是template = get _template(...),API 会有所不同,这有点令人困惑。
【解决方案2】:

从 Django 1.8 迁移到 Django 1.11.6

无论我有一个 RequestContext 类,都有一个方法 flatten() 将结果作为字典返回。

所以如果类是 RequestContext....

return t.render(context)

变成

return t.render(context.flatten())

如果上下文被 Context() 包裹,只需将其删除即可。因为 Context() 已被弃用。

return t.render(Context(ctx))

变成

return t.render(ctx)

【讨论】:

  • 除了展平RequestContext之外,还可以使用字典并传递请求,例如t.render(ctx, request=request).
【解决方案3】:

对于 django 1.11 及更高版本,上下文必须是 dict。

你可以使用:

context_dict = get_context_dict(context)
return t.render(context_dict)

context_dict = context.flatten()
return t.render(context_dict)

【讨论】:

  • 函数 get_context_dict 在 Django 中似乎不存在。
【解决方案4】:

我来到这里是因为我遇到了同样的问题。我正在通过 Andrew Pinkham 的 Django Unleashed 学习 Django。这是一本 2015 年的书。

我在官方文档中发现,必须将字典传递给上下文参数而不是上下文实例(来自 django.template.Context)。

@Alasdair 建议使用 render_to_string,但是,至少在 Django 3.2 中 render 方法本质上使用 render_to_string 方法。

def render(request, template_name, context=None, content_type=None, status=None, using=None):
"""
Return a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
"""
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)

所以,只使用渲染方法可能会更好。我提供这个答案是因为它是我一直在寻找的答案,它可能会帮助一些人解决这个 Stack Overflow 问题。

【讨论】:

    猜你喜欢
    • 2018-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-15
    • 2019-07-01
    • 2022-10-13
    • 2022-11-06
    • 2019-02-01
    相关资源
    最近更新 更多