Reventlow
Reventlow

Reputation: 167

Django counting ForeignKeyField

I want to count from my brandListVeiw view how many assets I have of a certain brand

models.py

    class Asset(models.Model):

    # Relationships
    room = models.ForeignKey("asset_app.Room", on_delete=models.SET_NULL, blank=True, null=True)
    model = models.ForeignKey("asset_app.Model", on_delete=models.SET_NULL, blank=True, null=True)

    # Fields
    created = models.DateTimeField(auto_now_add=True, editable=False)
    last_updated = models.DateTimeField(auto_now=True, editable=False)
    name = models.CharField(max_length=30)
    mac_address = models.CharField(max_length=30, null=True, blank=True)
    serial = models.CharField(max_length=30, unique=True, blank=True, null=True, default=None)
    purchased_date = models.DateField(null=True, blank=True)
    may_be_loaned = models.BooleanField(default=False, blank=True, null=True)
    notes = models.TextField(max_length=448, null=True, blank=True)
    ip = models.CharField(max_length=90, null=True, blank=True)

    class Meta:
        pass

    def __str__(self):
        return str(self.name)

    def get_absolute_url(self):
        return reverse("asset_app_asset_detail", args=(self.pk,))

    def get_update_url(self):
        return reverse("asset_app_asset_update", args=(self.pk,))


class Brand(models.Model):
    name = models.CharField(max_length=30)
    notes = models.TextField(max_length=448, null=True, blank=True)
    last_updated = models.DateTimeField(auto_now=True, editable=False)
    created = models.DateTimeField(auto_now_add=True, editable=False)

    class Meta:
        ordering = ["name"]

    def __str__(self):
        return str(self.name)

    def get_absolute_url(self):
        return reverse("asset_app_brand_detail", args=(self.pk,))

    def get_update_url(self):
        return reverse("asset_app_brand_update", args=(self.pk,))

class Model(models.Model):

    # Relationships
    asset_type = models.ForeignKey("asset_app.Asset_type", on_delete=models.SET_NULL, blank=True, null=True)
    brand = models.ForeignKey("asset_app.Brand", on_delete=models.SET_NULL, blank=True, null=True)

    # Fields
    name = models.CharField(max_length=30)
    notes = models.TextField(max_length=448, null=True, blank=True)
    created = models.DateTimeField(auto_now_add=True, editable=False)
    last_updated = models.DateTimeField(auto_now=True, editable=False)

    class Meta:
        pass

    def __str__(self):
        return str(self.name) + " :: " + str(self.brand.name) + " :: " + self.asset_type.name

    def get_absolute_url(self):
        return reverse("asset_app_model_detail", args=(self.pk,))

    def get_update_url(self):
        return reverse("asset_app_model_update", args=(self.pk,))

views.py

class BrandListView(generic.ListView):
    model = models.Brand
    form_class = forms.BrandForm

Webpage

{% extends "base.html" %}
{% block content %}


     <h1>Brand list</h1>

    <br/>
    {% if messages %}

        {% for message in messages %}
            <div class="alert alert-success alert-dismissible fade show" role="alert">
                {{ message }}
                <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
            </div>
        {% endfor %}
    {% endif %}

    {% if object_list %}
        <table class="table">
            <tr class="table-dark">
                <td>Brand</td>
                <td>
                    Number of assets within that brand
                </td>
                <td>
                    <center>Delete</center>
                </td>
            </tr>
            {% for brand in object_list %}
                <tr>
                    <td>{{ brand.name }} <a href="{{ brand.get_update_url }}"
                                               class="badge rounded-pill bg-dark">Edit</a>
                        {% if not brand.notes == None or brand.notes == "" %}
                            <a href="#"
                               data-bs-toggle="popover"
                               data-html="true"
                               class="badge rounded-pill bg-success"
                               data-bs-trigger="focus"
                               title="Noter på {{ brand.name }}"
                               data-bs-content="{{ brand.notes }}">Notes</a>
                        {% endif %}
                    </td>
                    <td>
                        ***COUNT INPUT HERE***
                    </td>



                    <td>
                        <center><a href="#" class="btn btn-danger btn-sm "
                                   tabindex="-1" role="button" aria-disabled="true">Delete</a></center>
                    </td>
                </tr>

            {% endfor %}
        </table>
    {% endif %}

{% endblock %}

So I am not even sure where I should insert my filter/count methode.

In other words I have an Asset, that is part of a Model and that Model is part of a Brand. How would I return how many Assets are their of a certain Brand.

Upvotes: 2

Views: 45

Answers (1)

Abdul Aziz Barkat
Abdul Aziz Barkat

Reputation: 21807

You can override get_queryset in your view and use the Count [Django docs] aggregation function to annotate the count:

from django.db.models import Count


class BrandListView(generic.ListView):
    model = models.Brand
    form_class = forms.BrandForm
    
    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.annotate(asset_count=Count('model__asset'))

Next in the template you can simply write the following to display this annotated count:

{{ brand.asset_count }}

Upvotes: 1

Related Questions