如何验证 Django 中的表单字段?

How to validate form field in django?

我想确保 bid field 的当前值不小于当前最大值 bid。这是我使用自定义 clean 方法的表单。

表格:

class Place_A_Bid_Form(forms.Form):
    listing = forms.CharField(widget=forms.TextInput(attrs={"type":"hidden"}))
    bid = forms.IntegerField(widget=forms.NumberInput(attrs={"class":"form-control"}), min_value=1)

    def clean_bid(self, biggestBid):
        bid = self.cleaned_data["bid"]
        if bid < biggestBid:
            raise ValidationError("""New bid shouldn't be less than starting bid, or 
                                    if any bids have been placed then new bid 
                                    should be greater than current biggest bid""")
        return bid

查看:

def place_a_bid(request):
    if request.method == "POST":
        form = Place_A_Bid_Form(request.POST)
        user = User.objects.get(username=request.user.username)
        biggest_bid = Bid.objects.filter(user=user).aggregate(Max("amount"))
        if form.is_valid():
            data = form.cleaned_data
            user_obj = User.objects.get(username=request.user.username)
            listing_obj = Listing.objects.get(title=data["listing"])
            Bid.objects.update_or_create(
                user=user_obj,
                listing=listing_obj,
                amount=data["bid"]
            )
        return redirect(listing_obj)

鉴于我正在提取要与之比较的当前值,但我不知道如何将此值传递给我的表单字段的 clean 方法。或者也许我做错了?那么如何正确地进行这种验证呢?

class Place_A_Bid_Form(forms.Form):
    listing = forms.CharField(widget=forms.TextInput(attrs={"type":"hidden"}))
    bid = forms.IntegerField(widget=forms.NumberInput(attrs={"class":"form-control"}),
    min_value=1)

    def __init__(self,biggestBid=0 *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.biggestBid = biggestBid

    def clean_bid(self):
        bid = self.cleaned_data["bid"]
        if bid < self.biggestBid:
            raise ValidationError("""New bid shouldn't be less than starting bid, or 
                                    if any bids have been placed then new bid 
                                    should be greater than current biggest bid""")
        return bid

然后在 views.py:

def place_a_bid(request):
    if request.method == "POST":
        dict = Bid.objects.filter(user=user).aggregate(Max("amount"))
        form = Place_A_Bid_Form(biggestBid=dict['amount__max'], data=request.POST)
        user = User.objects.get(username=request.user.username)
        if form.is_valid():
            data = form.cleaned_data
            user_obj = User.objects.get(username=request.user.username)
            listing_obj = Listing.objects.get(title=data["listing"])
            Bid.objects.update_or_create(
                user=user_obj,
                listing=listing_obj,
                amount=data["bid"]
            )
        return redirect(listing_obj)

Django 的 IntegerField [Django-doc] 可以在没有任何额外逻辑的情况下验证最小值,您可以设置 .min_value 并添加一个验证器:

from django.core.validators import MinValueValidator

class Place_A_Bid_Form(forms.Form):
    listing = forms.CharField(widget=forms.TextInput(attrs={'type': 'hidden'}))
    bid = forms.IntegerField(widget=forms.NumberInput(attrs={'class':'form-control'}))

    def __init__(self, *args, **kwargs, min_bid=0):
        super().__init__(*args, **kwargs)
        bid = self.fields['bid']
        min_bid += 1
        bid<strong>.min_value = min_bid</strong>
        bid<strong>.validators.add(MinValidator(min_bid))</strong>

那么你只需要将 min_bid 传递给表单:

from django.contrib.auth.decorators import login_required

@login_required
def place_a_bid(request):
    biggest_bid = Bid.objects.filter(user=request.user).aggregate(
        min_bid=Max('amount')
    )['min_bid'] or 0
    if request.method == 'POST':
        form = Place_A_Bid_Form(request.POST<strong>, min_bid=biggest_bid</strong>)
        if form.is_valid():
            data = form.cleaned_data
            listing_obj = Listing.objects.get(title=data['listing'])
            Bid.objects.update_or_create(
                user=request.user,
                listing=listing_obj,
                amount=data['bid']
            )
            return redirect(listing_obj)
    else:
        form = Place_A_Bid_Form(<strong>min_bid=biggest_bid</strong>)
    return render(request, '<em>app_name</em>/name-of-template.html', {'form': form})

在 GET 请求的情况下,这也构建了一个表单,将最大出价作为最低出价。这还将在 HTML 中将其添加为 min="<em>biggest-bid</em>" 以便浏览器可以验证这一点。因此,这也可以在提交表单之前在客户端验证出价,但也会在服务器端正确验证表单。

然而,最好不要通过表单传递列表,而是作为 URL 参数。


Note: You can limit views to a view to authenticated users with the @login_required decorator [Django-doc].