How to get highest bid in an auction bidding site Django

def make_bid(request, listing_id):
    listing = Auction.objects.get(pk=listing_id)
    bid_item = Bids.objects.filter(auction=listing).order_by('-new_bid').first()
    

#if theres no bid available, use starting bid, if available, update to the latest bid

    if bid_item == None:
        bid = listing.starting_bid
    else:
        bid = bid_item.new_bid

    if request.method == 'POST':
        bid_form = BidForm(request.POST, listing=listing)
        if bid_form.is_valid():
            accepted_bid = bid_form.save(commit=False)
            accepted_bid.user = request.user
            accepted_bid.save()

            messages.success(request, 'Successfully added your bid')
            return redirect('listing_detail', listing_id=listing_id)


        else:
            context = {
                "bid_form": bid_form,
                "bid": bid,
                "bid_item": bid_item,
                "listing": listing
                } 

        return render(request, 'auctions/details.html', context)
             
                
    return render(request, 'auctions/details.html', bid_form = BidForm())  

The listing reference in your context comes from this line:
listing = Auction.objects.get(pk=listing_id)
which means itā€™s an instance of an Auction object.

Where is that Auction object being updated?
(Your view is updating the Bids object from the form, but I see nothing here that would update the listing object.)

Edit:
Also, your template references a field named bid in that listing object, but I donā€™t see that defined in the Auction model definition you provided earlier.

I updated my Views to update the listing object

def make_bid(request, listing_id):
    listing = Auction.objects.get(pk=listing_id)
    bid_item = Bids.objects.filter(auction=listing)

    if request.method == 'POST':
        bid_form = BidForm(request.POST, listing=listing)
        if bid_form.is_valid():
            new_bid = request.POST["new_bid"]
            current_bid = bid_form.save(commit=False)
            current_bid.user = request.user
            current_bid.save()
            listing.bidding.add(current_bid)
            listing.bidding.new_bid = new_bid
            listing.save()


            messages.success(request, 'Successfully added your bid')
            return redirect('listing_detail', listing_id=listing_id)
#bidding is from the related name to auction
                  <h6>${{ listing.bidding.new_bid }}</h6>
                  <small>{{ listing.description|truncatewords:6 }}</small>

These three lines are unnecessary. The first line is going to add a duplicate row in the database. The second row is meaningless - listing.bidding is a set of rows, not an individual row. Setting an attribute value there isnā€™t right. And the third row doesnā€™t do anything. A reference to a related object is not a change to the object itself.

However, what you do want to do is update the auction field in the current_bid object before saving it.

Then, in your template:

Again, listing.bidding here is a set, not a singular item.

Review the docs on Related objects reference | Django documentation | Django

1 Like

I think Iā€™m close but not sure why its not working yet.

This is what Iā€™ve tried

    if request.method == 'POST':
        bid_form = BidForm(request.POST, listing=listing)
        if bid_form.is_valid():
            new_bid = request.POST["new_bid"]
            current_bid = bid_form.save(commit=False)
            current_bid.user = request.user
            current_bid.save(update_fields=['new_bid'])

AND

    if request.method == 'POST':
        bid_form = BidForm(request.POST, listing=listing)
        if bid_form.is_valid():
            current_bid = bid_form.save(commit=False)
            current_bid.user = request.user
            current_bid.save(update_fields=['listing'])

Referenced from QuerySet API reference | Django documentation | Django and Save your Django models using update_fields for better performance - DEV Community and django - Update only specific fields in a models.Model - Stack Overflow etc

This is the updated details (got rid of the ā€˜biddingā€™)

                            <hr>
                            <p>Current price: ${{ listing.new_bid }}</p>
                            <hr>

Iā€™m still missing something because its not yet working

You have:

This marked line is not needed and does not do you any good.

In that block, you have:

This sets the user field of the Bids object to the person who is currently logged on.

You need to do the exact same thing for the auction field of that same object to set the relationship between the Bids object and the Auction object.

In that same block you have:

You do not want to have that update_fields parameter in your save. Youā€™re creating and adding a new row to the table, you want all fields saved.

Your reference to listing is a reference to:

But, the Auction object does not have an attribute named new_bid, so thereā€™s nothing to display here.

Iā€™ve tried various options based on my understanding of your previous comment

I understand this part, to set the auction field to current bid, however what I am assigning to it has been a bit of back and forth in my head, this is what Iā€™ve tried so far

            current_bid.user = request.user
            current_bid.auction = listing
            current_bid.save()

and

current_bid.auction = bid_item 

For details, I used a previous comment regarding a different post ā€™ > <a href={% url 'listing_detail' watched.id %}>
What object type is listing_detail supposed to display?
What object type is watched ?ā€™ to make this change

