In-Depth Django E-Commerce Tutorial: Wagtail CMS + Snipcart

If you're in a rush, you can skip to the actionable e-commerce tutorial steps.

"Python all the way, man."

That's the confident answer a developer at the office gave me when I asked him what his go-to stack for fast prototyping was. He uttered the same words when I asked about developing full-blown apps. Needless to say, he's a big Python fan.

As a matter of fact, he's the one who sparked the idea for this post. After reading my last tutorial on enabling e-commerce on Harp JS, a Node.js static site generator, he told me:

"You guys should slow down on all that static web dev, and try to make Snipcart play nice with a Python or Django-powered platform."

Just for kicks, I thought I'd follow his advice.

After all, I already knew our shopping cart platform could integrate with pretty much any tool out there. I settled on looking for Django-based CMS and site builders; to find a platform on top of which I could add our HTML/JS layer of customizable e-commerce.

So I opened Google and started searching.

But first, what is Python?

Python is a general purpose, dynamic programming language. Ex-Googler Guido van Rossum developed it in the late 80's. A fan of Monthy Python, he took one-half of the name to baptize his programming project. Today, Python is used by hundreds of thousands of developers all over the world. It has maintained a spot in the top 10 most popular programming languages in the famous TIOBE index.

Maybe you're wondering why my earlier developer friend likes it so much? Here are a few reasons:

And what about Django?

Django is an open source, high-level Python web framework. Its emphasize on reusable components makes it faster and simpler for developers to build web apps on top of Python.

Now maintained by the Django Software Foundation, it was originally written by two brilliant Lawrence Journal-World developers. Oh, and while Python draws its name from a comedy icon, Django got his from a versatile guitar legend: Django Reinhardt!

Finding the right fit for our e-commerce project: Wagtail CMS

Following the long snake's trail online (see what I did there) got me Googling for queries like "build a site with Django" and "best Django CMS". In the jungle of search results, it wasn't long before I caught was looking for and stumbled upon Wagtail CMS.

Wagtail CMS is a developer-first Django content management system. Free and open source, it was developed by the good-hearted folks at Torchbox. It's elegant, flexible, and, IMHO, kicks ass.

In this post, I'm going to show you how to integrate our shopping cart platform to Wagtail CMS. By the end of the tutorial, you'll have a solid Django-powered e-commerce site up and running.

And since I've already gone too far with the snake references, we're going to build a SLYTHERIN demo shop!

Let'sssss get sssssstarted.


For this tutorial, we assume you:

  • Have a basic understanding of Python as a programming language
  • Have a free Snipcart account (sign up here)

1. Putting together the scaffolding for your e-commerce site

First things first: you'll need to start by creating a basic Wagtail project. You can see how to do that here.


2. Creating the product models in Wagtail

Let's move on to an essential component of your Wagtail e-commerce project: your models—where your data will be stored.

Open up your file. From there, we'll create a model representing a product for our store.

For this tutorial, the product model we created looks like this:

