Lesnie Sncheider
Lesnie Sncheider

Reputation: 375

Reverse lookup value of ForeignKey (Child to Parent)

I'm in need of accessing a value the reverse way using ForeignKey. I want to go from child model Category to parent model Post and grab the value title into my template

I've tried category.posts.title but it isn't showing any success for me.

The main purpose of this is to create a <div> for each Category and list the blog posts with that category down below.

Models:

class Category(models.Model):
    name = models.CharField(max_length=30)

class Post(models.Model):
    slug = models.SlugField(max_length = 250, null = True, blank = True)
    title = models.CharField(max_length = 250, default="Blog Post")
    body = models.TextField()
    created_on = models.DateTimeField(null=True)
    last_modified = models.DateTimeField(null=True)
    categories = models.ForeignKey('Category', related_name='posts', default="2", unique=False, on_delete=models.CASCADE)

View:

def blog_index(request):
    posts = Post.objects.all().order_by('-created_on')
    categories = Category.objects.all()
    context = {
        "posts": posts,
        "categories": categories,
    }
    return render(request, "blog_index.html", context)

Template

<div class="row">
<div style="padding: 0px;" class="col l12">
    {% for category in categories %}

<div class="col l3">
    <div style="background-color: white; box-shadow: 0 1px 15px 1px rgba(62,57,107,.07); border-radius: .6rem;" class="card ">
        <div class="card-body text-center">
            <div class="mb-4 pb-3"><i class="ti-briefcase text-muted font-40"></i></div>

            <h5 class="mb-3"> <a href="{% url 'blog_category' category %}">{{ category.name }}</a></h5>

            <div><a class="d-inline-flex align-items-center text-danger" ><a href="{% url 'blog_detail' category.name category.posts.slug category.posts.pk %}">{{ category.posts.title }}</a><i class="material-icons">
                keyboard_arrow_right
                </i></a></div>

        </div>
    </div>
</div>
{% endfor %}

Upvotes: 0

Views: 119

Answers (2)

Iain Shelvington
Iain Shelvington

Reputation: 32274

You need to loop over the posts in each category

{% for post in category.posts.all %}
    <a href="{% url 'blog_detail' category.name post.slug post.pk %}">{{ post.title }}</a>
{% endfor %}

You should also use prefetch_related on your categories queryset to reduce the number of DB queries you make when you access category.posts.all as you no longer need your posts queryset

def blog_index(request):
    categories = Category.objects.annotate(
        post_count=Count('posts')
    ).prefetch_related('posts')
    context = {
        "categories": categories,
    }
    return render(request, "blog_index.html", context)

Added the annotation for getting the count of posts for each category

{% category.post_count %}

Upvotes: 1

Sergey Pugach
Sergey Pugach

Reputation: 5669

As far as one Category can have multiple posts you would need to iterate over them:

category.posts.all()

In template:

{% for category in categories %}
    {{ category.name }}
    { % for post in category.posts.all %}
        {{ post.title }}
    {% endfor %}
{% endfor%}

Upvotes: 2

Related Questions