Я создаю приложение для аукционов, и мне нужно проверить, что сумма ставки, введенная в форму, равна или превышает начальную ставку (если было 0 ставок), или превышает текущую ставку.
Я использовал настраиваемую проверку с помощью clean ():
class Bid(models.Model):
listing = models.ForeignKey(Listing, on_delete=models.CASCADE)
amount = models.DecimalField(max_digits=11, decimal_places=2)
def clean(self):
# if there has been one or more bids
if self.listing.current_bid and self.listing.current_bid.amount >= self.amount:
raise ValidationError({'amount': _('Amount must be greater than current bid')})
# else if there has been 0 bids
elif self.listing.starting_bid > self.amount:
raise ValidationError({'amount': _('Amount must be great than or equal to starting bid')})
In views.py:
def listing_page(request, listing_id):
listing_selected = Listing.objects.get(pk=listing_id)
if request.method == "POST":
# Since I don't want the user to have to fill out a field specifying what listing page
# they're on, and since I don't have access to that information in the model class
# definition, I did that here:
request.POST._mutable = True
form = BidForm(request.POST)
form.data['listing'] = listing_selected
if form.is_valid():
# ...process clean data...
return HttpResponseRedirect(reverse('auctions:listing_page', args=(listing_id,)))
Теперь, когда я отправляю форму со значением, которое проверяется с помощью этой настраиваемой проверки я получаю «ValueError: представление auctions.views.listing_page не вернуло объект HttpResponse. Вместо этого оно вернуло None». Я проверил, что is_valid () оценивает значение False с помощью оператора печати. Если я отправлю недопустимое значение по умолчанию, например 10.1111 или abcd, я получаю правильное сообщение об ошибке. Разве это не должно происходить, когда is_valid () оценивается как False из-за моей пользовательской проверки? Что мне не хватает?
Редактировать: по запросу, полный вид (думаю, я изначально включил все соответствующие части, но кто знает):
def listing_page(request, listing_id):
listing_selected = Listing.objects.get(pk=listing_id)
bids = Bid.objects.filter(listing=listing_selected)
if request.method == "POST":
if request.POST.get('add_to_watchlist') and request.user.is_authenticated:
request.user.person.watchlist.add(listing_selected)
return HttpResponseRedirect(reverse('auctions:listing_page', args=(listing_id,)))
elif request.POST.get('remove_from_watchlist') and request.user.is_authenticated:
request.user.person.watchlist.remove(listing_selected)
return HttpResponseRedirect(reverse('auctions:listing_page', args=(listing_id,)))
elif (request.POST.get('close_listing') and request.user.is_authenticated
and request.user == listing_selected.user):
listing_selected.active = False
listing_selected.save()
return HttpResponseRedirect(reverse('auctions:listing_page', args=(listing_id,)))
elif request.POST.get('make_comment') and request.user.is_authenticated:
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
comment = Comment()
comment.user = request.user
comment.listing = listing_selected
comment.comment = comment_form.cleaned_data['comment']
comment.save()
return HttpResponseRedirect(reverse('auctions:listing_page', args=(listing_id,)))
elif request.POST.get('make_bid') and request.user.is_authenticated:
request.POST._mutable = True
form = BidForm(request.POST)
form.data['listing'] = listing_selected
if form.is_valid():
bid = Bid()
bid.listing = listing_selected
bid.user = request.user
bid.amount = form.cleaned_data['amount']
bid.save()
listing_selected.current_bid = bid
listing_selected.save()
request.session['bid_success_message'] = "Bid placed successfully."
return HttpResponseRedirect(reverse('auctions:listing_page', args=(listing_id,)))
else:
form = BidForm()
comment_form = CommentForm()
winning = False
if request.user.is_authenticated:
person = Person.objects.filter(user=request.user).filter(watchlist=listing_selected)
else:
person = False
if listing_selected.current_bid and listing_selected.current_bid.user == request.user:
winning = True
comments = Comment.objects.filter(listing=listing_selected)
category = None
if listing_selected.category:
for value, label in Listing.Category.choices:
if value == listing_selected.category:
category = label
context = {
"listing": listing_selected,
"person": person,
"num_bids": len(bids),
"winning": winning,
"form": form,
"comment_form": comment_form,
"comments": comments,
"category": category
}
if "bid_fail_message" in request.session:
message = request.session['bid_fail_message']
del request.session['bid_fail_message']
messages.error(request, message)
if "bid_success_message" in request.session:
message = request.session['bid_success_message']
del request.session['bid_success_message']
messages.success(request, message)
return render(request, "auctions/listing_page.html", context)
Также по запросу html:
<form class="bidform" action="{% url 'auctions:listing_page' listing.id %}" method="POST">
{% csrf_token %}
{{ form.amount }}
<input class="button bid_button" type="submit" value="Place Bid" name="make_bid">
</form>
Редактировать: Я запустил отладчик, и он переходит к этому методу dunder str перед тем, как выдать ошибку:
class Listing(models.Model):
def __str__(self):
return f"Listing '{self.title}' created by user '{self.user.username}' \
on {self.time_created.date()}"
Это происходит в обоих случаях, если я делаю «шаг в» и если я "перешагну" при вызове is_valid (). Зачем ему это?