Django Project Starter Template

My custom project starter for Django! I’ll try to support every upcoming
Django releases as much as I can!


  • Latest Python 3.7.4 runtime environment.
  • PostgreSQL
  • pip, virtualenv, virtualenvwrapper
  • If you like to run Rake Tasks, you need Ruby too...


macOS user can install PostgreSQL from Homebrew:

$ brew install postgres  # if you need to

Don’t forget to start your database server before continue. Now create your

$ createdb -E UTF8 -T template0 my_project_dev

# or createdb with locale
$ createdb -E UTF8 -T template0 --lc-collate=tr_TR.UTF-8 --lc-ctype=tr_TR.UTF-8 my_project_dev

# or postgres from docker
$ PGPASSWORD=YOUR-POSTGRES-PASSWORD createdb -h localhost -U postgres -E UTF8 -T template0 my_project_dev

# grant privileges
$ PGPASSWORD=YOUR-POSTGRES-PASSWORD psql -h localhost -U postgres -d my_project_dev -c "GRANT ALL PRIVILEGES ON DATABASE my_project_dev TO postgres;"

# check
$ PGPASSWORD=YOUR-POSTGRES-PASSWORD psql -h localhost -U postgres -l

Please use virtualenvwrapper and create your environment and activate it.
With Python 3.3+, you don’t need to install virtualenv. You can create your
environment via; python -m venv /path/to/your/environment

# example
$ mkvirtualenv my_projects_env

# or make it active:
$ workon my_projects_env

