将Django表单中的所有CharField字段输入转换为小写

3 投票
3 回答
11838 浏览
提问于 2025-04-18 10:24

我正在使用Django框架的表单来让用户注册,在这个表单里,用户可以输入优惠码。我想把用户在优惠码输入框里输入的所有字符都转换成小写字母。我尝试过在保存数据的方法里用.lower(),也尝试过在自定义的清理方法和自定义的验证器里使用这个方法,但都没有成功。下面是我的代码。

class StripeSubscriptionSignupForm(forms.Form):
    coupon = forms.CharField(max_length=30,
        required=False,
        validators=[validate_coupon],
        label=mark_safe("<p class='signup_label'>Promo Code</p>")

    def save(self, user):
        try:
            customer, created = Customer.get_or_create(user)
            customer.update_card(self.cleaned_data["stripe_token"])
            customer.subscribe(self.cleaned_data["plan"], self.cleaned_data["coupon"].lower())
        except stripe.StripeError as e:
            # handle error here
            raise e

如上所述,我也尝试过一个清理方法,但这个方法也没有效果:

def clean_coupon(self):
    return self.cleaned_data['coupon'].lower()

3 个回答

1

我在处理用户模型中的电子邮件字段时遇到了一个问题,想确保这个字段只保存为小写字母。下面我提到的方法的好处是,你可以控制表单中每个字段的格式,而不是像上面选中的答案那样,所有字段都被强制转换为小写,不管你是否想这样。

我遇到的问题,以及我相信上面提问者也遇到的问题是,虽然清理后的值确实是小写的,但在HTML页面上(也就是在验证和清理后显示的页面)却显示的是未清理的值(也就是仍然是大写的),这会让用户感到困惑。发生的情况是,表单字段的值仍然是最初的数据,比如X@Y.com,而清理后的数据实际上是x@y.com。

在处理提交的表单后:

>>>user_form.cleaned_data['email']
'x@y.com'

还有

>>>user_form['email'].value()
'X@Y.com'

模板使用的是user_form['email'].value(),而不是user_form.cleaned_data['email']提供的值,所以用户以为他的电子邮件是以大写形式保存的,实际上它是以小写形式保存的。

在这种情况下,最简单的方法是,在保存后直接重新加载保存的表单,这样清理后的字段就会在模板中显示出来。以下是两个示例(一个是保存到数据库,一个不是保存到数据库)。

forms.py

from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
    """
    UserForm is a simple form to allow a user to change his/her name and email.
    """
    class Meta:
        model = User 
        fields = ['first_name', 'last_name', 'email']

    def clean_email(self):
        """
        ensure that email is always lower case.
        """
        return self.cleaned_data['email'].lower()

在views.py中

def post(self, request):
    user_form = UserForm(request.POST, instance=request.user)
    if user_form.is_valid():
        user_form.save()  # using the provided save from Modelform in this case
        user_form = UserForm(instance=request.user)  # reload the amended user data
    return render(request, 'myApp/user_details.html',{'user_form': user_form})

这里的关键行是在views.py中,user_form = UserForm(instance=request.user),这行代码重新加载了表单。这样做的效果是,在呈现给用户之前,表单会用清理过的(在这种情况下是已保存的)数据重新填充。

现在,你可以通过为这些字段调用适当的clean_fieldname,将表单中的每个字符字段都转换为小写。

注意:如果你不与数据库交互(或者只是想不从数据库重新加载),你可以按如下方式重新填充表单:

def post(self, request):
    user_form = UserForm(request.POST) #gather the post'ed data
    if user_form.is_valid():
        user_form.process()  # process the gathered cleaned data            
        user_form = UserForm(
            {'email': user_form.cleaned_data['email'],
            'first_name': user_form.cleaned_data['first_name'],
            'last_name': user_form.cleaned_data['last_name'],}
        ) # reload the form       
    return render(request, 'myApp/user_details.html',{'user_form': user_form})

作为一个小优化,你可以使用内置的检查:

 if user_form.has_changed():

在is_valid()检查之后(或与之结合使用) - 通常如果表单没有任何变化,就没有必要保存或处理表单。

7

试着在你的表单中使用一个 CSS 的文本转换功能,像这样:

class StripeSubscriptionSignupForm(forms.Form):
    coupon = forms.CharField(max_length=30,
        required=False,
        validators=[validate_coupon],
        label=mark_safe("<p class='signup_label'>Promo Code</p>")
        widget=TextInput(attrs={'style': 'text-transform:lowercase;'})
        )
8

解决办法是创建一个自定义的表单字段,这样你就可以重写 to_python 方法。在这个方法里,你可以对表单字段中原始的值进行修改。

class CouponField(forms.CharField):
    def to_python(self, value):
        return value.lower()


class StripeSubscriptionSignupForm(forms.Form):
    coupon = CouponField(max_length=30,
        required=False,
        validators=[validate_coupon],
        label=mark_safe("<p class='signup_label'>Promo Code</p>")
    )

撰写回答