Braintree Django 异常“只能将 str而不是“元组”连接到 str"

问题描述

我在我的 Django 项目中使用 Braintree Drop-in。当我在开发环境 (manage.py runserver) 中使用它时,它完全正常工作。但是当我在弹性 beantalk 上访问相同的内容时,我收到错误“只能将 str(而不是“元组”)连接到 str”。以下是我的代码

extras.py

from django.conf import settings
import braintree

gateway = braintree.BraintreeGateway(
    braintree.Configuration(
        braintree.Environment.SandBox,merchant_id=settings.BT_MERCHANT_ID,public_key=settings.BT_PUBLIC_KEY,private_key=settings.BT_PRIVATE_KEY,)
)

def generate_client_token():
    return gateway.client_token.generate()

def transact(options):
    return gateway.transaction.sale(options)

def find_transaction(id):
    return gateway.transaction.find(id)

信号.py

from django.db.models.signals import post_save
from django.dispatch import receiver
#from django.conf import settings

from invoices.extras import gateway


@receiver(post_save,sender=User)
def create_phone(sender,instance,created,**kwargs):
    if created:
        gateway.customer.create({
            "first_name": instance.first_name,"last_name": instance.last_name,"email": instance.email,"phone": instance.phone_number,"id": instance.id,})

views.py

@login_@R_404_3889@()
  def customer_invoice_view(request,ticket_id):
      ticket = get_object_or_404(Ticket,pk=ticket_id)
      customer = ticket.customer
      client_token = gateway.client_token.generate({"customer_id": str(customer.id)})
      invoice = ticket.invoice
      if request.method == 'POST':
          result = transact({
              'amount': invoice.amount_payable,'payment_method_nonce': request.POST['payment_method_nonce'],'options': {
                  "submit_for_settlement": True
              }
          })

          if result.is_success or result.transaction:
              invoice.is_paid = True
              invoice.save()
              ticket = invoice.ticket
              ticket.status ='Payment Made'
              ticket.paid = True
              ticket.save()
              return redirect(customer_invoice_view,ticket_id=ticket.id)
          else:
              for x in result.errors.deep_errors:
                  messages.info(request,x)
              return redirect(customer_invoice_view,ticket_id=ticket.id)
      context = {
      'ticket' : ticket,'invoice' : invoice,'client_token' : client_token,}
      return render(request,'invoice/ticket_invoice_view.html',context)

ticket_invoice_view.html

<div class="p-3"> 
    {% if not invoice.is_paid%}
    <div class="row no-gutters">
        <div class="mb-2">
        <ul>
            {% for message in messages %}
            <li class="text-dark">{{message}}</li>
            {% endfor %}
        </ul>
        </div>
    </div>
    <div class="row no-gutters my-4">
        <form id="payment-form" method="post" action="" autocomplete="off">
            {% csrf_token %}
          <section>
            <div class="bt-drop-in-wrapper">
              <div id="bt-dropin"></div>
            </div>
          </section>
    
          <input type="hidden" id="nonce" name="payment_method_nonce" />
          <button class="btn-success" type="submit" id="submit-button"><span>Make Payment</span></button>
        </form>
    </div>
    {% endif %}
</div>

<script src="https://js.braintreegateway.com/web/dropin/1.25.0/js/dropin.min.js"></script>
<script>
  var form = document.querySelector('#payment-form');
  var client_token = '{{ client_token }}';

  braintree.dropin.create({
    authorization: client_token,container: '#bt-dropin',paypal: {
      flow: 'vault'
    }
  },function (createErr,instance) {
    form.addEventListener('submit',function (event) {
      event.preventDefault();

      instance.requestPaymentMethod(function (err,payload) {
        if (err) {
          console.log('Error',err);
          return;
        }

        // Add the nonce to the form and submit
        document.querySelector('#nonce').value = payload.nonce;
        form.submit();
      });
    });
  });
</script>

