Ok! Man it sure makes my day seeing you in my notifications still gung ho to help
So, I’ve fixed my multi dict key error and I have the ability to enter a bid or enter a comment, both form fields on the page, working great (for now. LOL).
Here is my current problem:
I have a third Django form on the page, hidden, submitting a value with a button: Add to Watchlist. This fires a model signal to save this item to someone’s watchlist. This works right now. It isn’t querying the model to see if it’s already on or able to take it off, but it is sending it and saving it. I’m pausing there. I was just trying to get to the place where I could save it. Now it is doing that. But I’m sort of stuck here because the actual model/object isn’t looking how I thought it would.
I am really worried I’m mucking up my models because I’m struggling to understand ManyToMany or ForeignKey and when the right time to implement is… poking around on the net it seems using a Watchlist Model in django, people use both! I’ve implemented mine using ForeignKeys for the User whose watchlist it is, and the item on the list.
Here are my problems:
When I’m in the admin panel, and click on “Watchlists”, I’m expecting to see a list of users, I click on the user, it lists all the items, says “yes” or “no” essentially. But instead, I see “Watchlist objects” and when I click into one, it shows a dropdown field of all the other auctions on the site. I just am not getting this. I feel i’m slightly grasping templating and django variables and even views stuff… slightly. but the models are difficult for me. I’ll post my models and view below. Thanks again Ken, if you want I’ll send you some Christmas cookies we got some peanut butters baking right now! haha
My View:
def listing_view(request, listing_id):
item_listing = Listing.objects.get(pk=listing_id)
minimum_bid = item_listing.starting_bid # set minimum bid at starting bid, then if bids exist, adjust minimum bid to max of bids + $1
bid_message = ''
current_user = User.objects.get(username=request.user)
watch_message = ''
comments = item_listing.comments.all()
new_comment = None
comment_form = CommentForm()
watchform = WatchForm()
bidform = BidForm()
total_bids = item_listing.bids.all()
total_length = len(total_bids) # total number of bids for given item/listing
if total_length == 0:
print('its empty')
# it's empty, leave minimum bid as is.
else:
highest = (item_listing.bids.latest('bid'))
minimum_bid = highest.bid + 1
if request.user == highest.bid_author:
bid_message = 'Your bid is the current highest bid.'
if request.method == "POST":
if 'comment_body' in request.POST: # if comment is being posted, do this
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
# Create Comment object but don't save to database yet
new_comment = comment_form.save(commit=False)
# Assign the current post to the comment
new_comment.comment_listing_id = item_listing
new_comment.comment_author = request.user
# Save the comment to the database
new_comment.save()
comment_form = CommentForm()
if 'bid' in request.POST: # if bid is being posted, do this
bidform = BidForm(data=request.POST)
submitted_bid = request.POST['bid']
submitted_bid = float(submitted_bid)
print('printing bidform bid:')
print(submitted_bid)
if submitted_bid < minimum_bid:
errormessage = 'Bid is too low!'
print(errormessage)
return render(request, "auctions/listing_page.html", {
"item":item_listing,
"bid_form":bidform,
'bid_amount':minimum_bid,
'num_of_bids':total_length,
'message':errormessage,
'bid_message':bid_message,
'watch_message':watch_message,
'watch_form':watchform
})
else:
if bidform.is_valid():
newbid = bidform.save(commit=False)
newbid.bid_author = request.user
print('bidform is valid!')
newbid.auction_id = item_listing
newbid.save()
bidform = BidForm()
minimum_bid = submitted_bid+1
highest = (item_listing.bids.latest('bid'))
if request.user == highest.bid_author: # give user update on their bid, let them know they are in the lead.
bid_message = 'Your bid is the current highest bid.'
total_bids = item_listing.bids.all() # re do the math of total bids, update number
total_length = len(total_bids)
if 'watchlist_button' in request.POST:
w = WatchForm(data=request.POST) #get the item ID
w = watchform.save(commit=False)
w.watchlist_user = request.user # assign the user to it.
w.save()
watch_message = 'This item is on your watch list'
watchform = WatchForm()
watch = Watchlist()
else:
bidform = BidForm()
comment_form = CommentForm()
return render(request, "auctions/listing_page.html", {
"item":item_listing,
"bid_form":bidform,
"comments":comments,
"newcomment":new_comment,
"comment_form":comment_form,
'num_of_bids':total_length,
'bid_message':bid_message,
'bid_amount':minimum_bid,
'watch_message':watch_message,
'watch_form':watchform
})
Models:
class Watchlist(models.Model):
watchlist_user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_watchlist')
item = models.ForeignKey(Listing, null=True, on_delete=models.CASCADE, related_name='watchlist')
class User(AbstractUser):
user_comments = models.ManyToManyField('Comment', blank=True, related_name="user_comments")
user_auctions = models.ManyToManyField('Listing', blank=True, related_name='auctions')
## comments / deprecated fields below
# user_bids = models.ManyToManyField()
# user_watchlist = models.ForeignKey('Listing', null=True, on_delete= models.CASCADE, related_name='watchlist')
# user watchlist could be a model of its own...
# watchlist holds a field for the user that owns the watchlist, with all items that are on the watchlist.
class Listing(models.Model):
auction_categories = [
("FASHION", "Fashion"),
("TOYS", "Toys"),
("ELECTRONICS", "Electronics"),
("HOME", "Home"),
("SHOES", "Shoes"),
("OTHER", "Other",)
]
listing_author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user_listings")
listing_title = models.CharField(max_length=80)
listing_description = models.CharField(max_length=800)
starting_bid = models.FloatField()
listing_image = models.URLField(default='https://tinyurl.com/yjzvdy7t')
category = models.CharField(max_length=80, choices=auction_categories)
listing_comments = models.ManyToManyField('Comment', blank=True)
listing_bids = models.ManyToManyField('ListingBids', blank=True, related_name='bid_list')
def __str__(self):
return f"Listing #{self.id}: {self.listing_title}, starting bid is ${self.starting_bid}. Category: {self.category}\
\n Listing Image {self.listing_image} Listing Description {self.listing_description}"
This time I’ll include my template as well, don’t think that’ll help here but you’re the wizard!
{% extends "auctions/layout.html" %}
{% block body %}
<div class="listing-heading-div">
<h1>
Listing: {{item.listing_title}}
</h1>
</div>
<div class="container-fluid">
<div class="row pt-1" id="listing-image-div">
<img src="{{item.listing_image}}" width="300" height="300">
</div>
<div class="row pt-1" id="item-description-div">
<h6>{{item.listing_description}}</h6>
</div>
<div class="row pt-2" id="bid-div">
<div class="listing-message-div">
{% if message %}
{{ message }}
{% endif %}
<br>
</div>
<div>
<br> <br><h2>${{bid_amount|floatformat:2 }}</h2>
</div>
</div>
<div class="row pt-2" id="num-of-bids-div">
{{ num_of_bids }} bid(s) so far. {% if bid_message %} {{bid_message}} {% endif %}
</div>
<div class="row pt-2" id="bid-field-div">
<form method="POST">
{{ bid_form }}
{% csrf_token %}
<div class="col-2">
<input type="submit" value="Submit Bid" class="btn btn-primary">
</div>
</form>
<div class="col-2">
<form method="POST">
{{ watch_form.as_hidden }}
{% csrf_token %}
<button type='submit' name='watchlist_button' value="{{ item.id }}" class="btn btn-primary">Add to Watchlist</button>
</form>
{% if watch_message %}
{{ watch_message }}
{% endif %}
</div>
</div>
<div class="row pt-2" id="listing-page-details-div">
<h2>
Details
</h2>
</div>
<div class="row" id="listing-page-details-list">
<ul>
<li>
Listed by: <a href="{% url 'user_listings' listing_owner=item.listing_author %}">{{ item.listing_author }}</a>
</li>
<li>
Category: <a href="{% url 'category_detail' category=item.category %}">{{ item.category|lower|capfirst }}</a>
</li>
</ul>
</div>
<div class="col-2 pt-4 pl-5">
</div>
<div class="col-6 pt-5">
</div>
<div class="col-3">
</div>
</div>
<div class="commentdiv">
<br>
variables on this page:
<br>
"newcomment"
"comment_form"
<br>
<h1>Comments:</h1>
{% for comment in comments %}
<div class="individualcomment">
{{ comment.comment_author| default:"deleted_user" }}
<br>
{{ comment.comment_date}}
<br>
{{ comment.comment_body}}
<br><br>
</div>
{% empty %}
{% endfor %}
<br>
<br>
<h2>Leave a Comment:</h2>
<br>
<form method="POST">
{{ comment_form.comment_body }}
{% csrf_token %}
<br><br>
<input type="submit" value="Submit" class="btn btn-primary">
</form>
</div>
{% endblock %}
ps. I also think my listing model is messed up as well because when I go into both users in the admin their “user auctions” both say all the listings, even though only one user listed them and is the listing author in the sqlite file. So if user_id “2” is the auction author in the sqlite table why are all the listings listed on all user page as user auctions? I feel like Beaker after a bad experiment…
I’ll include an image that shows clearly what I mean in the admin view as well.