Developers, 
Try Django for Yourself

 Why Build Websites This Way


A full-stack website, which integrates both front-end (user interface) and back-end (server and database) components, offers a comprehensive solution that streamlines development, ensures consistency in design and functionality, and enhances communication between different parts of the web application. 


This holistic approach not only accelerates the development process by allowing simultaneous progress on user-facing features and server-side logic but also simplifies maintenance and scalability. 


As developers have control over the entire system architecture, they can implement features more efficiently and ensure that all elements work seamlessly together, providing a smoother user experience and improving overall performance and security.


 Note: This walkthrough uses Wagtail 6.2 on Windows.

What is Django?​​


Django is a powerful tool used by web developers to build websites quickly and efficiently, developed with Python. It allows developers to focus on creating a unique and functional website without reinventing the wheel for each new project.



What is Wagtail?


Wagtail, is an add-on for Django that makes it easier to manage the content of a website. It provides a user-friendly interface where editors can easily modify and organize their website.


Continue reading this guide to learn more!

 Getting Started


Local Development Environment

  1. Install PyCharm Community Edition (Download)
  2. Install Python (Download)
  3. Install Docker (Download) & Sign-up (Account)
  4. Install Git (Download)


Project Creation

  1. Open PyCharm
  2. Create a new project
  3. Set the project location, if not already default
  4. Give it a Project Name
  5. Choose "Create a Git repository"
  6. Set the project virtual environment (venv) to Python 3.12 (current as of 6/15/24)
  7. Open the PyCharm Terminal panel and set Git info: git config user.email "your@email.com"

 Watch & Learn



New Wagtail Website

  1. Install Wagtail: pip install wagtail
    1. Note, if you need to install 6.2 specifically, use pip install wagtail==6.2
  2. Start Wagtail site: wagtail start [site-name]
  3. Change directories to new wagtail site: cd [site-name]
  4. Make database migrations: python manage.py makemigrations
  5. Run database migration: python manage.py migrate
  6. Create super user: python manage.py createsuperuser
    1. Provide a username, email, and password
  7. Run website for the first time: python manage.py runserver
    1. Test your website at 127.0.0.1:8000
  8. Stop the server process by typing CTRL+C in the PyCharm Terminal.


 Save Your Work! 
Add recent updates to your Git Repo: 
git add . then git commit -m "New Wagtail Website"


Extend Data Models

 Why use custom data models? By extending data models, you can easily add custom fields to your user authentication, images or documents (e.g., source, information, or type). Extending from the beginning gives you flexibility without altering the core features of Django. This is particularly useful if your application evolves and you need to store more information about your data objects.

Note, delete the initial db.sqlite3 file as we'll migrate again with custom models.


Custom User Model 
(Django for Professionals, Page 56 and Wagtail Docs)

  1. Create accounts app: python manage.py startapp accounts
  2. Add code to /accounts/models.py
  3. Update [site-name]/settings/base.py
    1. Comment out "wagtail.users" from INSTALLED_APPS
    2. Add "accounts" to INSTALLED_APPS
    3. Add "accounts.apps.CustomUsersAppConfig" to INSTALLED_APPS
    4. Add DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' below INSTALLED_APPS
    5. Add AUTH_USER_MODEL = "accounts.CustomUser" below INSTALLED_APPS
    6. Comment out this line, as we are redeclaring in the previous step: 
      from wagtail.compat import AUTH_USER_MODEL
  4. (Optional) Make database migrations: python manage.py makemigrations
    1. Note, this will recreate the db.sqlite3 file that we deleted earlier.
  5. Create the custom user admin form here: /accounts/forms.py - then add the custom classes.
  6. Update configuration here: /accounts/apps.py
  7. Update custom user admin here: /accounts/admin.py
  8. Add more custom fields, for example Bio text: 
    1. Update /accounts/models.py with new bio_text TextField
    2. Update /accounts/forms.py with new bio_text field
    3. Update /accounts/admin.py with new bio_text fieldset
    4. Add /accounts/viewsets.py with ViewSet code.
    5. Extend the Wagtail Create and Edit templates.
      1. Create /accounts/templates/edit.html and /accounts/templates/create.html 
      2. Add extra_fields block for the new bio_text field.
    6. Make database migrations: python manage.py makemigrations
    7. Run database migration: python manage.py migrate
    8. Run and test the local site again.


 Save Your Work! 
Add recent updates to your Git Repo: 
git add . then git commit -m "Custom User Model"


Custom Image Model
(Wagtail Docs)

  1. Create images app: python manage.py startapp images
  2. Update /images/models.py with custom classes.
  3. Add the images app to INSTALLED_APPS within /settings/base.py: "images"
  4. Then set the WAGTAILIMAGES_IMAGE_MODEL setting to point to it by placing the following code in your /settings/base.py configuration:
    WAGTAILIMAGES_IMAGE_MODEL = 'images.CustomImage'
  5. Make database migrations: python manage.py makemigrations
  6. Run database migration: python manage.py migrate
  7. Run and test the local site again, then  Save Your Work if successful.


