How do I get the current item in the model from the request?

Question:

When a submit button is clicked, I want to be able to know what item the user was on. The button would be on an item’s page that the user gets taken to when they click on an item. This button is is part of a django form (PlaceBid) that allows the user to bid for the item. So I want to be able to update what the item’s highest bid is if the bid is higher than the current highest. This means that I need to know what item the user was viewing.

I also want to save the bid in a model called Bid and in that model I also need to know what listing the bid is for.

So how do I get the correct item from the model?

The models:

  • Listing() is the model for the item

  • Bid() is the model for the bid

views.py:

def bid(request):
    if request.method == 'POST':
        form = PlaceBid(request.POST)
        if form.is_valid():
            current = Listing.objects.get(pk=request.id) # my attempt to get the current item
            highest = current.highest_bid
            if form.cleaned_data['bid'] < highest:
                obj = Bid()
                obj.price = form.cleaned_data['bid']
                obj.item = current
                obj.user = User.objects.get(pk=request.user.id)
                obj.save()
                current.highest_bid = form.cleaned_data['bid']
                current.save()
                return HttpResponseRedirect(request.path_info)

forms.py:

class PlaceBid(forms.Form):
    bid = forms.FloatField(required=False, widget=forms.NumberInput(attrs={
        'class': 'bid',
    }))

html:

<form action=" {% url 'bid' %} " method="post">
    {% csrf_token %}
    {{ bidForm }}
    <input type="submit" value="Place Bid" class="place-bid">
</form>
Asked By: tices

||

Answers:

You won’t get it from the request. Hide it in the form.

class PlaceBid(forms.Form):
    bid = forms.FloatField(required=False, widget=forms.NumberInput(attrs={
        'class': 'bid',
    }))
    listing_id = forms.IntegerField(widget=forms.HiddenInput())

Then in your method that displays the form (I’m using function-based views)

def view_listing(request, listing_id)

   listing = Listing.objects.get(id=listing_id)

   myForm = PlaceBid(initial={"listing_id" : listing_id})

   return render("whatever.html", {"listing" : listing, "form" : form })

I suppose another option would be to stash the listing_id in the session, but I try to avoid that.

Answered By: Chris Curvey

With the limited code shown, I can only assume at this point that you have a bidding form for each item in a forloop. Example:

{% for item in items %}
    ...
    <form action=" {% url 'bid' %} " method="post">
        {% csrf_token %}
        {{ bidForm }}
        <input type="submit" value="Place Bid" class="place-bid">
    </form>
    ...
{% endfor %}

But here are two methods that can be done…

  1. Use a hidden input field to hold the item object id then retrieve that field name on the server to get the item’s id value.

    # html
    <form action=" {% url 'bid' %} " method="post">
        {% csrf_token %}
        {{ bidForm }}
        <input type="hidden" value="{{ item.id }}" name="item_id">
        <input type="submit" value="Place Bid" class="place-bid">
    </form>
    
    
    # views.py
    def bid(request):
        if request.method == 'POST':
            form = PlaceBid(request.POST)
            if form.is_valid():
                item_id = request.POST.get('item_id', None)
                current = Listing.objects.get(id=item_id)
                # rest of code follows...
    
  2. Pass the item’s id via the url. (My recommendation)

    # html
    <form action=" {% url 'bid' item.id %} " method="post">
        {% csrf_token %}
        {{ bidForm }}
        <input type="submit" value="Place Bid" class="place-bid">
    </form>
    
    
    # urls.py 
    # update the necessary url to accept an id
    path('bid/<int:id>/', views.bid, name='bid')
    
    
    # views.py
    def bid(request, id):
        if request.method == 'POST':
            form = PlaceBid(request.POST)
            if form.is_valid():
                current = Listing.objects.get(id=id) # id passed to this method used here...
                # rest of code follows...
    

Also, instead of using Listing.objects.get(id=id), I’d suggest using get_object_or_404(Listing, id=id) as this will handle any potential error that Listing.objects.get(id=id) will throw.

Answered By: Damoiskii
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.