[Django]-Showing a total of items created in a Django model

1👍

I believe it’s more common to put function definitions in the Model class (Project, from the looks of it), and add the @property tag above the function.

class Project(models.Model):
    ''' definitions and stuff '''

    @property
    def total_projects(self): # etc...

As for your specific case, you could forego the function altogether and just use {{ project_list.count }} or {{ project_list|length }} in your template.

A note about count vs length from the docs:

A count() call performs a SELECT COUNT(*) behind the scenes, so you
should always use count() rather than loading all of the record into
Python objects and calling len() on the result (unless you need to
load the objects into memory anyway, in which case len() will be
faster).

Note that if you want the number of items in a QuerySet and are also
retrieving model instances from it (for example, by iterating over
it), it’s probably more efficient to use len(queryset) which won’t
cause an extra database query like count() would.

So use the correct one for your usage.

Also, according to this answer and the below comment from @djangomachine, length may not always return the same number of records as count. If accuracy is important it may be better to use count regardless of the above case.

👤17slim

2👍

All by current work has been around listing the number of tasks that are included i each project, but now I want a total – should I add this as a new View?

It depends. If you just want to show the total number of projects and tasks with the first 10 completed projects in the database (which is what your get_queryset method does, be careful), I would go and do all of it in the same view (it would be useless to make a new view only to show some numbers, and that isn’t the purpose of ListView IMO).

On the other hand, you’re calling a class’s instance method (total_projects) from a model’s instance. That method doesn’t exists on the model, and when an attribute/method doesn’t exists in an object when calling it in a template, you just get nothing. Based on the previous paragraph, I would set it in the view’s context using get_context_data:

def get_context_data(self, **kwargs):
    data = super().get_context_data(**kwargs)
    data["total_projects"] = Projects.objects.count()
    # I'm assuming you only need the whole number of tasks with no separation
    data["total_tasks"] = Task.objects.count()

    return data

Finally, you can edit your get_queryset method and make it be an instance attribute (if you want it to be cleaner and you can handle the filtering with no additional code):

class IndexView(generic.ListView):
    queryset = Project.objects.order_by('is_complete')[:10]

Leave a comment