0

I have created a Bid model so that type-2 users can bid on some 'Post' created by type-1 users. For achieving this, I made a foreign key for post field in the model 'Bid'.

Actually i wanted to relate the bids to a particular post with auto generated 'id' in the 'post' model. So i placed the get_absolute_url beside Post 'id' in my template. I am new to django and I am not sure whether it works for what i want or not.

How can i relate the bid with post_id to a particular post in the template so that i can get a bid amount placed by various type-2 users for a particular post? I would appreciate helping me solve this.

Here's my code:

Models.py:

class Post(models.Model):

    post_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
    from1 = models.CharField(max_length=20)
    timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)

    objects = PostManager()

    def __str__(self):
        return self.post_id

    def get_absolute_url(self):
        return reverse("posts:detail", kwargs={"id": self.post_id})

    class Meta:
        ordering = ["-timestamp", "-Time"]

class Bid(models.Model):

    bid_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    post = models.ForeignKey(Post, default=uuid.uuid4, related_name='bids' )
    user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True, blank=True, unique=False)
    amount = models.IntegerField()

    def get_absolute_url(self):
        return reverse("accept_bid", kwargs={"bid_id": self.bid_id})

    def __unicode__(self):
        return self.amount

    def __str__(self):
        return self.amount

forms.py:

class BidForm(forms.ModelForm):
    // Defined a post field as ModelChoiceField
    post = forms.ModelChoiceField(queryset= Post.objects.all(), label="Post", widget=forms.RadioSelect(), initial=0)
    amount = forms.IntegerField(help_text='Place the bid for a Post')

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super(BidForm, self).__init__(*args, **kwargs)
        self.fields['post'].queryset = Post.objects.all

    class Meta:
        model = Bid
        fields = ["amount"]

views.py:

def live_bid_truck(request, **kwargs):
    if request.method=='post':
        form = BidForm(request.POST or None)

        if  form.is_valid():
         bid = form.save(post)
         bid = form.save(commit=False)
         print(form.cleaned_data.get('amount'))
         bid.user = request.user
         bid.post = form.cleaned_data['post'] // Set my post here


         bid.save()
    else:
        form=BidForm()
        post_queryset = Post.objects.all()
        context = {
        "post_queryset": post_queryset, 
        "title": "List",
        'form': form,

    }
        return render(request, 'loggedin_truck/live_bid_truck.html', context)

live_bid_truck.html

{% for post in post_queryset %}
<table class="table table-striped, sortable">
    <thead>
        <tr>

            <th>Load No.</th>
            <th>From</th>
        </tr>
    </thead>
    <tbody>
        <tr> // Returns the post_queryset with radio buttons
            <td >{{form.post}} </td>
            <td>{{ post.from1 }}</a><br/></td>
        </tr> 
    </tbody>
</table>
<table class="table table-striped, sortable "  style="margin-top: 10px">
    <thead>
        <tr>
            <th> Amount</th>
        </tr>
    </thead>
    <tbody>
        <tr>     
            <form class="nomargin" method='POST' action='' enctype='multipart/form-data'>{% csrf_token %}
            <td>{% render_field  form.amount  class="form-control" %}</td>
        </tr>
     </tbody>
 </table>

<input type='submit' value='Post Bid'/></form>

{% endfor %}

Update - 1:

Views.py:

def live_bids(request):
    post_queryset = Post.objects.all().prefetch_related('bids')
    bid_queryset = Bid.objects.all().order_by('amount')

    context = {
        "post_queryset": post_queryset,
        "bid_queryset": bid_queryset,
        "title": "List",
    }
    return render(request, 'loggedin_load/live_bids.html', context)

live_bids.html:

{% for post in post_queryset %}
{{post.id}}
{% for bid in post.bids.all %}
{{bid.amount}}
{% endfor %}
{% endfor %}
sumanth
  • 751
  • 2
  • 15
  • 34
  • You probably want to show us your form. Is it a ModelForm you are using? – wobbily_col Jul 19 '16 at 16:41
  • 2
    @wobbily_col. I updated my code. Yes, i am using model form. I haven't included any post field in my model form. If required, How can i do it? – sumanth Jul 19 '16 at 16:49
  • @wobbily_col. I stuck at this point from last 2 days. i couldn't able to move forward. Can you please help me in solve this one. – sumanth Jul 20 '16 at 09:32
  • Try rendering the form in your template as {{ form }} instead of {% render_field form.amount class="form-control" %}. (Sorry I am kind of busy to post a proper reply). – wobbily_col Jul 20 '16 at 10:51

1 Answers1

5

If I understood correctly, the goal is to be able to list the related bidders/bids on the post? If so, then you can use select_related (if you're selecting parents from child) of prefetch_related (if you're doing a reverse lookup)

1) First of all in your Bid model better related_name would be "bids", like so;

post = models.ForeignKey(Post, default=1, related_name='bids' )

2) Secondly inside def live_bid_truck(request): make the post query like this so that you would get all the related objects in one database hit.;

Post.objects.all().prefetch_related('bids') 

3) Then in your template you can use can access the related bids for the post