当我在本地运行项目 (manage.py runserver) 时,它工作正常,当创建用户时,会在 Braintree 中创建一个客户,用户 ID 为客户 ID。而且付款也得到了处理,没有任何问题。但是当通过弹性豆茎完成同样的操作时,我收到错误“只能将 str(而不是“元组”)连接到 str”。

以下是回溯。

TypeError: can only concatenate str (not "tuple") to str
  File "django/core/handlers/exception.py",line 47,in inner
    response = get_response(request)
  File "django/core/handlers/base.py",line 179,in _get_response
    response = wrapped_callback(request,*callback_args,**callback_kwargs)
  File "django/contrib/auth/decorators.py",line 21,in _wrapped_view
    return view_func(request,*args,**kwargs)
  File "accounts/decorators.py",line 20,in wrapper_func
    return view_func(request,**kwargs)
  File "invoices/views.py",line 33,in customer_invoice_view
    client_token = gateway.client_token.generate({"customer_id": str(customer.id),},)
  File "braintree/client_token_gateway.py",line 26,in generate
    response = self.config.http().post(self.config.base_merchant_path() + "/client_token",params)
  File "braintree/configuration.py",line 113,in base_merchant_path
    return "/merchants/" + self.merchant_id

这是 Post Save Signal Error 的回溯。

TypeError: can only concatenate str (not "tuple") to str
  File "django/core/handlers/exception.py",**callback_kwargs)
  File "django/views/generic/base.py",line 70,in view
    return self.dispatch(request,**kwargs)
  File "django/utils/decorators.py",line 43,in _wrapper
    return bound_method(*args,**kwargs)
  File "django/views/decorators/debug.py",line 89,in sensitive_post_parameters_wrapper
    return view(request,**kwargs)
  File "allauth/account/views.py",line 230,in dispatch
    return super(SignupView,self).dispatch(request,line 75,in dispatch
    request,**kwargs
  File "allauth/account/views.py",line 204,in dispatch
    return super(CloseableSignupMixin,**kwargs)
  File "django/views/generic/base.py",line 98,in dispatch
    return handler(request,line 102,in post
    response = self.form_valid(form)
  File "allauth/account/views.py",line 246,in form_valid
    self.user = form.save(self.request)
  File "allauth/account/forms.py",line 419,in save
    adapter.save_user(request,user,self)
  File "allauth/account/adapter.py",in save_user
    user.save()
  File "django/contrib/auth/base_user.py",line 67,in save
    super().save(*args,**kwargs)
  File "django/db/models/base.py",line 754,in save
    force_update=force_update,update_fields=update_fields)
  File "django/db/models/base.py",line 803,in save_base
    update_fields=update_fields,raw=raw,using=using,File "django/dispatch/dispatcher.py",in send
    for receiver in self._live_receivers(sender)
  File "django/dispatch/dispatcher.py",in <listcomp>
    for receiver in self._live_receivers(sender)
  File "accounts/signals.py",line 30,in create_phone
    "id": instance.id,File "braintree/customer_gateway.py",line 24,in create
    return self._post("/customers",{"customer": params})
  File "braintree/customer_gateway.py",line 79,in _post
    response = self.config.http().post(self.config.base_merchant_path() + url,in base_merchant_path
    return "/merchants/" + self.merchant_id

如果有人能帮我解决,我将不胜感激。

解决方法

谢谢你这么详细的问题!

错误就是线索。它说你试图连接一个元组和一个不允许的字符串。由于该行是 return "/merchants/" + self.merchant_id 并且我没有看到表示无关元组的逗号,这意味着问题出在 self.merchant_id 上。这似乎是从 settings.BT_MERCHANT_ID 设置的。我的预感是 settings.BT_MERCHANT_ID 在它的末尾有一个逗号,它不应该导致它成为一个元组。

例如:

x = 1

导致 x 被设置为整数 1。但是

x = 1,

导致 x 被设置为元组 (1,)。这是一个痛苦的陷阱,最终会咬住每个 Python 开发人员。