Home > database >  How to filter queryset based on boolean value, then count in template
How to filter queryset based on boolean value, then count in template

Time:04-13

I want to count how many jobs are open vs closed. I don't understand why this isn't working, I have added {{ap.id}} and {{open.line_num_id }} after the forloop just to see what was rendered. I would think that if they match, then it's added to the count. This is not the case, all jobs are counted regardless of the "if" statement. Totally lost as to what is happening and why. Any help would be very appreciated .

I have two models:

class Airplane(models.Model):
    line_num = models.CharField(max_length=10, unique=True)
    vh_num = models.CharField(max_length=4, unique=True)
    vz_num = models.CharField(max_length=4, unique=True)
    stall = models.CharField(max_length=30, choices=stall_picker)
    status = models.CharField(max_length=30, choices=status_picker)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    is_completed = models.BooleanField(default=False)
    pm = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.line_num

class Job(models.Model):
    line_num = models.ForeignKey(
        Airplane, on_delete=models.CASCADE, related_name="ap_jobs")
    job_num = models.CharField(max_length=10, unique=True)
    description = models.CharField(max_length=200)
    status = models.CharField(max_length=30, choices=status_picker)
    category = models.CharField(max_length=30, choices=categories_picker)
    is_completed = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class meta:
        ordering = ["category", "status"]

    def __str__(self):
        return (f"{self.job_num}: {self.description} : {self.is_completed}")

My View:

def Ap_linup(request):
    context = {
        'ap_list': Airplane.objects.all().filter(is_completed=False),
        'open_jobs': Job.objects.all().filter(is_completed=False),
        'closed_jobs': Job.objects.all().filter(is_completed=True)
    }
    
    return render(request, 'airplane/airplane_list.html', context)

Template:

{% extends 'base.html' %}

{% block title %} Airplane List {% endblock %}

{% block content %}
<center>
    <div >
        {% for ap in ap_list %}
        <div >
            <div >
                <div >
                    <h1>
                        <center>
                            <a href="{% url 'airplane:ap_detail' ap.id %}">{{ ap.line_num }}</a>
                        </center>
                    </h1>
                    <h3>
                        <p>Stall:<strong>{{ ap.stall }}</strong> VH:<strong>{{ ap.vh_num }}</strong> VZ:<strong>{{ap.vz_num }}</strong>
                        <p>MGR: {{ ap.owner }}</p>
                        <hr >
                        <h1>{{ ap.id }}</h1>
                        {% if ap.status == "Avalible" %}
                        <p>Current Status:</p>
                        <p >{{ ap.status }}</p>
                        {% else %}
                        <p>Current Status:</p>
                        <p >{{ ap.status }}</p>
                        {% endif %}
                    </h3>  
                    <!-- Open Job counts -->
                    <div> 
                        {% for open in open_jobs %}
                        {% if open.line_num_id == ap.id %}</p>
                            <p>Open Jobs: {{ open_jobs.count }}</p>
                        {% endif %}
                        {% endfor %}
                        {% for closed in closed_jobs %}
                        {% if closed.line_num_id == ap.id %}</p>
                            <p>Closed Jobs: {{ closed_jobs.count }}</p>
                        {% endif %}
                        {% endfor %}
                    </div>
                    <div >
                        {% for comment in ap.ap_comments.all %}
                            {% if comment_id == ap_id %}
                                    <p><strong>{{ comment.author }}</strong>: {{ comment.text }} @ {{comment.created_at }}</p>
                            {% endif %}
                        {% endfor %}
                    </div>
                </div>
            </div>
        </div>
        {% endfor %}
        
    </div>
</center>



{% endblock %}

OUTPUT:

Output

I want to display open and closed job counts per Airplane. Count of Open and Close jobs just add up to total jobs on Airplane.

CodePudding user response:

As Kusko mentions in the comments, you can pass that number to the context. You can do so by doing something like this:

def Ap_linup(request):
    context = {
        'ap_list': Airplane.objects.all().filter(is_completed=False),
        'open_jobs': Job.objects.all().filter(is_completed=False),
        'closed_jobs': Job.objects.all().filter(is_completed=True),
        'open_jobs_count': Job.objects.filter(is_completed=False).count(),
        'closed_jobs_count': Job.objects.filter(is_completed=True).count()
    }

Also, you don't need .all() because filter is sufficient.

and if you wanted to clean up the code a bit more so you don't have a lot of queries, you can declare variables before the context.

def Ap_linup(request):
    open_jobs = Job.objects.filter(is_completed=False)
    closed_jobs = Job.objects.filter(is_completed=True)

    context = {
        'ap_list': Airplane.objects.all().filter(is_completed=False),
        'open_jobs': open_jobs,
        'closed_jobs': closed_jobs,
        'open_jobs_count': open_jobs.count(),
        'closed_jobs_count': closed_jobs.count()
    }
    
    return render(request, 'airplane/airplane_list.html', context)

UPDATE:

To display this information in the template you can do this outside of your loop:

For closed jobs you just call the variable you set in the context

<p>Closed Jobs: {{ closed_jobs_count }}</p>

and for open jobs you would do the same thing

<p>Open Jobs: {{ open_jobs_count }}</p>

You no longer need to add a .count to the template because you already did the work on the backend. The value stored in closed_jobs_count and open_jobs_count is an number.

  • Related