Ben P
Ben P

Reputation: 3369

Displaying content from 2 models on a single Django template

I am working with my first Django project and I have printed my first template tag using a view onto my page template. I'd like to display some other database values on my page, but repeating the same process seems wrong.

Here are my two models:

class Drink(models.Model):
    drink_name = models.CharField(max_length=100)
    strength = models.IntegerField(default=0)
    def __str__(self):
        return self.drink_name


class status(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    health = models.IntegerField(default=100)
    strength = models.IntegerField(default=50)
    charisma = models.IntegerField(default=50)

And my view:

from django.shortcuts import render

from .models import Drink
from .models import status

# Create your views here.
def index(request):
    served_drinks = Drink.objects.order_by('strength')
    context = {'served_drinks': served_drinks}
    return render(request, 'tavern/index.html', context)

And my template:

  Hello {{ user.get_username }}, welcome to the tavern.

  <br><br>

  <div class="card-panel teal lighten-3">Grab a drink from the bar</div>
  {% if served_drinks %}
      <ul>
      {% for drink in served_drinks %}
          <li>{{ drink.drink_name }} with a strength of {{ drink.strength }}</li>
      {% endfor %}
      </ul>
  {% else %}
      <p>No drinks are available.</p>
  {% endif %}

Which returns:

Hello admin, welcome to the tavern. 

Grab a drink from the bar
Water with a strength of 0
Wine with a strength of 3
Ale with a strength of 5
Black Ale with a strength of 9

As you can see I've printed out my served_drinks object in the template, but I also want to print out data from the status model on this page too.

I've tried simply adding {{ status.health }} to the template but this does not work. Should I be adding extra information to the index view? If so, what if I want to show this information on many pages?

Upvotes: 2

Views: 90

Answers (2)

Alasdair
Alasdair

Reputation: 308799

Since you're using the render shortcut, you can add whatever you want to the context dict:

from django.contrib.auth.decorators import login_required

@login_required
def index(request):
    served_drinks = Drink.objects.order_by('strength')
    context = {
        'served_drinks': served_drinks,
        'status': Status.objects.get(user=request.user),
    }
    return render(request, 'tavern/index.html', context)

Then you can use {{ status.health }} in the template. Note the login_required decorator is used so that only logged-in users can access the view, otherwise the Status.objects.get() would fail for anonymous users. I would also rename your model from status to Status, so that you do not confuse the Status model with status instances.

However, you don't actually need to add status to the context in this case. You can follow the one-to-one field backwards from user to status:

{{ user.status.health }}

Upvotes: 4

Olzhas Arystanov
Olzhas Arystanov

Reputation: 986

You should pass your status instance to the context of the view as well. For example, let's get a first instance of status model in database:

def index(request):
    served_drinks = Drink.objects.order_by('strength')
    status = status.objects.all().first()
    context = {'served_drinks': served_drinks, 'status': status}
    return render(request, 'tavern/index.html', context)

Now, you can use {{ status.health }} in your template.

Also, try to start your model names with capital letters. So, model Status is better than status. It's just good practices.

Upvotes: 5

Related Questions