0

I was looking through this article to figure out how to set a field's value after a form is initialized. I don't see this in Django's docs, or maybe I'm putting in the wrong query, but is there a way to set the 'min' attribute value of a field in views.py? I'm asking because the min value can change constantly since it's a bid amount that is set each time a user bids above the highest_bid variable value in the view_listing function.

models.py

class Bid(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
    listing = models.ForeignKey(Listing, on_delete=models.CASCADE, null=True)
    bid_amount = models.DecimalField(decimal_places=2, max_digits=10)

    def __str__(self):
        return f"{self.user}'s bid on {self.listing} is {self.bid_amount}"

forms.py

class BidForm(ModelForm):
    class Meta:
        model = Bid
        fields = ('bid_amount',)
        labels = { 'bid_amount': ('Your Bid'), }

        widgets = {
            'bid_amount': forms.NumberInput(attrs={'step': 00.50, 'class': 'form-control', 'style': 'width:50%', 'min': 0, 'title': '', 'placeholder': '' })
        }

views.py

@login_required
def view_listing(request, listing_id):
    listing = get_object_or_404(Listing, pk=listing_id)
    bids = Bid.objects.filter(listing=listing)

    all_bids = [] # Set an empty bid list to get all bids if any exist
    highest_bid = listing.starting_price # Set highest bid to 0 in case there are no bids

    if bids:
        bid_list = list(bids) # Convert Queryset to a list
        for index in bid_list:
            all_bids.append(index)
        highest_bid = all_bids[-1].bid_amount # Get the highest bid from all_bids
        listing.starting_price = highest_bid
    else:
        highest_bid # Else highest bid is 0

    if request.method == "GET":
        bid_form = BidForm()
        # Bid must be at least equal to highest bid
        bid_form.initial['bid_amount'] = highest_bid
        print(bid_form.initial['bid_amount'])

        try: # Check if the item is in the user's watchlist and pass the user's wishlist item name if it does
            Watchlist.objects.get(user=request.user, listing=listing)
            list_item = Watchlist.objects.get(user=request.user, listing_id=listing_id)
            return render(request, "auctions/viewlisting.html" , { "listing": listing, "item": list_item, "bids": bids, "bid_form": bid_form, "highest_bid": highest_bid  })
        except: # else return None
            None
        return render(request, "auctions/viewlisting.html" , { "listing": listing, "bids": bids, "bid_form": bid_form, "highest_bid": highest_bid })

    else: # On POST, allow a user to bid on an item
        try:

            bid_form = BidForm(request.POST)
            newbid = bid_form.save(commit=False)
            newbid.user = request.user

            if bid_form.is_valid():
                bid_amount = request.POST.get("bid_amount")
                # Got bid value from form. Left off here
                bid_value = bid_form.cleaned_data['bid_amount']

                if bid_value <= highest_bid:
                    messages.error(request, f"Your bid must be greater than ${highest_bid}")
                    return HttpResponseRedirect(listing.get_absolute_url())

                bid = Bid.objects.create(
                    listing=listing, user=request.user, bid_amount=bid_amount
                )
                bid.save()
                messages.success(request, "Your bid was saved.")
                return HttpResponseRedirect(listing.get_absolute_url())
            return redirect("auctions:index")

        except ValueError:
            messages.error(request, "Your bid was not accepted.")
            return render(request, "auctions/viewlisting.html", { "listing": listing, "error": ValueError })

viewlisting.html

some html code...
<!-- my bid form --!>
<form action="" method="POST">
   {% csrf_token %} {{ bid_form.as_p }}
   <input type="submit" value="Submit Your Bid" class="btn btn-danger">
</form>

In the "GET" section of my views.py file, where bid_form.initial['bid_amount'] = highest_bid is set, I also want to set the bid_form['bid_amount'] min value to highest_bid value each time it changes so that the user cannot enter anything lower than highest_bid in the form field. Is this at all possible to set in the views.py file? I've tried bid_form['bid_amount'].min but this shows up in the console <built-in method min of decimal.Decimal object at 0x7f99172a82d0>

1 Answer 1

1

You could make a custom function that checks all the other bid amounts, and returns a validation error if new bidding is less than any previous biddings

def validate_highest_bid(value):
    bids = Bid.objects.all()
    for bid in bids:
        if value <= bid.bid_amout:
            raise ValidationError(
            f"{value} must be higher than previous value",
            params={'value': value},
        )
class Bid(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
    listing = models.ForeignKey(Listing, on_delete=models.CASCADE, null=True)
    bid_amount = models.DecimalField(decimal_places=2, max_digits=10, validators=[validate_highest_bid])

    def __str__(self):
        return f"{self.user}'s bid on {self.listing} is {self.bid_amount}"

You can then add something on save that handles the error

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.