【问题标题】:Stripe with Django - make form clean() method return value that isn't a form fieldStripe with Django - 使表单 clean() 方法返回不是表单字段的值
【发布时间】:2018-05-29 02:12:08
【问题描述】:

我正在将 Stripe 支付处理集成到我的 Django 应用程序中,但我无法找出“正确”的方式来验证客户的卡信息并在我的用户表中插入一行,其中包含用户的 Stripe 客户 ID。

理想情况下,我希望按照以下方式做一些事情,其中​​我的 CheckoutForm 验证卡详细信息并在它们不正确时引发表单 ValidationError。但是,使用此解决方案,我无法找到一种方法来获取由 clean() 函数生成的 customer.id。

forms.py

class CheckoutForm(forms.Form):
    email = forms.EmailField(label='E-mail address', max_length=128, widget=forms.EmailInput(attrs={'class': 'form-control'}))
    stripe_token = forms.CharField(label='Stripe token', widget=forms.HiddenInput)

    def clean(self):
        cleaned_data = super().clean()
        stripe_token = cleaned_data.get('stripe_token')
        email = cleaned_data.get('email')

        try:

            customer = stripe.Customer.create(
                email=email,
                source=stripe_token,
            )
            // I can now get a customer.id from this 'customer' variable, which I want to insert into my database

        except:
            raise forms.ValidationError("It looks like your card details are incorrect!")

views.py

# If the form is valid...
if form.is_valid():

    # Create a new user
        user = get_user_model().objects.create_user(email=form.cleaned_data['email'], stripe_customer_id=<<<I want the customer.id generated in my form's clean() method to go here>>>)
        user.save()

我能想到的唯一其他解决方案是在表单验证后在views.py 中运行stripe.Customer.create() 函数。这行得通,但它似乎不是编码事物的“正确”方式,因为据我了解,表单字段的所有验证都应该在 forms.py 中完成。

在这种情况下,正确的 Django 编码实践是什么?我应该将我的卡验证代码移动到views.py,还是有一种更简洁的方法将卡验证代码保留在forms.py 中并从中取出customer.id?

【问题讨论】:

    标签: django forms validation django-forms stripe-payments


    【解决方案1】:

    我不认为在这种情况下,正确的 Django 编码实践与 Python 编码实践有什么不同。由于 Django 表单只是一个类,您可以为customer 定义属性。像这样的:

    class CheckoutForm(forms.Form):
        email = forms.EmailField(label='E-mail address', max_length=128, widget=forms.EmailInput(attrs={'class': 'form-control'}))
        stripe_token = forms.CharField(label='Stripe token', widget=forms.HiddenInput)
    
        _customer = None
    
        def clean(self):
            cleaned_data = super().clean()
            stripe_token = cleaned_data.get('stripe_token')
            email = cleaned_data.get('email')  
    
            try:
                self.customer = stripe.Customer.create(
                    email=email,
                    source=stripe_token,
                )
            except:
                raise forms.ValidationError("It looks like your card details are incorrect!")
    
        @property
        def customer(self):
            return self._customer
    
        @customer.setter
        def customer(self, value):
            self._customer = value
    

    然后是form.is_valid() 之后的views.py,您将调用此属性。

    if form.is_valid():
        customer = form.customer
    

    或者@property 是一种矫枉过正,你可以简单地这样做:

    class CheckoutForm(forms.Form):
        email = forms.EmailField(label='E-mail address', max_length=128, widget=forms.EmailInput(attrs={'class': 'form-control'}))
        stripe_token = forms.CharField(label='Stripe token', widget=forms.HiddenInput)
    
        customer = None
    
        def clean(self):
            cleaned_data = super().clean()
            stripe_token = cleaned_data.get('stripe_token')
            email = cleaned_data.get('email')  
    
            try:
                self.customer = stripe.Customer.create(
                    email=email,
                    source=stripe_token,
                )
            except:
                raise forms.ValidationError("It looks like your card details are incorrect!")
    

    ...在views.py 中仍然是form.customer

    我想两者都应该可以工作,但我还没有测试过代码。

    【讨论】:

    • 明白了——完全有道理,博鲁特!感谢您的回复,我已接受此为正确答案。一个快速跟进:您是否认为在 clean() 方法中包含所有表单解析逻辑是“正确的 django 编码实践”?例如,我是否应该将所有 'user=' 代码块从 views.py 移到 forms.py 的 clean() 方法中?
    • clean() 中包含与表单验证相关的所有内容是一种很好的做法。您不应该在视图中验证表单(或用户发布的数据)。关于在clean() 中包含user 验证;我检查了我的一些项目,但没有发现很多我这样做或对我有意义的案例。
    • 太棒了。感谢您的帮助!
    猜你喜欢
    • 2016-04-29
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 2010-10-13
    • 1970-01-01
    相关资源
    最近更新 更多