You need to declare DATABASE_URL for postgres connection and DJANGO_SECRET
for settings. I always put my project specific environment variables under
virtualenvwrapper’s postactivate file. Open your
~/.virtualenvs/my_projects_env/bin/postactivate and add (or set it

# docker/postgres usage;
export DATABASE_URL="postgres://postgres:[email protected]:5432/my_project_dev"

# or for osx/homebrew postgres usage;
export DATABASE_URL="postgres://localhost:5432/my_project_dev"
export DJANGO_SECRET=$(head -c 75 /dev/random | base64 | tr -dc 'a-zA-Z0-9' | head -c 50)

By default, DJANGO_ENV environment variable is set to development via For production usage, DJANGO_ENV environment variable is set to
production via This means, if you don’t set DJANGO_ENV variable,
app sets it for you.

Now trigger workon my_projects_env, this reloads environment variables.

# for django X.Y.Z
# check

$ curl -L >
$ unzip
$ mv django2-project-template-django-X.Y.Z my_project && rm
$ cd my_project/
$ cp config/settings/ config/settings/
$ cp config/settings/ config/settings/
# is not under revison control
# is not under revison control
$ pip install -r requirements/development.pip
$ git init # now you can start your own repo!

or, you can use installer script:

$ bash <(curl -fsSL
$ pip install -r requirements/development.pip
$ git init # now you can start your own repo!

This template comes with custom User model. Please take a look at it. If you
need to add/change fields, please do so. Default app language is set to en-us and
timezone is set to UTC. I use:

# config/settings/

TIME_ZONE = 'Europe/Istanbul'

If you change anything, please run makemigrations to keep track of your db.
Then continue to work:

$ python migrate
$ python createsuperuser

# enter: Email, First Name, Last Name and password
$ python runserver_plus # or
$ rake

You can fix your Django Admin titles now. Go to config/ and fix: = _('Your admin index title') = _('Your site title') = _('Your site header')

Do not forget to compile your locale messages files.


  • Custom User Model
  • Custom BaseModel
  • Custom BaseModelWithSoftDelete
  • Custom manager for BaseModel and BaseModelWithSoftDelete
  • Better Django Application structure! (imho)
  • Settings abstraction: Development / Production / Heroku / Test
  • Requirements abstraction depending on your environment!
  • Custom logger and log formatters for development server
  • Basic logging configuration for production server
  • App and Model creator management commands
  • Custom Locale middleware
  • Debug Mixin for your HTML templates
  • Handy utils: console, console.dir(), numerify, save_file
  • File widget for Django Admin: AdminImageFileWidget
  • Easy naming for your admin site!
  • DJANGO_ENV indicator for your admin site!
  • Custom and configurable error pages: 400, 403, 404, 500
  • OverwriteStorage for overwriting file uploads
  • Custom file storage for missing files for development environment: FileNotFoundFileSystemStorage
  • Report errors to Slack: SlackExceptionHandler

Quick Start

Let’s create blog application. We’ll have two models. Post and Category.
First, create application:

$ python create_app blog

# or

$ rake new:application[blog]

"blog" application created.

    - Do not forget to add your `blog` to `INSTALLED_APPS` under `config/settings/`:


    - Do not forget to fix your `config/`:
    # ...
    urlpatterns = [
        # ...
        # this is just an example!
        path('__blog__/', include('blog.urls', namespace='blog')),
        # ..
    # ...

Fix your config/settings/, add this newly created app to your INSTALLED_APPS:

# config/settings/
AUTH_USER_MODEL = 'baseapp.User'


Now, if you fix your config/ you’ll be able to see demo
pages for your app:

# config/
urlpatterns = [
    # ...
    path('__blog__/', include('blog.urls', namespace='blog')),
    # ..

Now run server and call

$ python runserver

# or

$ rake

You’ll see Hello from Blog page and If you check blog/views/ you’ll see
and example usage of HtmlDebugMixin and console util.

import logging

from django.views.generic.base import TemplateView

from baseapp.mixins import HtmlDebugMixin
from baseapp.utils import console

__all__ = ['BlogView']

logger = logging.getLogger('app')
console = console(source=__name__)

class BlogView(HtmlDebugMixin, TemplateView):
    template_name = 'blog/index.html'

    def get_context_data(self, **kwargs):
        self.hdbg('Hello from hdbg')
        kwargs = super().get_context_data(**kwargs)
        return kwargs

Let’s look at our blog application structure:

    ├── admin
    │   └──
    ├── migrations
    │   └──
    ├── models
    │   └──
    ├── tests
    │   ├──
    │   └──
    ├── views
    │   ├──
    │   └──

Now lets add Post model with soft-delete feature!

$ python create_model blog Post softdelete

# or

$ rake new:model[blog,Post,softdelete]

models/ created.
admin/ created.
Post model added to models/
Post model added to admin/

    `Post` related files created successfully:

    - `blog/models/`
    - `blog/admin/`

    Please check your models before running `makemigrations` ok?

This creates blog/models/ and blog/admin/ files:

# blog/models/

import logging

from django.db import models
from django.utils.translation import ugettext_lazy as _

from baseapp.models import BaseModelWithSoftDelete
from baseapp.utils import console

__all__ = ['Post']

logger = logging.getLogger('app')
console = console(source=__name__)

class Post(BaseModelWithSoftDelete):
    title = models.CharField(max_length=255, verbose_name=_('title'))

    class Meta:
        app_label = 'blog'
        verbose_name = _('post')
        verbose_name_plural = _('posts')
    def __str__(self):
        return self.title

and Category model:

$ python create_model blog Category softdelete

# or

$ rake new:model[blog,Category,softdelete]

models/ created.
admin/ created.
Category model added to models/
Category model added to admin/

    `Category` related files created successfully:

    - `blog/models/`
    - `blog/admin/`

    Please check your models before running `makemigrations` ok?

Now It’s time to fix our models by hand!

# blog/models/

import logging

from django.conf import settings
from django.db import models
from django.utils.translation import ugettext_lazy as _

from baseapp.models import BaseModelWithSoftDelete
from baseapp.utils import console

__all__ = ['Post']

logger = logging.getLogger('app')
console = console(source=__name__)

class Post(BaseModelWithSoftDelete):
    author = models.ForeignKey(
    category = models.ForeignKey(
    title = models.CharField(max_length=255, verbose_name=_('title'))
    body = models.TextField(verbose_name=_('body'))

    class Meta:
        app_label = 'blog'
        verbose_name = _('post')
        verbose_name_plural = _('posts')  # check pluralization

    def __str__(self):
        return self.title

We’ll keep blog/models/ same, Category will have only title

# blog/models/

import logging

from django.db import models
from django.utils.translation import ugettext_lazy as _

from baseapp.models import BaseModelWithSoftDelete
from baseapp.utils import console

__all__ = ['Category']

logger = logging.getLogger('app')
console = console(source=__name__)

class Category(BaseModelWithSoftDelete):
    title = models.CharField(max_length=255, verbose_name=_('title'))

    class Meta:
        app_label = 'blog'
        verbose_name = _('category')
        verbose_name_plural = _('categories')

    def __str__(self):
        return self.title

Now It’s time to create migrations:

$ python makemigrations --name create_post_and_category

# or

$ rake db:update[blog,create_post_and_category]

Migrations for 'blog':
    - Create model Category
    - Create model Post

Now migrate!

$ python migrate

# or

$ rake db:migrate

Operations to perform:
  Apply all migrations: admin, auth, baseapp, blog, contenttypes, sessions
Running migrations:
  Applying blog.0001_create_post_and_category... OK

Now time to run server and dive in to admin page!

$ python runserver

# or

$ rake

Performing system checks...

System check identified no issues (0 silenced).
Django version X.Y.Z, using settings 'config.settings.development'
Starting development server at
Quit the server with CONTROL-C.

Open and use your superuser credentials.

Project File/Folder Structure

What I’ve changed ?

  • All Django apps live under applications/ folder.
  • All of the models live under generated app’s models/ folder.
  • All of the views live under generated app’s views/ folder.
  • All of the tests live under generated app’s tests/ folder.
  • All of the admin files live under generated app’s admin/ folder.
  • Every app should contain It’s own
  • All settings related files will live under config/settings/ folder.
  • Every environment has It’s own setting such as config/settings/
  • Every environment/settings can have It’s own package/module requirements.
  • All of the templates live under basedir’s templates/APP_NAME folder.
  • All of the locales live under basedir’s locale/LANG/... folder.
  • Lastly, Ruby and Python can be friends in a Django Project!

Here is directory/file structure:

├── applications
│   └── baseapp
├── config
│   ├── settings
│   ├──
│   ├──
│   └──
├── db
├── locale
│   └── tr
├── requirements
│   ├── base.pip
│   ├── development.pip
│   └── heroku.pip
├── static
│   └── css
├── templates
│   ├── admin
│   ├── baseapp
│   └── base.html
├── Procfile
├── Rakefile
├── requirements.txt
└── runtime.txt

Settings and Requirements Abstraction

By default, looks for DJANGO_ENV environment variable. Builds
DJANGO_SETTINGS_MODULE environment variable according to DJANGO_ENV variable.
If your DJANGO_ENV environment variable is set to production, this means that
you are running config/settings/

Also config/ looks for DJANGO_ENV environment variable too. For
example, If you want to deploy this application to HEROKU, you need
config/settings/ and must add config variable DJANGO_ENV and set
it to heroku on HEROKU site. (You’ll find more information further below)

All the other settings files (according to environment) imports
config/settings/ and gets everything from it. is
un-tracked/git-ignored file. Original file is You
need to create a copy of it! (if you follow along from the beginning, you’ve already did this)

All the base/common required Python packages/modules are defined under requirements/base.pip:


This is the main settings file. All other settings will extend this one. By
default, we have Django Extensions installed as 3^rd party app.

Available installed apps are:

# base apps
    'baseapp.apps.BaseappConfig',  # our helper app

Extras are:

# add your newly created apps here!

Django Extension adds great functionalities:


One of my favorite: python show_urls :)

Logging is enabled only in development mode. Our development server
uses Werkzeug and we have special filter which is defined in LOGGIN_SKIP_THESE_EXTENSIONS.
You can skip displaying specified extensions from development server logs.

You can un-comment django.db.backends if you want to see the SQL queries.

    'loggers': {
        'app': {'handlers': ['console'], 'level': 'DEBUG'},
        'werkzeug': {'handlers': ['console'], 'level': 'DEBUG', 'propagate': True},
        'django.db.backends': {'handlers': ['console_sql'], 'level': 'DEBUG'},  # un-comment

By default, this template ships with Django Debug Toolbar in development

AUTH_PASSWORD_VALIDATORS are removed for development purposes. You can enter
simple passwords such as 1234. MEDIA_ROOT is set to basedir’s media folder,
STATICFILES_DIRS includes basedir’s static folder.

All the required modules are defined under requirements/development.pip:

-r base.pip

Basic settings for running tests.

You can deploy your app to HEROKU super easy. Just set your ALLOWED_HOSTS.
Add your heroku domain here:

    '',  # example heroku domain

All the required modules are defined under requirements/heroku.pip:

-r base.pip

By default, Heroku requires requirements.txt. Therefore we have it too :)

-r requirements/heroku.pip

Heroku also requires Procfile and runtime.txt. Both provided in the basedir.
Don’t forget to create heroku config variables:

$ heroku login
$ heroku apps:create
$ heroku addons:create heroku-postgresql:hobby-dev
$ heroku config:set DJANGO_ENV="heroku"
$ heroku config:set WEB_CONCURRENCY=3
$ git push heroku master
$ heroku run python migrate
$ heroku run python createsuperuser


If you are using different platform or OS, such as Ubuntu or your custom
servers, you can follow the settings and requirements conventions. If you name
it production, create your config/settings/ and

You need to set these environment variables in to your production server

  • DJANGO_ENV to production
  • DATABASE_URL to your PostgreSQL’s url
  • DJANGO_SECRET to more securly generated secret.

User model

This is custom model which uses AbstractBaseUser and PermissionsMixin.
Fields are:

  • created_at
  • updated_at
  • email
  • first_name
  • middle_name (optional)
  • last_name
  • avatar (optional)
  • is_active
  • is_staff
  • is_superuser

Username field is set to: email. Your users will login using their email’s
and password’s by default. You can modify everything if you like to. This also
mimics like default User model of Django. Available methods are:

  • get_short_name
  • get_full_name


This is a common model. By default, BaseModel contains these fields:

  • created_at
  • updated_at
  • status

We are overriding the default manager. BaseModel uses BaseModelQuerySet as
manager, BaseModelWithSoftDelete uses BaseModelWithSoftDeleteManager.
There are 4 basic status types:


You can make these queries:

>>> Post.objects.deleted()  # filters: status = STATUS_DELETED
>>> Post.objects.actives()  # filters: status = STATUS_ONLINE
>>> Post.objects.offlines() # filters: status = STATUS_OFFLINE
>>> Post.objects.drafts()   # filters: status = STATUS_DRAFT


This model inherits from BaseModel and provides fake deletion which is
probably called SOFT DELETE. This means, when you call model’s delete()
method or QuerySet’s delete() method, it acts like delete action but never
deletes the data.

Just sets the status field to STATUS_DELETED and sets deleted_at field to

This works exactly like Django’s delete(). Broadcasts pre_delete and
post_delete signals and returns the number of objects marked as deleted and
a dictionary with the number of deletion-marks per object type.

You can call hard_delete() method to delete an instance or a queryset

>>> Post.objects.all()

SELECT "blog_post"."id",
  FROM "blog_post"

Execution time: 0.000135s [Database: default]

<BaseModelWithSoftDeleteQuerySet [<Post: Python post 1>, <Post: Python post 2>, <Post: Python post 3>]>

>>> Category.objects.all()

SELECT "blog_category"."id",
  FROM "blog_category"
 WHERE "blog_category"."deleted_at" IS NULL

<BaseModelWithSoftDeleteQuerySet [<Category: Python>]>

>>> Category.objects.delete()
(4, {'blog.Category': 1, 'blog.Post': 3})

>>> Category.objects.all()
<BaseModelWithSoftDeleteQuerySet []>       # rows are still there! don’t panic!

>>> Category.objects.deleted()
<BaseModelWithSoftDeleteQuerySet [<Category: Python>]>

BaseModelWithSoftDeleteQuerySet has these query options according to
status field:

  • .all()
  • .offlines() : filters if BaseModel.STATUS_OFFLINE is set
  • .actives() : filters if BaseModel.STATUS_ONLINE is set
  • .deleted() : filters if BaseModel.STATUS_DELETED is set and deleted_at is not NULL
  • .drafts() : filters if BaseModel.STATUS_DRAFT is set
  • .delete() : soft delete on given object.
  • .undelete() : recover soft deleted on given object.
  • .hard_delete() : this is real delete. this method erases given object.

When soft-delete enabled (during model creation), Django admin will
automatically use CustomBaseModelAdminWithSoftDelete which is inherited from:
CustomBaseModelAdmin <- admin.ModelAdmin.

CustomBaseModelAdmin, CustomBaseModelAdminWithSoftDelete

Inherits from admin.ModelAdmin. By default, adds status to list_filter.
You can disable this via setting sticky_list_filter = None. When model is
created with rake new:model... or from management command, admin file is
automatically generated.

Example for Post model admin.

import logging

from django.contrib import admin

from baseapp.admin import CustomBaseModelAdminWithSoftDelete
from baseapp.utils import console

from ..models import Post

__all__ = ['PostAdmin']

logger = logging.getLogger('app')
console = console(source=__name__)

class PostAdmin(CustomBaseModelAdminWithSoftDelete):
    # sticky_list_filter = None
    # hide_deleted_at = False

By default, deleted_at excluded from admin form like created_at and
updated_at fields. You can also override this via hide_deleted_at attribute.
Comment/Uncomment lines according to your needs! This works only in CustomBaseModelAdminWithSoftDelete.

CustomBaseModelAdminWithSoftDelete also comes with special admin action. You can
recover/make active (undelete) multiple objects like deleting items.


This is mostly used for our custom projects. Injects LANGUAGE_CODE variable to
request object. /en/path/to/page/ sets request.LANGUAGE_CODE to en otherwise tr.

# add this to your settings/
MIDDLEWARE += ['baseapp.middlewares.CustomLocaleMiddleware']

Custom Error Pages

You have browsable (only in development mode) and customizable error handler
functions and html templates now!. Templates are under templates/custom_errors/
folder. Handlers are under baseapp/views/


HtmlDebugMixin injects {{ IS_DEBUG }} and {{ LANG }} template variables
to context. Also with self.hdbg(arg, arg, arg) method, you can debug
anything from view to html template...

# example:

import logging

from django.views.generic.base import TemplateView

from baseapp.mixins import HtmlDebugMixin
from baseapp.utils import console

__all__ = ['IndexView']

logger = logging.getLogger('app')
console = console(source=__name__)

class IndexView(HtmlDebugMixin, TemplateView):
    template_name = 'index.html'

    def get_context_data(self, **kwargs):
        self.hdbg('This', 'is', 'an', 'example', 'of')
        self.hdbg('self.hdbg', 'usage')
        return kwargs

{% hdbg %} tag added by default in to your templates/base.html:

{% load static %}
{% load i18n %}

<!DOCTYPE html>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{% block title %}Baseapp{% endblock %}</title>
    <link rel="stylesheet" href="[email protected]/css/bulma.min.css">
    <script defer src=""></script>
    <link rel="stylesheet" href="{% static 'css/baseapp.css' %}">
    <link rel="stylesheet" href="{% static 'css/application.css' %}">
    {% block extra_css %}{% endblock %}
    {% hdbg %}
    {% block body %}{% endblock %}
    {% block extra_js %}{% endblock %}

If you don’t want to extend from templates/base.html you can use your
own template. You just need to add {% hdbg %} tag in to your template.


Do you need to debug an object from the View or anywhere from your Python
script? Sometimes you need to print out some variable(s) or values to console
and you want to keep it safe right? print() is very dangerous if you forget
on production server.

console(), console.dir() they both work only under DEBUG = True mode.

# example:

from baseapp.utils import console

class IndexView(TemplateView):
    def get_context_data(self, **kwargs):
        kwargs = super().get_context_data(**kwargs)
        console('Hello', 'World')
        return kwargs

Now console.dir() outputs to terminal:

instance of AnonymousUser | <class 'django.utils.functional.SimpleLazyObject'>**
(   {   'arg': (   <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x10c3229e8>>,),
        'instance_attributes': ['_setupfunc', '_wrapped'],
        'internal_methods': [   '__class__', '__delattr__', '__dict__',
                                '__dir__', '__doc__', '__eq__', '__format__',
                                '__ge__', '__getattribute__', '__gt__',
                                '__hash__', '__init__', '__init_subclass__',
                                '__le__', '__lt__', '__module__', '__ne__',
                                '__new__', '__reduce__', '__reduce_ex__',
                                '__repr__', '__setattr__', '__sizeof__',
                                '__str__', '__subclasshook__', '__weakref__'],
        'private_methods': ['_groups', '_user_permissions'],
        'public_attributes': [   'check_password', 'delete',
                                 'get_group_permissions', 'get_username',
                                 'groups', 'has_module_perms', 'has_perm',
                                 'has_perms', 'id', 'is_active',
                                 'is_anonymous', 'is_authenticated',
                                 'is_staff', 'is_superuser', 'pk', 'save',
                                 'set_password', 'user_permissions',
        'public_methods': ['_setupfunc']},)

You can set defaults for console:

from baseapp.utils import console

console = console(
    source='', # banner title will be ``
    width=8,             # output width will wrap to 8 chars (demo purpose)
    indent=8,            # 8 characters will be userd for indention (demo purpose)
    color='white',       # banner color will be: white

console('Hello again...')

There are few basic color options available:

  • black
  • red
  • green
  • yellow
  • blue
  • magenta
  • cyan
  • white
  • default


Little helper for catching QUERY_STRING parameters for numerical values:

from baseapp.utils import numerify

>>> numerify("1")
>>> numerify("1a")
>>> numerify("ab")
>>> numerify("abc", default=44)


While using FileField, sometimes you need to handle uploaded files. In this
case, you need to use upload_to attribute. Take a look at the example in baseapp/models/

from baseapp.utils import save_file as custom_save_file
class User(AbstractBaseUser, PermissionsMixin):
    avatar = models.FileField(
        verbose_name=_('Profile Image'),

save_user_avatar returns custom_save_file’s return value. Default
configuration of for custom_save_file is
save_file(instance, filename, upload_to='upload/%Y/%m/%d/'). Uploads are go to
such as MEDIA_ROOT/upload/2017/09/21/...

Make your custom uploads like:

from baseapp.utils import save_file as custom_save_file

def my_custom_uploader(instance, filename):
    # do your stuff
    # at the end, call:
    return custom_save_file(instance, filename, upload_to='images/%Y/')

class MyModel(models.Model):
    image = models.FileField(
        verbose_name=_('Profile Image'),


After shipping/deploying Django app, users start to upload files, right ?
Then you need to implement new features etc. You can get the dump of the
database but what about uploaded files ? Sometimes files are too much or
too big. If you call, let’s say, a model’s ImageField’s url property,
local dev server logs lot’s of file not found errors to console.

Also breaks the look of application via broken image signs in browser.

Now, you won’t see any errors... FileNotFoundFileSystemStorage is a
fake storage that handles non existing files. Returns file-not-found.jpg
from static/ folder.

This is development purposes only! Do not use in the production!

You don’t need to change/add anything to your code...


OverwriteStorage helps you to overwrite file when uploading from django
admin. Example usage:

# in a model
from image OverwriteStorage

class MyModel(models.Model):
    photo = models.ImageField(

Add storage option in you file related fields.


Use this widget in your admin forms:

from baseapp.widgets import AdminImageFileWidget

class MyAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.FileField: {'widget': AdminImageFileWidget},

This widget uses Pillow (Python Image Library) which ships with your base.pip
requirements file. Show image preview, width x height if the file is image.

Currently, there is only one template variable available: {{ DJANGO_ENVIRONMENT_NAME }}.
This is used for indicating the current environment in django admin site. You
can customize look and feel here:

<!-- templates/admin/base_site.html -->

{% extends "admin/base_site.html" %}

{% load i18n %}

{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}

{% block branding %}
<h1 id="site-name">
    <a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a>
{% endblock %}

{% block welcome-msg %}
    {% trans 'Welcome,' %}
    <strong>{{ user.get_full_name }}</strong>.
{% endblock %}

{% block extrastyle %}
<style type="text/css">
    body:before {
        display: block;
        width: 100%;
        position: fixed;
        top: 0;
        z-index: 9999;
        line-height: 35px;
        text-align: center;
        font-weight: bold;
        text-transform: uppercase;
        color: white;
        content: "{{ DJANGO_ENVIRONMENT_NAME }}";
        background-color: red;
    body {
        padding-top: 35px !important;
{% endblock %}

This adds a basic HTML element via CSS to the <body> tag.


If you have Ruby installed, you’ll have lots of handy tasks for the project.
Type rake -T for list of tasks:

$ rake -T

rake db:migrate[database]                                        # Run migration for given database (default: 'default')
rake db:roll_back[name_of_application,name_of_migration]         # Roll-back (name of application, name of migration)
rake db:shell                                                    # run database shell ..
rake db:show[name_of_application]                                # Show migrations for an application (default: 'all')
rake db:update[name_of_application,name_of_migration,is_empty]   # Update migration (name of application, name of migration?, is empty?)
rake locale:compile                                              # Compile locale dictionary
rake locale:update                                               # Update locale dictionary
rake new:application[name_of_application]                        # Create new Django application
rake new:model[name_of_application,name_of_model,type_of_model]  # Create new Model for given application: django,basemodel,softdelete
rake run_server                                                  # Run server
rake shell[repl]                                                 # Run shell+ avail: ptpython,ipython,bpython default: ptpython
rake test:browse_coverage[port]                                  # Browse test coverage
rake test:coverage[cli_args]                                     # Show test coverage (default: '--show-missing --ignore-errors --skip-covered')
rake test:run[name_of_application,verbose]                       # Run tests for given application

Default task is run_server. Just type rake that’s it! runserver uses
runserver_plus. This means you have lots of debugging options!

rake db:migrate[database]

Migrates database with given database name. Default is default. If you like
to work multiple databases:

# example
# config/settings/

    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db', 'development.sqlite3'),
    'my_database': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db', 'my_database.sqlite3'),

You can just call rake db:migrate or specify different database like:
rake db:migrate[my_database] :)

rake db:roll_back[name_of_application,name_of_migration]

Your database must be rollable :) To see available migrations:
rake db:roll_back[NAME_OF_YOUR_APPLICATION]. Look at the list and choose your
target migration (example): rake db:roll_back[baseapp,1].

# example scenario
$ rake db:roll_back[baseapp]
Please select your migration:
 [X] 0001_create_custom_user
 [X] 0002_post_model

$ rake db:roll_back[baseapp,1]
$ rake db:show[baseapp]
 [X] 0001_create_custom_user
 [ ] 0002_post_model

rake db:shell

Runs default database client.

rake db:show[name_of_application]

Show migrations. Examples:

$ rake db:show # shows everything
 [X] 0001_initial
 [X] 0002_logentry_remove_auto_add
 [X] 0001_initial
 [X] 0002_alter_permission_name_max_length
 [X] 0003_alter_user_email_max_length
 [X] 0004_alter_user_username_opts
 [X] 0005_alter_user_last_login_null
 [X] 0006_require_contenttypes_0002
 [X] 0007_alter_validators_add_error_messages
 [X] 0008_alter_user_username_max_length
 [X] 0001_create_custom_user
 [X] 0001_create_post_and_category
 [X] 0001_initial
 [X] 0002_remove_content_type_name
 [X] 0001_initial

or just a specific app:

$ rake db:show[blog]
 [X] 0001_create_post_and_category

rake db:update[name_of_application,name_of_migration,is_empty]

When you add/change something in the model, you need to create migrations. Use
this task. Let’s say you have added new field to Post model in your blog

$ rake db:update[blog]                           # automatic migration (example)
Migrations for 'blog':
    - Alter field category on post
    - Alter field title on post

$ rake db:update[blog,add_new_field_to_post]     # migration with name (example)
Migrations for 'blog':

$ rake db:update[blog,add_new_field_to_post,yes] # migration with name (example)
Migrations for 'blog':

rake locale:compile and rake locale:update

When you make changes in your application related to locales, run: rake locale:update.
When you finish editing your django.po file, run rake locale:compile.

rake new:application[name_of_application]

Creates new application!

$ rake new:application[blog]

rake new:model[name_of_application,name_of_model,type_of_model]

Creates new model! Available model types are: django (default), basemodel
and softdelete.

$ rake new:model[blog,Post]                # will create model using Django’s `models.Model`
$ rake new:model[blog,Post,basemodel]      # will create model using our `BaseModel`
$ rake new:model[blog,Post,softdelete]     # will create model using our `BaseModelWithSoftDelete`

rake shell[repl]

Runs Django repl/shell with use shell_plus of django-extensions.
rake shell. This loads everything to your shell! Also you can see the
SQL statements while playing in shell. We have couple different repls:

  1. ptpython
  2. bpython
  3. ipython

Default repl is: ptpython

$ rake shell
$ rake shell[bpython]
$ rake shell[ipython]

rake test:run[name_of_application,verbose]

If you don’t provide name_of_application default value will be applications.
verbose is 1 by default.


$ rake test:run
$ rake test:run[baseapp,2]

rake test:coverage[cli_args]

Get the test report. Default is --show-missing --ignore-errors --skip-covered for
cli_args parameter.

$ rake test:coverage

rake test:browse_coverage[port]

Serves generated html coverages under htmlcov folder via python. Default port
is 9001

Run Tests Manually

$ DJANGO_ENV=test python test baseapp -v 2                                 # or
$ DJANGO_ENV=test python test baseapp.tests.test_user.CustomUserTestCase   # run single unit
$ rake test:run[baseapp]

Manual Usage

Let’s assume you need a model called: Page. Create a file under YOUR_APP/models/

# YOUR_APP/models/

from django.db import models

__all__ = [

class Page(models.Model):
    # define your fields here...

# YOUR_APP/models/
# append:
from .page import *

Now make migrations etc... Use it as from YOUR_APP.models import Page :)

New Features



You can send errors/exceptions to slack channel.
Just create a slack app, get the webhook URL and set as SLACK_HOOK
environment variable. Due to slack message size limitation, traceback
is disabled.

Example message contains:

  • http status
  • error message
  • exception message
  • or None
  • full path
http status: 500
ERROR (internal IP): Internal Server Error: /__baseapp__/
Exception: User matching query does not exist.
user_id: anonymous (None)
full path: /__baseapp__/?foo=!

You can enable/disable in config/settings/ / config/settings/

    'loggers': {
        'django.request': {'handlers': ['mail_admins', 'slack'], 'level': 'ERROR', 'propagate': False},  # remove 'slack'



All PR’s are welcome!

  1. fork (
  2. Create your branch (git checkout -b my-features)
  3. commit yours (git commit -am 'added killer options')
  4. push your branch (git push origin my-features)
  5. Than create a new Pull Request!


This project is licensed under MIT

GitHub - vigo/django2-project-template: Django project/application starter for lazybones :)
Django project/application starter for lazybones :) - GitHub - vigo/django2-project-template: Django project/application starter for lazybones :)