<p>Current price: ${{ listing.auction.new_bid }}</p>
<h6>${{ bid_item.auction.new_bid }}</h6>
<h6>${{ listing.bids.new_bid }}</h6>

I tried each respectively, Iā€™m unfortunately still stuck with the same issue of the price not showing

This is correct.

This is a completely different issue from what weā€™ve been discussing so far with your form-submission.

If the form has been submitted correctly and does process as expected, youā€™re redirecting to a different page. The page being rendered is not being rendered by this view - itā€™s being rendered by the view named ā€œlisting_detailā€. You have not yet posted that view here. There is no data from your make_bid view available in the redirected view.

So letā€™s start with addressing which price you want to display?

The Auction model you posted at the top of this thread has a ā€œcurrent_bidā€ field - but itā€™s defined as an integer. Iā€™m not sure I understand what its purpose is.

Your Bids model has a ā€œnew_bidā€ field. But you have an unbounded number of Bids instances for each Auction. (In other words, any individual Auction object may effectively have an unlimited number of Bids objects referring to it.)

So we first need to be clear on what data you want rendered on that page.

Iā€™m sorry, I thought was clear earlier. I want to display the new_bid if the bid is valid (greater than the previous bid). This is the price I meant

The current_bid (Iā€™ve changed the field name to starting_bid) is the first bid that the user that creates the product/listing (E.g, if I list an artwork on the site, I have to put the title, description, the starting bid I want etc). I defined as an integer because I want donā€™t want any of the users to input a decimal digit.

bid_item = Bids.objects.filter(auction=listing).order_by('-new_bid').first()

Yes you were clear.

But now consider the situation.

A person has entered a bid and clicked submit. That bid, assuming itā€™s valid, gets saved to the database and the browser is redirected to a new page. Neither the browser nor the view has any information available to it about any data submission in a form from the previous page. The only data it has available to it is whatā€™s in the database.

So, you have this query:
bid_item = Bids.objects.filter(auction=listing).order_by('-new_bid').first()

This will give you a single instance of a Bids object.

If you have an object of type Bids named bid_item, how do you access the amount of that bid from bid_item?

To access the amount (new_bid) from bid_item

bid_item.new_bid

Correct!

How are you passing bid_item to the template to be rendered?

Is this what you mean?

<p>Current price: ${{ bid_item.new_bid }}</p>

Thatā€™s in the template to be rendered. But, in your view, you have to make data available to the template to be rendered.

How is that done?

        current_bid.auction = listing
        current_bid.save()


        messages.success(request, 'Successfully added your bid')
        context = {
            "bid_form": bid_form,
            "bid_item": bid_item,
            "listing": listing
            } 

        return render(request, 'auctions/details.html', context)

Cool! So itā€™s working now?

If not, please post the complete view.

The price is not yet showing
VIEWS.PY


@login_required
def make_bid(request, listing_id):
    listing = Auction.objects.get(pk=listing_id)
    bid_item = Bids.objects.filter(auction=listing).order_by('-new_bid').first()

    if request.method == 'POST':
        bid_form = BidForm(request.POST, listing=listing)
        if bid_form.is_valid():
            current_bid = bid_form.save(commit=False)
            current_bid.user = request.user
            current_bid.auction = listing
            current_bid.save()


            messages.success(request, 'Successfully added your bid')
            context = {
                "bid_form": bid_form,
                "bid_item": bid_item,
                "listing": listing
                } 

            return render(request, 'auctions/details.html', context)


        else:
            context = {
                "bid_form": bid_form,
                "bid_item": bid_item,
                "listing": listing
                } 

        return render(request, 'auctions/details.html', context)
             
                
    return render(request, 'auctions/details.html', bid_form = BidForm())  

INDEX.HTML

                  <h5>{{ listing.title|truncatewords:3 }}</h5>
                  <h6>${{ bid_item.new_bid }}</h6>
                  <small>{{ listing.description|truncatewords:6 }}</small>

Ok, so follow through the sequence of events.

When are you getting bid_item relative to when you are processing the form submission?

Could you please rephrase? Iā€™m not sure I quite understand.

Do you mean that its the sequence of this that is the problem

as opposed to this, maybe?

            context = {
                "bid_item": bid_item,
                "bid_form": bid_form,
                "listing": listing

Is this part to show the item in the index.html template the right way?

                  <h6>${{ bid_item.new_bid }}</h6>

No, thatā€™s a single statement.

Youā€™re doing a number of things in this view.

  • Get the Auction object
  • Get the current bid
  • Accept a submitted form
  • Validate form
  • Save data
  • Render page

Look at what order these things are occurring, and consider what the values are of all the key data items at each step.