Django: 反向 'verify-payment' 没有找到参数 '('',)'。尝试了 1 种模式:['course/u/(?P<ref>[^/]+)/$']

Django: Reverse for 'verify-payment' with arguments '('',)' not found. 1 pattern(s) tried: ['course/u/(?P<ref>[^/]+)/$']

我写了一个视图来验证付款但是当我点击付款按钮时我得到这个错误说 Reverse for 'verify-payment' with arguments '('',)' not found. 1 pattern(s) tried: ['course/u/(?P<ref>[^/]+)/$']

我知道这是一个 url 配置错误,我没有传递正确的参数,但我不知道要传递什么,我已经尝试过 payment.ref

views.py

@login_required
def course_checkout(request, slug):
    course = Course.objects.get(slug=slug)
    user = request.user
    action = request.GET.get('action')
    order = None 
    payment = None 
    error = None 

    try:
        user_course = UserCourse.objects.get(user=user, course=course)
        error = "Congratulations! You are Already Enrolled In This Course"
    except:
        pass 
        amount = None 
        if error is None:
            amount = int((course.price - (course.price * course.discount * 0.01)) * 100)
        if amount == 0:
            userCourse = UserCourse(user=user, course=course)
            userCourse.save()
            return redirect('course:course-content', course.slug) # change this to redirect to my courses page with a button to start course because this course is free

        if action == 'create_payment':
            currency = "NGN"
            notes = {
            "email": user.email,
            "name": user.username
            }
            reciept = f"DexxaEd-{int(time())}"
            order = client.order.create(
                {
                'reciept' : reciept,
                'notes' : notes,
                'amount' : amount,
                'currency' : currency,
                'paystack_public_key' : settings.PAYSTACK_PUBLIC_KEY,
                }
            )

            payment = Payment()
            payment.user = user 
            payment.course = course 
            payment.order_id = order.get('id')
            payment.save()


    context = {
        "course":course,
        "order":order,
        "payment":payment,
        "user":user,
        "error":error,
    }

    return render(request, "course/course-checkout.html", context)


def verify_payment(request: HttpRequest, ref: str) -> HttpResponse:
    payment = get_object_or_404(Payment, ref=ref)
    verified = payment.verify_payment()
    return redirect("userauths:profile")

models.py


class Payment(models.Model):
    order_id = models.CharField(max_length = 50 , null = False)
    payment_id = models.CharField(max_length = 50)
    user_course = models.ForeignKey(UserCourse , null = True , blank = True ,  on_delete=models.CASCADE)
    user = models.ForeignKey(User ,  on_delete=models.CASCADE)
    course = models.ForeignKey(Course , on_delete=models.CASCADE)
    date = models.DateTimeField(auto_now_add=True)
    status = models.BooleanField(default=False)

    email = models.EmailField()
    ref = models.CharField(max_length=200)
    verified = models.BooleanField(default=False)

    def __str__(self):
        return f"Payment: {self.course.price}"
    
    def save(self ,*args, **kwargs):
        while not self.ref:
            ref = secrets.token_urlsafe(50)
            objects_with_similar_ref = Payment.objects.filter(ref=ref)
            if not objects_with_similar_ref:
                self.ref = ref 
            super().save(*args, **kwargs)
    
    def amount_value(self) -> int:
        return self.course.price * 100

    def verify_payment(self):
        paystack = PayStack()
        status, result = paystack,verify_payment(self.ref, self.course.price)
        if status:
            if result['course.price'] / 100 == self.course.price:
            # if result['amount'] / 100 == self.course.price:
                self.verified = True
            self.save()
        if self.verified:
            return True 
        return False

urls.py

    path('u/<str:ref>/', views.verify_payment, name = 'verify-payment'),

课程-checkout.html

{{ course.price }}
<button id="django-paystack-button" onclick="payWithPayStack()" class="chck-btn22">Make Payment</button>

<script>
    function payWithPaystack() {
        let currency = "USD";
        let plan = "";
        let ref = "{{payment.ref}}";
        let obj = {
            key: "{{ paystack_public_key }}",
            email: "{{ request.user.email }}",
            amount: "{{course.price_value}}",
            ref: ref,
            callback: function (response) {
                window.location.href = "{% url 'course:verify-payment' payment.ref %}";
            },
        };

        if (Boolean(currency)) {
            obj.currency = currency.toUpperCase();
        }
        if (Boolean(plan)) {
            obj.plan = plan;
        }
        var handler = PaystackPop.setup(obj);
        handler.openIframe();
    }
</script>

问题不在于您的 url 配置,也不在于 payment.ref,而在于您的 course_checkout 页面中的逻辑。问题是即使付款是 None,用户也可以登陆 course-checkout.html 页面,这就是导致错误的原因,因为 url 期待非空 <str:ref>。我的期望是,如果这不是您想要的,我深表歉意,用户应该进入 course-checkout 页面的唯一时间是 (1) 用户尚未注册该课程,或 (2)该课程是免费的。否则,应将用户带到 course-checkout 页面(无需检查 if action == 'create_payment':,因为如果 (1) 或 (2) 为假,这是唯一的其他选项,正如我所见).我没有测试下面的代码,但我认为这可能是实现它的方法:

def course_checkout(request, slug):
    course = Course.objects.get(slug=slug)
    user = request.user
    action = request.GET.get('action')
    order = None 
    payment = None 
    error = None 

    try:
        user_course = UserCourse.objects.get(user=user, course=course)
    except:
        pass

    # User is already registered for course, so go to the course page
    if user_course:
        return redirect('course:course-content', course.slug)

    amount = int((course.price - (course.price * course.discount * 0.01)) * 100)

    # Redirect to my courses page with a button to start course because this course is free
    if amount == 0:
        userCourse = UserCourse(user=user, course=course)
        userCourse.save()
        return redirect('course:course-content', course.slug) 
        
    # User is not registered for the course, and the amount is NOT 0, so send 
    # to the checkout page
    currency = "NGN"
    notes = {
        "email": user.email,
        "name": user.username
    }
    reciept = f"DexxaEd-{int(time())}"
    order = client.order.create(
        {
            'reciept' : reciept,
            'notes' : notes,
            'amount' : amount,
            'currency' : currency,
            'paystack_public_key' : settings.PAYSTACK_PUBLIC_KEY,
        }
    )

    payment = Payment()
    payment.user = user 
    payment.course = course 
    payment.order_id = order.get('id')
    payment.save()

    context = {
        "course":course,
        "order":order,
        "payment":payment,
        "user":user,
        "error":error,
    }

    return render(request, "course/course-checkout.html", context)