{% for bid in post.bids.all %} // In your case post is obj
    {{ bid }}  // Access whatever you need from the bid like {{ bid.user }}
{% endfor %}

You should be able to call post.bids.all and receive values even without prefetch by just following the backward relation. If you're not getting any values, then you probably are not setting them properly. prefetch_related helps with the performance as the number of posts increase.


FROM YOUR CODE

In your BidForm there is no reference to the post and I don't know if you have it in your custom save() method or not. When you save this form as it is, post_id will be the default value 1

# NO REFENCE TO post
class BidForm(forms.ModelForm):

 class Meta:
    model = Bid
    fields = ["amount"]  

Also in your view you don't set the post either.

def live_bid_truck(request):

    form = BidForm(request.POST or None)

    if  form.is_valid():
        bid = form.save(commit=False)

        print(form.cleaned_data.get("amount"))
        bid.user = request.user # YOU SET THE USER 
        bid.post = ?? # YOU DON'T SET THE POST HERE EITHER, 
                      # SO ALL YOUR BIDS HAVE THE DEFAULT POST id = 1
                      # DO YOU ACTUALLY HAVE POST with id = 1?

        bid.save()

        # WHAT HAPPENS IF YOU PRINT BID POST ID HERE ?? 
        # CHECK HERE IF YOU REALLY HAVE THE RELATED POST ID.
        print(bid.post.id)
Tiny Instance
  • 2,351
  • 17
  • 21
  • After i placed an amount in my BidForm in live_bid_truck.html, the value is stored in my database. But i couldn't able to get the amount value for a particular post in live_bids.html. I updated my code in the question. Could you once again help me!!! – sumanth Jul 22 '16 at 08:27
  • In you update I see you're using `prefetch_related` which should be `select_related` as you're trying to follow ForeignKey relations.See [this question for the difference](http://stackoverflow.com/questions/31237042/whats-the-difference-between-select-related-and-prefetch-related-in-django-orm) – Tiny Instance Jul 22 '16 at 08:50
  • Also in your model, `related_name` still looks like *"posts"*. If the `related_name` is still *"posts"* then use `select_related('posts')` – Tiny Instance Jul 22 '16 at 08:53
  • 1
    As it is Reverse ForeignKey relationship i used prefetch_related. Any way i don't know why i couldn't able to get amount value in live_bids.html. – sumanth Jul 22 '16 at 10:24
  • Assuming you have this `post = models.ForeignKey(Post, default=1, related_name='bids' )` in your `Bid` model, could you please try `Post.objects.all().select_related('bids')` – Tiny Instance Jul 22 '16 at 10:42
  • when i do this it raising an error: Invalid field name(s) given in select_related: 'bids'. Choices are: user – sumanth Jul 22 '16 at 10:44
  • I'm sorry, I guess I'm making a mistake with the second `select_related` . Even if you don't prefetch, when you access it via `post.bids.all`, although not efficient it should list the bids. What do you get, empty values or an error? – Tiny Instance Jul 22 '16 at 11:26
  • When i use select_related: it returns - FieldError at /live_bids/ Invalid field name(s) given in select_related: 'bids'. Choices are: user With prefetch_related: emptyvalues – sumanth Jul 22 '16 at 12:17
  • @Tiny_Instance I am new to django and it is hard to move further. Could you help me to solve why i getting an error when i use select_related & empty values when i use prefetch_related – sumanth Jul 23 '16 at 12:54
  • In your `BidForm` you only have `amount` field. And in your view you only assign `user`. Are you sure are also assigning the related `post` ForeignKey and saving? If you don't have `post` in your form then you need to assign it like you did the `instance.user = request.user` before saving. You're getting empty values, probably because you forgot to assign and save. – Tiny Instance Jul 23 '16 at 13:55
  • so for associating a post to the bids, in my live_bid_truck.views should I need to add instance.post_id = request.post_id? – sumanth Jul 23 '16 at 14:03
  • in my Post model, instead of autogenerated id i included post_id as UUIDField for associating the post field in Bid Model. So, how can i write to associate a particular post_id to bids in live_bid_truck view? – sumanth Jul 23 '16 at 14:08
  • `Bid` model has a `post` field, you need to set it to the correct post, otherwise all the bids will belong to `post` with id=1 because of the `default=1` value. You need to know which `post` the user is bidding for inside live_bid_truck right? – Tiny Instance Jul 23 '16 at 14:11
  • Yes(These letters are for sake of stackoverflow) – sumanth Jul 23 '16 at 14:14
  • I updated the answer, added extra comments tried to show the possible flaws. Please check all the comments and I hope these help. – Tiny Instance Jul 23 '16 at 23:28
  • I used ModelChoiceField for 'post' field in forms.py as in my updated code. Now, i am again facing trouble for how can i render this in my template. I use a custom radio button in my template and with {% for choice in form.post.field.queryset %} it return the whole queryset in each row of my table, and with {% for choice in form.post.field.choices %} it raising an error object of type 'method' has no len() may because of using UUID field. And i am not sure how can i save it in my views also as you mentioned in your updated answer. Could you help me in solving this one more time – sumanth Jul 25 '16 at 17:57