Как валидировать поле формы в django?
Я хочу убедиться, что текущее значение поля "ставка" не меньше, чем текущая самая большая ставка. Это моя форма с пользовательским методом очистки.
Форма:
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":
biggest_bid = Bid.objects.filter(user=user).aggregate(Max("amount"))
form = Place_A_Bid_Form(biggestBid=biggest_bid, 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's 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.min_value = min_bid
bid.validators.add(MinValidator(min_bid))
тогда вам нужно только передать 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, min_bid=biggest_bid)
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(min_bid=biggest_bid)
return render(request, 'app_name/name-of-template.html', {'form': form})
Это также создаст форму в случае GET-запроса с самым большим предложением в качестве минимальной ставки. Это также добавит это как min="biggest-bid" в HTML, чтобы браузер мог проверить это. Таким образом, форма может проверить ставку уже на стороне клиента перед отправкой формы, но также правильно проверит форму на стороне сервера.
Однако, возможно, лучше передавать листинг не через форму, а как параметр URL.
Примечание: Вы можете ограничить представления для аутентифицированных пользователей с помощью декоратора
@login_requiredдекоратора [Django-doc].