current_bid = Auction.objects.get('current_bid)
Possible?
current_bid = Auction.objects.get('current_bid)
Possible?
I suggest you try that in the Django shell to see what you get.
What didnât work? (You obviously jumped way ahead of where I was with my last response, so I donât know what you just tried.)
Tried this
def clean_new_bid(self):
new_bid = self.cleaned_data['new_bid']
current_bid = Auction.objects.get('current_bid')
Ok, I suggested you try out that query in the Django shell, not by updating your view with it.
Had you tried just that query in the shell, you would have seen that it would not retrieve the information that you need.
Back in your post at How to get highest bid in an auction bidding site Django - #19 by Theresa-o you show a query on the Auction model.
The query you need to write needs to get the proper instance of that model, and then access the current_bid
field of that model.
If necessary, review the docs at:
Along with the examples at Writing your first Django app, part 3 | Django documentation | Django.
And if youâre not familiar with the Django shell, you should become familiar with it - see Writing your first Django app, part 2 | Django documentation | Django.
current_bid = Auction.objects.get(current_bid=current_bid)
On my windows shell âNameError: name âcurrent_bidâ is not definedâ
I donât know what to do at this point.
Tried .filter() but still same
In your view, you have:
So in this case, youâre retrieving a specific Auction object - the one for which you want to submit a bid - and likely the one from which you want to access the current bid.
Question 1: If you have an object of type Auction named auction
, how do you access the current_bid
value in that instance?
Now, you have access to the listing_id
in the view, which doesnât help you in the form. You still need to pass either the listing_id
, or the Auction object itself, into the form.
You have a couple different ways of accomplishing that. My personal preference for that would be to pass it as a named parameter to the form.
In the view:
bid_form = BidForm(request.POST, auction=auction)
This passes a new named parameter into the form named auction
.
So then you need to retrieve this parameter in the form. This can be done by adding an __init__
method to the form.
Example:
def __init__(self, *args, **kwargs):
self.auction = kwargs.pop('auction', None)
super().__init__(*args, **kwargs)
You then have a variable named auction
(accessed as self.auction
in that class) that accesses whatever value was passed into the form constructor.
Hi Ken, thank you for the help so far.
I have been reading up on the __init__
method (this is my first time seeing it),
So, I searched online for how to access the starting_bid using âself.auctionâ and I have so far tried this (referencing this python - get request data in Django form - Stack Overflow);
def clean_new_bid(self):
new_bid = self.cleaned_data['new_bid']
starting_bid = self.auction.starting_bid
This throws the below error
âNoneTypeâ object has no attribute âstarting_bidâ
I also saw a different post on how to reference an init variable Django ModelForms __init__ kwargs create and update - Stack Overflow and Pass data to django form's field clean method - Stack Overflow
def clean_new_bid(self):
new_bid = self.cleaned_data['new_bid']
starting_bid = Auction.objects.get(starting_bid = self.auction)
This threw this error
Field âstarting_bidâ expected a number but got <Auction: Brain/Cloud>.
Brain/Cloud is the name/title of my post.
How do I reference self.auction in this scenario to get the starting_bid to use in the clean function to compare with new_bid?
I really did try to research in order to come up with a solution by myself but Iâve been stuck since and would appreciate your input. Thank you.
I need to see your current view and form for this. I know thereâs a lot of work that has been done, and I canât piece together what the current code looks like from the various responses here.
These two parts (view and form) work together. The view needs to pass either the auction object, or the id for the auction object to the form. What the view passes to the form will determine what the form needs to do with it.
The NoneType
error is an indication that you are not passing (or retrieving, depending) the auction object to the form from the view.
The TypeError is telling you that youâre trying to assign the complete Auction object to starting_bid
, not the numeric field. (Also, I have a feeling that your query is wrong - you want to do a get based on the key, not the value of the bid. It appears to me that youâre mixing up the process of retrieving an object and getting the values from that object.)
This is the what I have so far
VIEWS.PY
def make_bid(request, listing_id):
auction = Auction.objects.get(pk=listing_id)
bid_item = Bids.objects.filter(auction=auction).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 = auction.starting_bid
else:
bid = bid_item.new_bid
if request.method == 'POST':
bid_form = BidForm(request.POST, auction=auction)
if bid_form.is_valid():
user = request.user
bid_count = Bids.objects.filter(auction=listing_id).count()
new_bid = request.POST['new_bid']
Bids.objects.create(auction=auction, user = user, new_bid = new_bid)
messages.success(request, 'Successfully added your bid')
return HttpResponseRedirect(reverse("listing_detail", listing_id=listing_id))
else:
bid_form = BidForm(request.POST)
context = {
"bid_form": bid_form,
"bid": bid,
"bid_item": bid_item,
"auction": auction
}
return render(request, 'auctions/details.html', context)
return render(request, 'auctions/details.html', bid_form = BidForm())
FORMS.PY
class AuctionForm(forms.ModelForm):
class Meta:
model = Auction
fields = ['title', 'description', 'starting_bid']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.Textarea(attrs={'class': 'form-control'}),
'starting_bid': forms.NumberInput(attrs={'class': 'form-control'}),
}
class BidForm(forms.ModelForm):
class Meta:
model = Bids
fields = ['new_bid']
labels = {
'new_bid': ('Bid'),
}
def __init__(self, *args, **kwargs):
self.auction = kwargs.pop('auction', None)
super().__init__(*args, **kwargs)
def clean_new_bid(self):
new_bid = self.cleaned_data['new_bid']
starting_bid = Auction.objects.get(starting_bid = self.auction)
if new_bid <= starting_bid:
raise ValidationError("New bid must be greater than the previous bid")
return new_bid
From this line in the view:
youâre passing an actual Auction object into the form.
If I have an object of type Auction
named auction
, how do I access the starting_bid
field of auction
?
Once you understand that, then you can change:
to the appropriate syntax.
(If necessary, review page 2 of the tutorial, including the section at Playing with the API.
Also, from your view:
The three lines marked with ***
are unnecessary and can be removed.
The general flow is:
if form.is_valid():
new_object = form.save(commit=False)
new_object.field = "some updated value"
new_object.save()
Also see Creating forms from models | Django documentation | Django
Reviewing this line in the page
# Access model field values via Python attributes.
>>> q.question_text
"What's new?"
I adjusted my code to
def clean_new_bid(self):
new_bid = self.cleaned_data['new_bid']
starting_bid = self.auction.starting_bid
Just want to explain my logic, using the first statement about accessing auction through âself.auctionâ and this line â>>> q.question_textâ which accesses the field âquestion_textâ through the variable âqâ.
Unfortunately, still missing it because I get the Nonetype error still.
Thank you, this has been updated
if bid_form.is_valid():
accepted_bid = bid_form.save(commit=False)
accepted_bid.new_bid = bid_form.cleaned_data['new_bid']
accepted_bid.user = request.user
accepted_bid.save()
Ok, Iâm missing something here regarding your auction
object. I see no reason at the moment how/why you would be getting a NoneType
error with it.
Can you post the complete error?
Regarding your new view:
The marked line is unnecessary - thatâs the data that is coming in from the form. You donât need to do anything with it. The reason you have the accepted_bid.user
line following it is because user
is not a field in the form.
âNoneTypeâ object has no attribute âstarting_bidâ
Request Method: | POST |
---|---|
Request URL: | http://127.0.0.1:8000/make_bid/2 |
Django Version: | 4.0.2 |
Exception Type: | AttributeError |
Exception Value: | âNoneTypeâ object has no attribute âstarting_bidâ |
C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\handlers\exception.py
, line 47, in inner
âŚ
Local vars
C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\core\handlers\base.py
, line 181, in _get_response
âŚ
Local vars
C:\Users\USER\AppData\Local\Programs\Python\Python310\lib\site-packages\django\contrib\auth\decorators.py
, line 21, in _wrapped_view
âŚ
Local vars
C:\Users\USER\Downloads\commerce\commerce\auctions\views.py
, line 146, in make_bid
O, that makes sense. Thanks
Itâs generally more helpful to get the error message from the console in which this is being run than whatâs displayed on the web page, but we can try to work with this.
Iâm guessing from context that line 146 from the referenced error message is the marked line here:
The situation causing that issue is here:
You should not be recreating the form again. Youâre creating your instance of the form before the is_valid
call, which makes it available on both sides of the condition. (The actual error is that, in recreating it here, youâre not passing the auction
variable to the constructor. But you shouldnât be recreating it at all.)
I have one final problem bugging me, the bid price is not updating on the page when the user types it in
<hr>
<p>Current price: ${{ listing.bid }}</p>
<hr>
Ok
Context please? I donât see that in any of the previous templates youâve posted nor a reference to it in the view youâve been working on.
The new bid amount that the user inputs should show on the homepage, so Iâm trying to pass in the bid amount into my index.html file
INDEX.HTML
<h5>{{ listing.title|truncatewords:3 }}</h5>
<h6>${{ listing.bid }}</h6>
<small>{{ listing.description|truncatewords:6 }}</small>
bid is gotten from this VIEW
I need to see the view that is rendering the index.html template.