Braintree Django 异常 "can only concatenate str (not "tuple") 到 str"

Braintree Django Exception "can only concatenate str (not "tuple") to 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)

signals.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_required()
  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 运行服务器)时,它工作正常,当创建用户时,会在 Braintree 中创建一个客户,其用户 ID 作为客户 ID。并且付款也得到了处理,没有任何问题。但是当通过弹性 beantalk 完成相同操作时,我收到错误“只能将 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, *args, **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 保存信号错误的回溯。

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/views/generic/base.py", line 70, in view
    return self.dispatch(request, *args, **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, *args, **kwargs)
  File "allauth/account/views.py", line 230, in dispatch
    return super(SignupView, self).dispatch(request, *args, **kwargs)
  File "allauth/account/views.py", line 75, in dispatch
    request, *args, **kwargs
  File "allauth/account/views.py", line 204, in dispatch
    return super(CloseableSignupMixin, self).dispatch(request, *args, **kwargs)
  File "django/views/generic/base.py", line 98, in dispatch
    return handler(request, *args, **kwargs)
  File "allauth/account/views.py", 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", line 246, 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", line 179, in send
    for receiver in self._live_receivers(sender)
  File "django/dispatch/dispatcher.py", line 179, 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, params)
  File "braintree/configuration.py", line 113, 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 开发人员。