Custom Document Model
(Wagtail Docs)

  1. Create documents app: python manage.py startapp images
  2. Update /documents/models.py with custom classes.
  3. Add the images app to INSTALLED_APPS within /settings/base.py: "documents"
  4. Then set the WAGTAILDOCS_DOCUMENT_MODEL setting to point to it by placing the following code in your /settings/base.py configuration:
    WAGTAILDOCS_DOCUMENT_MODEL = 'documents.CustomDocument'
  5. Make database migrations: python manage.py makemigrations
  6. Make database migrations: python manage.py migrate
  7. Run and test the local site again, then  Save Your Work if successful.


Coming Soon: How to run your Wagtail website in Docker!

 Code Snippets

All code in this exercise is provided below.

/accounts/models.py

from django.contrib.auth.models import AbstractUser
from django.db import models


class CustomUser(AbstractUser):
    bio_text = models.TextField(verbose_name="Bio", max_length=1000, null=True)
    is_active = models.BooleanField(default=True)

/settings/base.py

INSTALLED_APPS = [
    ...
    # "wagtail.users",
    "accounts",
    "accounts.apps.CustomUsersAppConfig",  # a custom app config for the wagtail.users app
    ...
]

# Place below INSTALLED_APPS
AUTH_USER_MODEL = "accounts.CustomUser"

/accounts/forms.py

from django.contrib.auth import get_user_model
from django import forms
from wagtail.users.forms import UserEditForm, UserCreationForm


class CustomUserCreationForm(UserCreationForm):
    bio_text = forms.CharField(label="Bio", max_length=1000)

    class Meta:
        model = get_user_model()
        fields = {
            'email', 'username', 'bio_text', 'first_name', 'last_name',
        }


class CustomUserEditForm(UserEditForm):
    bio_text = forms.CharField(label="Bio", max_length=1000)
    is_active = forms.BooleanField()

    class Meta:
        model = get_user_model()
        fields = {
            'email', 'username', 'bio_text', 'first_name', 'last_name', 'is_active'
        }

/accounts/admin.py

from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserEditForm

CustomUser = get_user_model()


class CustomUserAdmin(UserAdmin):
    add_form = CustomUserCreationForm
    form = CustomUserEditForm
    model = CustomUser
    fieldsets = UserAdmin.fieldsets + (
        (None, {'fields': ('bio_text',)}),
    )
    add_fieldsets = UserAdmin.add_fieldsets + (
        (None, {'fields': ('bio_text',)}),
    )
    list_display = ['email', 'username', 'is_superuser', 'bio_text']


admin.site.register(CustomUser, CustomUserAdmin)

/accounts/apps.py

from wagtail.users.apps import WagtailUsersAppConfig


class CustomUsersAppConfig(WagtailUsersAppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    user_viewset = "accounts.viewsets.UserViewSet"

/accounts/viewsets.py

from wagtail.users.views.users import UserViewSet as WagtailUserViewSet
from .forms import CustomUserCreationForm, CustomUserEditForm


class UserViewSet(WagtailUserViewSet):
    template_prefix = "accounts/templates/"

    def get_form_class(self, for_update=False):
        if for_update:
            return CustomUserEditForm
        return CustomUserCreationForm

/images/models.py

from django.db import models

from wagtail.images.models import Image, AbstractImage, AbstractRendition


class CustomImage(AbstractImage):
    caption = models.CharField(verbose_name="Caption", max_length=255, blank=True)

    admin_form_fields = Image.admin_form_fields + (
        'caption'
    )


class CustomRendition(AbstractRendition):
    image = models.ForeignKey(CustomImage, on_delete=models.CASCADE, related_name='renditions')

    class Meta:
        unique_together = (
            ('image', 'filter_spec', 'focal_point_key'),
        )

/documents/models.py

from django.db import models

from wagtail.documents.models import Document, AbstractDocument

class CustomDocument(AbstractDocument):
    source = models.CharField(
        max_length=255,
        blank=True,
        null=True
    )

    admin_form_fields = Document.admin_form_fields + (
        'source',
    )

Other Settings

  1. PIP
    1. pip install environs
    2. pip freeze > requirements.txt
  2. Settings
    1. Base.py
      1. Django Private Key
    2. dev.py
      1. Database
        1. Heroku postgres plan 
        2. DATABASE_URL Config Var is set under Settings
    3. production.py
      1. Django Settings
      2. “DATABASES”
        1. Dj_db_url package
      3. “ALLOWED_HOSTS”
      4. Debug True/False

Next: Docker Configuration

Docker Configuration

  1. Open the Docker desktop app
  2. Open the PyCharm Terminal panel and run the docker ps command to ensure that Docker is running. Typically, you should see no processes running.
  3. Update the Dockerfile with:
    1. ...
    2. ...
  4. Create compose.yaml file and add code:
    1. ...
  5. Freeze your dependencies to requirements.txtpip freeze > requirements.txt
  6. First time “docker compose up”
    1. Error Note: no such table wagtailcore_site
    2. “Docker-compose exec web python manage.py migrate”

Next: Heroku Configuration

Heroku Configuration

  1. Create heroku.yml
  2. Deploy to Heroku Container Service
  3. … “heroku login”
  4. … “heroku container:login”
  5. … “heroku container:push web -a [app name]
  6. … “heroku container:release web -a [app name]
  7. Check app logs on Heroku
  8. Django commands on Heroku CLI
  9. … “heroku run web python manage.py migrate -a [app name]”
  10. … “heroku run web python manage.py createsuperuser -a [app name]”

Next: Your New Wagtail Website

Would you like updates?

We're continually adding to and improving this article.