stin
stin

Reputation: 93

Django 2.1, How to show Foreign key values in template?

Sorry for my English level and my model is not good.

Now, i'm stuck showing value in templates.

purchaseinfo/models.py

class Status(Models.model):         
    type = models.CharField(max_length=30)

class PurchaseInfo(models.Model):
    purchase_id = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    purchase_name = models.CharField(max_length=30)
    .....
    type = models.ForeignKey(Status,on_delete=models.PROTECT)

customlogin/views.py

def purchaseHistory(request):
    history = PurchaseInfo.objects.filter(purchase_id=request.user).values()
    return render(request,'customlogin/purchaseHistory.html',{'history':history})

customlogin/purchaseHistory.html

{% for i in history %}
<tr>
    <td>{{i.purchase_name}}</td>
    <td>{{i.product_price}}</td>
    ......
    <td>{{i.type}}</td>   <---- Here, Only this cannot show
</tr>
{% endfor %}

In templates, Other things work well. But {{i.type}} cannot show.

class Status's values : before deposit, Confirmation of payment and so on.

before deposit is base value. So i want to show base value in templates.

How can show the {{i.type}} in templates?? T.T

Upvotes: 1

Views: 224

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476624

The error is due to the fact that you call the QuerySet with .values() at the end, and therefore you will obtain a QuerySet of dictionaries. Foreign keys are not resolved, but you fetch the corresponding primary key.

It is better to use .values() only when you really need it: when you want to fetch a subset of columns. Normally it is better to fetch model objects, since then the "behavior" you attached to the objects remains the same.

def purchaseHistory(request):
    # no .values()
    history = PurchaseInfo.objects.filter(purchase_id=request.user)
    return render(request,'customlogin/purchaseHistory.html',{'history':history})

Now that we have made a QuerySet of PurchaseInfo objects, in the template, i.type will be Status object. This will render the Status object, by calling the str(..) object. By default this will look like Status object (123) with 123

You can however access fields from this Status object in the template as well:

{% for i in history %}
<tr>
    <td>{{ i.purchase_name }}</td>
    <td>{{ i.product_price }}</td>
    ......
    <td>{{ i.type.type }}</td>
</tr>
{% endfor %}

given the name of the field is type, so if that field contains as value 'Before deposit', it will render that string.

Since we here will fetch the related Status object for each PurchaseInfo object in the queryset, it is better to fetch it in one query, like:

def purchaseHistory(request):
    # no .values()
    history = PurchaseInfo.objects.filter(purchase_id=request.user).select_related('type')
    return render(request,'customlogin/purchaseHistory.html',{'history':history})

You might want to override the __str__ method in the Status class, such that this is the "standard" way of rendering the status, like:

class Status(Models.model):         
    type = models.CharField(max_length=30)

    def __str__(self):
        return self.type

In that case {{ i.type }} in the template will suffice.

Upvotes: 2

Related Questions