Search code examples
htmldjangofor-looppytorctl

Filters and for loops in Django


I am sorry if it is an obvious question, I am new to Django and Python. I am working on a small blog application. The following code retrieves all the posts from my database. I do not want to display all of them within the main page. I just need three of them. I am sure it is done using a for loop and some sort of filters according to the documentation.

https://docs.djangoproject.com/en/1.7/ref/templates/builtins/

views.py

def all(request):
    allPosts = Post.objects.all()
    context = {'Posts': allPosts}
    template = "home.html"
    return render(request, template, context)

home.html

<div class="sidebar-module">
            <h4>Archive</h4>
            <ol class="list-unstyled">

            {% for singlePost in Posts %}
            <li><a href="#">{{singlePost.title}}</a></li>
            {% endfor %}
            </ol>
          </div>

Solution

  • Since you are looking for only 3 posts, there is no need to pull all of the entries, the following will be sufficient:

    def all(request):
        """To get only three posts use a slice operation."""
        allPosts = Post.objects.all()[:3]
        context = {'Posts': allPosts}
        template = "home.html"
        return render(request, template, context)
    

    You can find more in the official documentation: https://docs.djangoproject.com/en/1.7/topics/db/queries/#limiting-querysets If you need the results filtered, use the same concept, but apply your filters: https://docs.djangoproject.com/en/1.7/topics/db/queries/#retrieving-specific-objects-with-filters

    On the other hand if you are going to use all of them on the same post but just want to restrict only to 3 on a specific part (say a sidebar etc) from the same set, then you could fetch them all as in your original post, and then loops inside the template:

    <div class="sidebar-module">
        <h4>Archive</h4>
        <ol class="list-unstyled">
    
        {% for singlePost in Posts|slice:":3" %}
            <li><a href="#">{{singlePost.title}}</a></li>
        {% endfor %}
        </ol>
    </div>
    

    Beware though that the above will result in a new query, if you are experiencing load problems it would be better, to evaluate your queryset in the view, assign it to a list and use the evaluated query:

    def all(request):
        """The bellow evaluates the queryset before it hits the template.
        So slicing in the template (example before) will not result in a new
        Queryset."""
        allPosts = list(Post.objects.all())
        context = {'Posts': allPosts}
        template = "home.html"
        return render(request, template, context)
    

    You can find more about evaluation here: https://docs.djangoproject.com/en/1.7/ref/models/querysets/#when-querysets-are-evaluated