class Product(Page):
    productAt = models.URLField()
    sku = models.CharField(max_length=255)
    name = models.CharField(max_length=255)
    image = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    description = models.CharField(max_length=255)

    content_panels = Page.content_panels + [

As you can see, our new model inherits from Page. Accordingly, Wagtail registers it and gives us the basic attributes of a page.

We'll also create another model that will serve as the homepage for our online store.

Here's the declaration for this one:

class HomePage(Page):
    body = RichTextField(blank=True)
    content_panels = Page.content_panels + [
        FieldPanel('body', classname="full")

Now, we have to migrate your Wagtail database to interact with these new models.

To handle migrations with Wagtail, you need to execute these methods sequentially in your project's root folder:

python makemigrations
python migrate

#Also, you can start your server with this method
python runserver

Entering the products data for your store

We now have the appropriate models set up in our Wagtail e-commerce project. So let's go ahead and create some actual products in the CMS!

If you've kept the standard server config thus far, you can open up your admin dashboard at http://localhost:8000/admin.

For our tutorial demo, the product pages will all be children of our homepage. Here's an example of one of our products:


In the fields here, you'll need to fill in all of Snipcart's mandatory HTML product attributes we defined in our models. Product definition with Snipcart is quite straightforward; you can read more about it here.

Declaring your online store's global settings

Before creating products templates for our site, we'll need to build a small template for Snipcart's required scripts.

This template will include your Snipcart account's API key. Even though we could hard code this key in the script declaration, we're better off using a setting config—it'll give us edit access right in the Wagtail CMS admin panel.

To do so, we'll add a package in the application definition. Go in your, located at /{project_name}/settings.

There, in the INSTALLED_APPS = [ ... ] assignation, add another app called 'wagtail.contrib.settings'.

We'll now be able to declare site-wide settings. But in order to access these settings in the templates, we need to add another context processor to our app. This will be added in the same file as the preceding one, but to the TEMPLATES = [{..., 'OPTIONS': { 'context_processors': [ ... ]}] assignation.

Here's the name of the package we will add into the context_processors array: 'wagtail.contrib.settings.context_processors.settings'.

Now that we've added the necessary packages, let's create the actual setting model to store our API key.

Let's hop back to our file and create a setting class like this one:

class SnipcartSettings(BaseSetting):
    ApiKey = models.CharField(
        help_text='Your Snipcart Api Key'

There, you will have to make a final migration to register the settings into the database.

You can now go back to your Wagtail admin dashboard. The settings panel on the left should have a SnipcartSettings section. Click on it and there will be a nice text box waiting for you to paste your API key!

Switch back to you editor and create a file in the /{project_name}/templates folder. This is where we'll put all of Snipcart's scripts use the settings we just created.

Here's our file's content for the tutorial demo:

<script src=""></script>
  <script src="" data-api-key="{{ settings.[your_app_label].SnipcartSettings.ApiKey }}" id="snipcart"></script>
  <link href="" rel="stylesheet" type="text/css" />

You'll have to change [your_app_label] for yours. For the demo, ours is home.

Building your online store's templates

Okay, so we have Wagtail set up just right, and our necessary e-commerce data. Time to create some templates to render all of this good stuff! We'll create a product.html file in the /home/templates/home folder.

This one will show basic product information, with a buy button. This view will be served for every single product. With the default server setup, it'll be accessible at http://localhost:8000/{your-product-name}.

We did a fairly simple one for the demo:

{% extends "base.html" %}

{% block body_class %}template-homepage{% endblock %}

{% block content %}

  {% include "snipcart.html" %}

  <h3>{{ }}</h3>

  <div class="product">
      <div class="product-details">
        <img src="{{ self.image }}" alt="{{ }}" class="thumbnail"/>
        <div class="product-description">
          <p>{{ }}</p>
          <p>{{ self.description }}</p>

          <button class="snipcart-add-item"
            data-item-name="{{ }}"
            data-item-id="{{ self.sku }}"
            data-item-image="{{ self.image }}"
            data-item-url="{{ self.productAt }}"
            data-item-price="{{ self.price }}"
            data-item-description="{{ self.description }}">
            Buy it for {{ self.price }} $


{% endblock %}

You can see we included the snipcart.html file to make sure the scripts for our buy buttons work.

Besides the individual product pages, we'll also want to show every product on our homepage.

So let's create a new template for this partial product view.

Go back in your /{project_name}/templates folder and create a product_partial.html file.

This is the one we used:

<div class="product">

  <div class="product-details">

      <img src="{{ product.image }}" alt="{{ }}" class="thumbnail"/>

      <a href="{{ product.slug }}">

        <div class="product-description">
          <p>{{ }}</p>
          <p>{{ product.description }}</p>

          <button class="snipcart-add-item"
            data-item-name="{{ }}"
            data-item-id="{{ product.sku }}"
            data-item-image="media/{{ product.image }}"
            data-item-url="{{ product.productAt }}"
            data-item-price="{{ product.price }}"
            data-item-description="{{ product.description }}">
            Buy it for {{ product.price }} $

Then, let's create the actual homepage template that will iterate through its children pages and render the products. We'll call this template home_page.html and place it in the same folder as the last one.

Here's how we did it:

 {% extends "base.html" %}

 {% load wagtailcore_tags %}

 {% block body_class %}template-homepage{% endblock %}

 {% block content %}

   {% include "snipcart.html" %}

   <div class="site-title">{{ self.title }}</div>

     <div class="products">

       {% for product in self.get_children.specific %}
         {% include "product_partial.html" %}
       {% endfor %}


 {% endblock %}

BOOM: ready to roll!

And here we go: a full Django-powered e-commerce set up with Snipcart & Wagtail CMS. Our sizzlin' Slytherin demo store is now ready.


 Check out the live demo yourself (and the awesome custom curssssor I made for you)!

You can see/use all the code written for this e-commerce tutorial here.


I really liked playing a bit with Python & Django while crafting this tutorial: I had never touched this programming language before. And creating a Wagtail CMS project from scratch was quite easy. The database setup was basically a single command job. What's super cool about Wagtail CMS is that it's both light and granular. You add specific modules(apps) only if you need them.

However, there seemed to be a lot of ways to achieve specific things: I often needed to search outside the documentation to figure out the best way to do it (like handling global setting for instance). Fortunately, there's an active community providing lots of help for new users!

I hope this post inspired you to try out small—or big—e-commerce projects on top of Wagtail with Snipcart! :)

Found this post entertaining or valuable in any way? Take a sec to send a tweet our way. That would be awesome! Got any questions or comments regarding Wagtail CMS or Snipcart? Hit the section below!

Suggested posts: