Vincent Roye
Vincent Roye

Reputation: 2851

How to return all the distinct foreign keys in a Django view?

Here is my model.py:

class Category(models.Model):
    name = models.CharField(max_length=50, unique=True)
    description = models.CharField(max_length=255, default='')

    def __str__(self):
        return "%s" % (self.name)


class SubCategory(models.Model):
    name = models.CharField(max_length=50, unique=True)
    description = models.CharField(max_length=255, default='')
    category = models.ForeignKey(Category, on_delete=models.CASCADE)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['name']

And my view.py:

def home(request):
    context = {
        'home_page': "active",
        'categories': SubCategory.objects.order_by('category').distinct('category').values_list('category'),
    }
    return render(request, 'candidates/home.html', context)

and my template:

<ul>
        {% for category in categories %}
            <li>{{ category }}</li>
        {% endfor %}
    </ul>

and instead of seing the Category names, I see their ID

enter image description here

How can I get their names?

Thanks

Upvotes: 1

Views: 496

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477881

You should use the name of the category, so:

def home(request):
    context = {
        'home_page': "active",
        'categories': SubCategory.objects.order_by('category__name').distinct('category__name').values_list('category__name', flat=True),
    }
    return render(request, 'candidates/home.html', context)

That being said, querying the Subcategory does not make much sense. You can get a list of Categorys with:

def home(request):
    context = {
        'home_page': "active",
        'categories': Category.objects.order_by('name'),
    }
    return render(request, 'candidates/home.html', context)

Or if you want only Categorys with at least one subcategory, you can work with:

def home(request):
    context = {
        'home_page': "active",
        'categories': Category.objects.filter(subcategory__isnull=False).order_by('name').distinct(),
    }
    return render(request, 'candidates/home.html', context)

You can simplify the __str__ of the Category with:

class Category(models.Model):
    name = models.CharField(max_length=50, unique=True)
    description = models.CharField(max_length=255, default='')

    def __str__(self):
        return f'{self.name}'

EDIT: You can order the Categorys by the number of subcategories (in descending order) with:

def home(request):
    context = {
        'home_page': "active",
        'categories': Category.objects.annotate(
            nsub=Count('subcategory')
        ).order_by('-nsub')
    }
    return render(request, 'candidates/home.html', context)

Upvotes: 2

Related Questions