Gonzalo Dambra
Gonzalo Dambra

Reputation: 980

Django: Check in template if queryset is empty

I have found the solution for this but only by checking in views so far. I need to check in templates.

My view:

brands = Brand.objects.all()
for brand in brands:
    brand.products = Product.objects.filter(brand=brand.id)

And so in my template I want to show all my brands but not those which do not have any product.

{% for brand in brands %}
    {% if brand.product is not None %}
        <!-- Displays brand -->
    {% endif %}
{% endfor %}

Something like that, but the code is not None doesn't work for empty querysets and it is still displaying brands with no objects in them. What can I do?

EDIT: Sharing model as requested.

class Brand(models.Model):
    name = models.CharField(max_length=100, null=False)

    def __str__(self):
        return self.name


class Product(models.Model):
    name = models.CharField(max_length=100, null=False)
    brand = models.IntegerField(null=True)
    price = models.DecimalField(max_digits=12, decimal_places=2, null=False)

    def __str__(self):
        return self.name

Upvotes: 0

Views: 2898

Answers (4)

Nube Colectiva
Nube Colectiva

Reputation: 292

This simple solution using {% empty %} inside my for worked for me.

{% for detallesblog in object_list %}
  <label for="detalles" class="negritatxt">Detalles</label>

    <p>
      {{ detallesblog.detalles }}
    </p>

    <label for="logo" class="negritatxt">Logo</label>

    <p>
      <img src="{% static 'uploads/' %}{{ detallesblog.logo }} " class="img-fluid" alt="{{ detallesblog.logo }}">          
    </p>

    <label for="updated_at" class="negritatxt">Fecha de Actualización</label>
    <p>
      {{ detallesblog.updated_at }}
    </p>
    <a href="detallesblog/editar/{{ detallesblog.id }}" title="Editar" type="button" class="btn btn-primary">Editar Datos</a>
{% empty %}

    "You have not yet edited the details of your Blog", press the "Edit Data" button to do so.
    <
    <a href="detallesblog/editar/{{ detallesblog.id }}" title="Editar" type="button" class="btn btn-primary">Editar Datos</a>

{% endfor %}

You can adapt it to your needs

Upvotes: 0

orangecaterpillar
orangecaterpillar

Reputation: 876

If you want to display something different when a collection is empty, check this out:

{% for i in list %}
    // Do this in non - empty condition
{% empty %}
    // Do this in empty condition
{% endfor %}

credit: GeeksForGeeks

Upvotes: 0

JBoy
JBoy

Reputation: 144

Your template should be like:

{% for brand in brands %}
    {% if brand.product %}
        <!-- Displays brand -->
    {% endif %}
{% endfor %}

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477769

It is usually not a good idea to use IntegerFields, etc. to represent relations. Django uses ForeignKey [Django-doc] to implement such relations. There are multiple advantages for this: (1) it will add extra constraints to the database, such that the key can only refer to a real Brand; and (2) you will have extra ways to retrieve the related Products.

The Product model thus should have a ForeignKey to the Brand model, like:

class Product(models.Model):
    name = models.CharField(max_length=100, null=False)
    brand = models.ForeignKey(Brand, null=True, db_column='brand')
    price = models.DecimalField(max_digits=12, decimal_places=2, null=False)

Here we leave the database structure itself intact, but it will add a ForeignKey on it, as well as an index, making retrieving all products for a given Brand much faster.

It is usually a bad idea to write (business)logic in templates. In fact one of the reasons why the Django template language does not allow to make calls with parameters, etc. is to avoid that people write business logic in the template. So I strongly advice you to shift the logic to the view.

You can retrieve the Brands that at least have one related Product in the view with a one-liner:

Brand.objects.filter(product__isnull=False).distinct()

So it is not necessary to check each brand individually. Here we also check the existance of a Product in a single query for all Brands, not an extra query per Brand to check if there are related Products.

This will result in a query that looks like:

SELECT DISTINCT brand.*
FROM brand
INNER JOIN product ON brand.id = product.brand_id
WHERE product.id IS NOT NULL

Upvotes: 2

Related Questions