Django Tutorial #9: Wrap Things Up

    Django Tutorial #9: Wrap Things Up

    More Tutorials on Web Development

    In this post, we’ll create some optional features for our website. If you are not interested, just skip to the end of this post and start preparing for deployment.


    When we add more and more posts to our blog, creating a paginator might be a good idea, since we don’t want to have too many posts on one page.

    To do that, we need to add some extra code to our views. Let’s take the home view has an example.

    Import necessary packages:

    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

    Update home view:

    def home(request):
        page = request.GET.get('page', '')
        posts_list = Post.objects.all()
        paginator = Paginator(posts_list, 1)
            posts =
        except PageNotAnInteger:
            posts =
        except EmptyPage:
            posts =
        return render(request, 'blog/home.html', {
            'posts': posts,

    Here I striped unnecessary part to avoid confusion, but you need to remember to add them.

    Line 2, we get the page number here which we’ll need to use later.

    Line 3, get all the posts like we did before.

    Line 6 to 11, here we try three different conditions. If the page number is an integer, if the page number is not an integer, and if the page number is empty.

    Next, we need to display the paginator like this:

    <!-- Pagination -->
    {% if posts.has_other_pages %}
    <!-- Pagination -->
    {% if posts.has_other_pages %}
        <ul class="pagination">
            {% if posts.has_previous %}
                <li class="page-item"><a class="page-link" href="?page={{ posts.previous_page_number }}">&laquo;</a></li>
            {% else %}
                <li class="page-item disabled"><span class="page-link">&laquo;</span></li>
            {% endif %}
            {% for i in posts.paginator.page_range %}
                {% if posts.number == i %}
                    <li class="page-item active"><span class="page-link">{{ i }} <span
                {% else %}
                    <li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
                {% endif %}
            {% endfor %}
            {% if posts.has_next %}
                <li class="page-item"><a class="page-link" href="?page={{ posts.next_page_number }}">&raquo;</a></li>
            {% else %}
                <li class="page-item disabled"><span class="page-link">&raquo;</span></li>
            {% endif %}
    {% endif %}

    Refresh the page and you should see the paginator at the bottom.

    The idea is to get the posts with the same tags.

    Update post view:

    def post(request, slug):
        requested_post = Post.objects.get(slug=slug)
        post_tags = requested_post.tag.values_list('id', flat=True)
        related_posts = Post.objects.filter(tag__in=post_tags).exclude(
        return render(request, 'blog/post.html', {
            'post': requested_post,
            'related_posts': related_posts,

    Line 3, get all the tags that this post has.

    Line 4, get all the posts that have at least one of the tags from post_tags, but exclude the same post.

    Display the related posts:

    <!-- Related Posts -->
    <h3>Related Posts</h3>
    <div class="row">
        {% for post in related_posts %}
            <div class="col-md-4">
                <div class="card mb-4 box-shadow">
                    <img class="card-img-top" src="{{ post.featured_image.url }}" alt="{{ post.title }}">
                    <div class="card-body">
                        <h3 class="card-title">{{ post.title }}</h3>
                        <p class="card-text">{{ post.content|striptags|truncatewords_html:25 }}</p>
                        <div class="d-flex justify-content-between align-items-center">
                            <div class="btn-group">
                                <a href="{% url 'post' post.slug %}"
                                   class="btn btn-sm btn-outline-secondary">Read
                                    More →</a>
        {% endfor %}

    If you are tired of coding, there is always an easy way by using AddThis. They have related posts, share buttons, subscription forms and lots of other tools you may find useful.


    First, register a Disqus account.

    Create a new site.

    Follow the instructions and put the code into the right place, and Disqus will take care of the rest.

    Prepare For Deployment

    There are a few things we need to do before deploying our website.

    Prepare static and media files. Run the following command:

    python collectstatic

    This command will collect all static files from all the apps you created into the staticfiles folder. And now we can delete the static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) from the URL config.

    The media files, on the other hand, Django discourages serving media files directly from the server in the production environment. You need to configure your server settings. Take Apache as an example:

    Alias /media/ /path/to/mediafiles/
    <Directory /path/to/mediafiles/>
    Order deny,allow
    Allow from all

    Notice that /media/ matches the setting for MEDIA_URL, and /path/to/mediafiles/ is the absolute path to the mediafiles/ folder.

    Run Deployment Check

    Before we deploy our project, we need to check a few things. Go to terminal and run check --deploy. This command will check the SECRET_KEYDEBUGALLOWED_HOSTS and a few other sensitive settings for you.

    Please check your own settings against this documentation:

    Leave a Reply

    Your email address will not be published. Required fields are marked *