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
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.