Django Logo

Django Blog Engine

ButterCMS is an API-based Django blog engine that integrates with Django in minutes. With ButterCMS it's possible to launch the perfect company blog in Django.

Table of Contents


Learn how to quickly build a Django blog with great SEO.

If you need help after reading this, contact us via email, livechat, or book a time with to pair with one of our developers.

Display posts

To display posts, add a blog app to your Django project. This will serve as the basis of your blog home and individual post pages. The home page will display a list of 10 most recent posts.

python startapp blog

Set up a new url route to this blog app in our project's global file (i.e. myproject/myproject/

urlpatterns = [
    url(r'^blog/', include('blog.urls'))

Define the blog home route in blog/

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.home, name='blog'),
    url(r'^page/(?P<page>\d+)$', views.home, name='archive'),

Note there's also an archive named route for letting users paginate through older blog posts. It points to home view and passes in page as a param.

Then set up our home view in blog/ and fetch blog posts from the Butter API. The response also includes some metadata we'll use for pagination.

from django.http import Http404
from django.shortcuts import render
from butter_cms import ButterCMS

client = ButterCMS('')

def home(request, page=1):
    response = client.posts.all({'page_size': 10, 'page': page})

        recent_posts = response['data']
        # In the event we request an invalid page number, no data key will exist in response.
        raise Http404('Page not found')

    next_page = response['meta']['next_page']
    previous_page = response['meta']['previous_page']

    return render(request, 'blog_base.html', {
        'recent_posts': recent_posts,
        'next_page': next_page,
        'previous_page': previous_page

Next we'll create the blog_base.html template that displays our posts and pagination links:


<!-- List of posts -->
{% for post in recent_posts %}
    <a href="{% url 'blog_post' post.slug %}">{{ post.title }}</a>
{% endfor %}

<!-- Pagination links -->
  {% if previous_page %}
  <a href="{% url "archive" previous_page %}">Prev</a>
  {% endif %}

  {% if next_page %}
  <a href="{% url "archive" next_page %}">Next</a>
  {% endif %}

We'll also create an additional route + view for displaying individual posts:

# in blog/

urlpatterns = [
    url(r'^$', views.home, name='blog'),
    url(r'^page/(?P<page>\d+)$', views.home, name='archive'),

    url(r'^(?P<slug>.*)$',, name='blog_post'),
# in blog/

def post(request, slug):
        response = client.posts.get(slug)
        raise Http404('Post not found')

    post = response['data']
    return render(request, 'blog_post.html', {
        'post': post

The view for displaying a full post includes information such as author, publish date, and categories. See a full list of available post properties in our API reference.

<title>{{ post.seo_title }}</title>
<meta name="description" content="{{ post.meta_description }}">

<!-- Post title -->
<h2>{{ post.title }}</h2>

<!-- Post author + Publish date -->
Posted by <a href="{% url 'blog_author' author.slug %}">{{ }} {{ }}</a> on {{ post.published }}

<!-- Post categories -->
{% for category in post.categories %}
<a href="{% url 'blog_category' category.slug %}">{{ }}</a>
{% endfor %}

<!-- Post body -->
{{ post.body|safe }}

Categories, Tags, and Authors

Use Butter's APIs for categories, tags, and authors to feature and filter content on your blog:

# In blog/

client = ButterCMS('')

def home(request, page=1):
    # Query categories and tags to display in sidebar
    categories = client.categories.all()
    tags = client.tags.all()

    return render(request, 'blog_base.html', {...})

def author(request, slug):
    response = client.posts.all({'author_slug': slug})
    recent_posts = response['data']

    return render(request, 'author.html', {
        'recent_posts': recent_posts

def category(request, slug):
    response = client.posts.all({'category_slug': slug})
    recent_posts = response['data']

    return render(request, 'category.html', {
        'recent_posts': recent_posts

See our API reference for more information about these objects:

RSS, Atom, and Sitemap

Butter generates RSS, Atom, and sitemap XML markup. To use these on your blog, return the generated XML from the Butter API with the proper content type headers.

# in blog/
def rss(request):
    response = client.feeds.get('rss')
    return HttpResponse(response['data'], content_type='application/rss+xml')

def atom(request):
    response = client.feeds.get('atom')
    return HttpResponse(response['data'], content_type='application/rss+xml')


Butter doesn't provide an API for comments due to the excellent existing options that integrate easily. Two popular services we recommend are:

Both products are free, include moderation capabilities, and give your audience a familiar commenting experience. They can also provide some additional distribution for your content since users in their networks can see when people comment on your posts. For a minimalist alternative to Disqus, check out RemarkBox or for an open-source option, Isso.


Butter integrates into your front-end so you have complete control over the design of your blog. Use the following CSS as boilerplate for post content styling.

.post-container {
  h1, h2, h3, h4, h5 {
    font-weight: 600;
    margin-bottom: 1em;
    margin-top: 1.5em;

  ul, ol {
    margin-bottom: 1.25em;

    li {
      margin-bottom: 0.25em;

  p {
    font-family: Georgia, Cambria, "Times New Roman", Times, serif;
    font-size: 1.25em;
    line-height: 1.58;
    margin-bottom: 1.25em;
    font-weight: 400;
    letter-spacing: -.003em;

  /* Responsive default image width */
  img {
    max-width: 100%;
    height: auto;

  /* Responsive floating */
  @media only screen and (min-width: 720px)  {
    .butter-float-left {
      float: left;
      margin: 0px 10px 10px 0px;

    .butter-float-right {
      float: right;
      margin: 0px 0px 10px 10px;

  /* Image caption */
  figcaption {
    font-style: italic;
    text-align: center;
    color: #ccc;

  p code {
    padding: 2px 4px;
    font-size: 90%;
    color: #c7254e;
    background-color: #f9f2f4;
    border-radius: 4px;
    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;

  pre {
    display: block;
    padding: 1em;
    margin: 0 0 2em;
    font-size: 1em;
    line-height: 1.4;
    word-break: break-all;
    word-wrap: break-word;
    color: #333333;
    background-color: #f5f5f5;
    font-family: Menlo, Monaco,Consolas, "Courier New", monospace;


To import content from another platform like WordPress or Medium, send us an email.

About Django

Django is an MVC web application development framework written in Python.

Blog Engine for these technologies and more

Ruby, Rails, Node.js, Python, ASP.NET, C#, Flask, Django, Go, PHP, React, Phoenix, Elixir

Get started now

Sign up with Google Sign up with Github