Jarana Manotumruksa
Jarana Manotumruksa

Reputation: 180

How can I query an object and its related object in one time in Django

class Ingredient(models.Model):
    ..
    status = models.CharField(max_length=16, default="pending")

class Food(models.Model):
    ..
    ingredients = models.ManyToManyField(Ingredient)


{% for i in food %}
    {% for j in food.ingredients.all %}

In the for loop tag, I would like to list each food with its ingredients which the status is not "pending".

I don't want to use IF tag to check at client side because if food contains a lot of pending ingredients, it means that the server has to sent a lot of data that will never be used. The server supposes to sent only needed data.

Thank you for your help.

Upvotes: 0

Views: 56

Answers (1)

almalki
almalki

Reputation: 4775

First of all and from db design point of view, it is better if your status field is a list of choices. It would be something like this:

class Ingredient(models.Model):
    NEW = 1
    PENDING = 2
    APPROVED = 3
    STATUS_CHOICES = (
        (NEW, 'New'),
        (PENDING, 'Pending'),
        (APPROVED , 'Approved'),
    )
    status = models.IntegerField(default=PENDING, choices=STATUS_CHOICES)

Now since the relation is many to many and to get list of related ingredients, get a list of food items and then apply filter(in view using orm filter on each food item, or in template using !=)

food = Food.objects.all()

and in template(notice the difference in second line from your loop):

{% for i in food %}
    {% for j in i.ingredients.all %}
        {% if j.status != 2 %}

The problem with this approach is that for every food item it will send db query which might not be efficient. Instead you can do this in your view:

food = Food.objects.prefetch_related('ingredients')

which will bring all related ingredients in one query for all food items. The problem with prefetch_related is that you have to do any filtering also yourself.

Upvotes: 1

Related Questions