All notes



import django
// (1, 4, 2, 'final', 0)

python -m django --version


Writing your first Django project

Create Project

mkdir ~/djcode
cd ~/djcode

# This will create a mysite directory in your current directory. startproject mysite

The created mysite has the structure as:

# Outside dir. You can rename it to anything you like.
	# Management app.
    # This dir name is written to
		# A file required for Python to treat the mysite directory as a package.

Create App

Make sure you’re in the same directory as and type this command:

python startapp polls

In mysite/, include polls' URLConf:

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


Open up mysite/, Set Database and TIME_ZONE.

If you're using a database besides SQLite, make sure you've created a database by this point. Do that with “CREATE DATABASE database_name;” within your database’s interactive prompt.

Also make sure that the database user provided in mysite/ has “create database” privileges. This allows automatic creation of a test database.

Add to polls.

Add polls config to mysite/


We need do this before "migration" because the migrate command will only run migrations for apps in INSTALLED_APPS.


python makemigrations polls

# Check the SQL:
python sqlmigrate polls 0001
# Or check:
python check

# Do the real migration
python migrate

The migrate command looks at the INSTALLED_APPS setting and creates any necessary database tables according to the database settings in your mysite/ file and the database migrations shipped with the app.

The migrate command takes all the migrations that haven’t been applied (Django tracks which ones are applied using a special table in your database called django_migrations) and runs them against your database - essentially, synchronizing the changes you made to your models with the schema in the database.

Dry Principle

Don’t Repeat Yourself (DRY). Every distinct concept and/or piece of data should live in one, and only one, place. Redundancy is bad. Normalization is good. DjangoDoc: Dry.

The opposite is WET: We Edit Terribly. c2: DontRepeatYourself.

Playing with the API

python shell sets the DJANGO_SETTINGS_MODULE environment variable, which gives Django the Python import path to your mysite/ file.

export DJANGO_SETTINGS_MODULE=projRoot.settings_dev

You can play around the Models.

If you want helpful information from Model objects, add a __str__() method to both Question and Choice:

# polls/

import datetime
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils import timezone

@python_2_unicode_compatible  # only if you need to support Python 2
class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    def __str__(self):
        return self.question_text
    def was_published_recently(self):
        return self.pub_date >= - datetime.timedelta(days=1)

@python_2_unicode_compatible  # only if you need to support Python 2
class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)
    def __str__(self):
        return self.choice_text

The following are interactive examples:

from polls.models import Question, Choice

# []

# Create a new Question.
from django.utils import timezone
q = Question(question_text="What's new?",
# Save the object into the database. You have to call save() explicitly.
# 1
# Access model field values via Python attributes.
# "What's new?"
# datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=UTC)

# Change values by changing the attributes, then calling save().
q.question_text = "What's up?"

# objects.all() displays all the questions in the database.

# Django provides a rich database lookup API that's entirely driven by keyword arguments.
# [<Question: What's up?>]
# [<Question: What's up?>]

# Get the question that was published this year.
from django.utils import timezone
current_year =
# <Question: What's up?>

# Request an ID that doesn't exist, this will raise an exception.
# Traceback (most recent call last):
#     ...
# DoesNotExist: Question matching query does not exist.

# Lookup by a primary key is the most common case, so Django provides a shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
# <Question: What's up?>

# Make sure our custom method worked.
q = Question.objects.get(pk=1)
# True

# Give the Question a couple of Choices. The create call constructs a new Choice object, does the INSERT statement, adds the choice to the set of available choices and returns the new Choice object. Django creates a set to hold the "other side" of a ForeignKey relation (e.g. a question's choice) which can be accessed via the API.
q = Question.objects.get(pk=1)

# Display any choices from the related object set -- none so far.
# []

# Create three choices.
q.choice_set.create(choice_text='Not much', votes=0)
# <Choice: Not much>
q.choice_set.create(choice_text='The sky', votes=0)
# <Choice: The sky>

c = q.choice_set.create(choice_text='Just hacking again', votes=0)
# Choice objects have API access to their related Question objects.
# <Question: What's up?>

# And vice versa: Question objects get access to Choice objects.
# [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# 3

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
# [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]

# Let's delete one of the choices. Use delete() for that.
c = q.choice_set.filter(choice_text__startswith='Just hacking')


Create superuser:

python createsuperuser

The admin URL is like: "".

We need to tell the admin that Question objects have an admin interface. To do this, open the polls/ file, and edit it to look like this:

# polls/

from django.contrib import admin
from .models import Question

Run server

python help

# Run a built-in, lightweight Web server
python runserver

python runserver

python runserver --settings=settings_dev
# The Python path to a settings module. If this isn't provided, the DJANGO_SETTINGS_MODULE environment variable will be used.

Create Json response


import json
from django.http import HttpResponse

response_data = {}
response_data['result'] = 'error'
response_data['message'] = 'Some error message'

# Pre-Django 1.7 you'd return it like this:
return HttpResponse(json.dumps(response_data), content_type="application/json")

# For Django 1.7+
from django.http import JsonResponse
return JsonResponse({'foo':'bar'})

# If it's run from Django, return HttpResponse.
if os.environ.get('DJANGO_SETTINGS_MODULE')!=None:
	return HttpResponse(json.dumps(response_data), content_type="application/json")
# Else just output json.
	return json.dumps(response_data)

Manage command

StackOverflow: insert row into DB.

python shell

# Dump data to fixture
python dumpdata -o output.json

# Remember to exclude unmanaged database.
# --indent=4 make it human readable.
# -e sessions exclude session data
# -e admin exclude history of admin actions on admin site
# -e contenttypes -e auth.Permission exclude objects which are recreated automatically from schema every time during syncdb. Only use it together with --natural or else you might end up with badly aligned id numbers.
python dumpdata -e myApp.Backup --indent=2 -e sessions -e admin -e contenttypes -e auth.Permission -o output.json

# Import fixture data
python loaddata fixtureName

# Migration squashmigrations myapp 0004

python runserver



from django.http import HttpResponse
import datetime

def current_datetime(request):
	now =
	html = "<html><body>It is now %s.</body></html>" % now
	return HttpResponse(html)

def returnError(request):
	Return HTTP status 500: server error.
	return HttpResponse(status=500)



To disable it, you need declare on every view function:

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse

def my_view(request):
	return HttpResponse('Hello world')

from django.conf.urls.defaults import patterns, include, url
# Import the module - mysite/
from mysite.views import hello

urlpatterns = patterns('',
	# 'r' here denotes "raw string", so its contents should not interpret backslashes.
	#  There's a natural collision between Python's usage of backslashes and the backslashes that are found in regular expressions, so we always use raw string for regexp.
    url(r'^hello/$', hello),


Dynamic URLs, Pretty URLs

Usually, you may query /time/plus?hours=3 for time in 3 hours, but the URL /time/plus/3/ is far cleaner.

# This will match to 0-99 hours.
url(r'^time/plus/\d{1,2}/$', hours_ahead)
# This will match to any hour, but is not good one with regards to boundary condition.
url(r'^time/plus/\d+/$', hours_ahead)

# This is the magic one!!!
# With (), the matched text is captured and passed as arguments to the function.
url(r'^time/plus/(\d{1,2})/$', hours_ahead)

def hours_ahead(request, offset):
		# Converts the string value to an integer.
		offset = int(offset)
	except ValueError:
		raise Http404()
	dt = + datetime.timedelta(hours=offset)
	html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
	return HttpResponse(html)

Technically, captured values will always be Unicode objects, not plain Python bytestrings.

(r'^user/(?P<username>\w{0,50})/$', views.profile_page,),

For URL "domain/search/?q=haha", then you would use

request.GET.get('q', '')
# q is the parameter you want, And '' is the default value if q isn't found.


Wcf recommends to write INFO levels often, even in production enviroment, esp. for the server codes.

  1. DEBUG: Low level system information for debugging purposes
  2. INFO: General system information
  3. WARNING: Information describing a minor problem that has occurred.
  4. ERROR: Information describing a major problem that has occurred.
  5. CRITICAL: Information describing a critical problem that has occurred.

Writing to console and log file:

import os

    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO'),

Writes all request logging from the django.request logger to a local file:

	'version': 1,
	# If true, all loggers from the default configuration will be disabled. So usually set to False.
	'disable_existing_loggers': False,
	'handlers': {
		'mail_admins': {
			'level': 'ERROR',
			'class': 'django.utils.log.AdminEmailHandler'
		'file': {
			'level': 'DEBUG',
			'class': 'logging.FileHandler',
			'filename': '/path/to/django/debug.log',
	'loggers': {
		'django.request': {
			'handlers': ['file'],
			'level': 'DEBUG',
			'propagate': True,


Deploying static files

Before running nginx, you have to collect all Django static files in the static folder. First of all you have to edit mysite/ adding:

# Edit in
STATIC_ROOT = os.path.join(BASE_DIR, "static/")

# and then run
# python collectstatic



Security Concerns


Secure cookies

In, add

# May be missing when Django less than 1.4:
# The following is optional:

so cookies will only be sent via HTTPS connections.

In Django less than 1.4, a quick fix here. SESSION_COOKIE_SECURE=True. Editing django/middleware/

class CsrfViewMiddleware(object):
	def process_response(self, request, response):
			request.META["CSRF_COOKIE"], max_age = 60 * 60 * 24 * 7 * 52,
			secure=settings.SESSION_COOKIE_SECURE or None)

Direct HTTP requests to HTTPS in the webserver

server {
   listen 80;
   rewrite ^(.*) https://$host$1 permanent;

# # Turn on HSTS (HTTP Strict Transport Security) headers in your web server by adding a line to nginx:
# # This tells your web browser that your website for the next 10 years will be using HTTPS only. Enable this in caution!
# add_header Strict-Transport-Security max-age=31536000;

Make directs in Django always using HTTPS

# Either set the environment var:
os.environ['HTTPS'] = "on"
# Or
uwsgi --ini uwsgi.ini --evn HTTPS=on
# Or
# adding the line "env = HTTPS=on" to your uwsgi.ini file.
# See django/http/ for the need of setting HTTPS env var.

# If you are using wsgi:
os.environ['wsgi.url_scheme'] = 'https'

Submit to SSL Test.

Host header validation

Django validates Host headers against the ALLOWED_HOSTS setting in the django.http.HttpRequest.get_host() method.

This validation only applies via get_host(); if your code accesses the Host header directly from request.META you are bypassing this security protection.

Other concerns



python -m pdb runserver

Or insert in py (pythonDoc):

import pdb; pdb.set_trace()

from django.http import HttpResponse

def default(request):

	# completely innocuous variables
	foo = 1
	bar = 0

	# Set a break point here.
	import pdb; pdb.set_trace()

	ni = foo/bar

	return HttpResponse("Foo says %d" % ni, mimetype="text/plain")



If your tests rely on database access such as creating or querying models, be sure to create your test classes as subclasses of django.test.TestCase rather than unittest.TestCase. Using unittest.TestCase avoids the cost of running each test in a transaction and flushing the database.

Good examples


from django.test import TestCase
from myapp.models import Animal

class AnimalTestCase(TestCase):
	def setUp(self):
		Animal.objects.create(name="lion", sound="roar")
		Animal.objects.create(name="cat", sound="meow")

	def test_animals_can_speak(self):
		"""Animals that can speak are correctly identified"""
		lion = Animal.objects.get(name="lion")
		cat = Animal.objects.get(name="cat")
		self.assertEqual(lion.speak(), 'The lion says "roar"')
		self.assertEqual(cat.speak(), 'The cat says "meow"')


# RequestFactory

from django.test import TestCase
from django.test import RequestFactory

import views as myViews

class syncTest(TestCase):

	def setUp(self):
		self.factory = RequestFactory()

	def test_syncTimely(self):
		request = self.factory.get('/syncTimely/')
		response = myViews.syncTimely(request)
		self.assertEqual(response.status_code, 200)

For RequestFactory, see DjangoAdvancedTestingDoc.

# The -Wall flag tells Python to display deprecation warnings.
python -Wall test

# discover tests below that directory:
python -Wall test animals/

# if your test files are named differently from the test*.py pattern:
./ test --pattern="tests_*.py"

unittest module’s built-in test discovery. By default, this will discover tests in any file named “test*.py” under the current working directory.

The test database. Tests that require a database (namely, model tests) will not use your “real” (production) database. Separate, blank databases are created for the tests. Regardless of whether the tests pass or fail, the test databases are destroyed when all the tests have been executed.

By default the test databases get their names by prepending test_ to the value of the NAME settings for the databases defined in DATABASES. When using the SQLite database engine the tests will by default use an in-memory database (i.e., the database will be created in memory, bypassing the filesystem entirely!). If you want to use a different database name, specify NAME in the TEST dictionary for any given database in DATABASES.


In order to guarantee that all TestCase code starts with a clean database, the Django test runner reorders tests in the following way:

  1. All TestCase subclasses are run first.
  2. Then, all other Django-based tests (test cases based on SimpleTestCase, including TransactionTestCase) are run with no particular ordering guaranteed nor enforced among them.
  3. Then any other unittest.TestCase tests (including doctests) that may alter the database without restoring it to its original state are run.

Speeding up

In recent versions of Django, the default password hasher is rather slow by design. If during your tests you are authenticating many users, you may want to use a custom settings file and set the PASSWORD_HASHERS setting to a faster hashing algorithm:


Don’t forget to also include in PASSWORD_HASHERS any hashing algorithm used in fixtures, if any.

Builtin Loggers

DjangoLogging. Django provides several built-in loggers.

To silence a particular type of SuspiciousOperation, you can override that specific logger following this example:

'loggers': {
	'': {
		'handlers': ['null'],
		'propagate': False,
Test on unmanaged model

To make TEST use 'mytestdatabase' as databaseName instead of the default 'test_mydatabase', set here: DjangoProject.

	'default': {
		'ENGINE': 'django.db.backends.postgresql',
		'USER': 'mydatabaseuser',
		'NAME': 'mydatabase',
		'TEST': {
			'NAME': 'mytestdatabase',


from django.db import connection

class MyTest(unittest.TestCase):
	def setUp(self):
		connection.cursor().execute("CREATE TABLE ...")

	def tearDown(self):
		connection.cursor().execute("DROP TABLE ...")


Time zones

DjangoProject: timezones.

TIME_ZONE = 'Asia/Shanghai'


Auto populated fields

from django.template.defaultfilters import slugify

from django.contrib.auth.models import User
class TodoList(models.Model):
    title = models.CharField(maxlength=100)
    created = models.DateField(editable=False)
    updated = models.DateTimeField(editable=False)
    created_by = models.ForeignKey(User)
    objects = TodoListManager()
    def save(self):
        if not
            self.created =
        self.updated =
        super(TodoList, self).save()

class TodoListManager(models.Manager):
    def create_list(self, title, user):
        new_list = self.model(title=title, created_by=user)
        return new_list

from django import forms
class TodoListForm(forms.Manipulator):
    def __init__(self, request):
        self.fields = (
            forms.TextField(field_name='title', length=30, maxlength=100, is_required=True),
        self.request = request
    def save(self, new_data):
        return TodoList.objects.create_list(new_data['title'], self.request.user)

def create_todo_list(request):
    manipulator = TodoListForm(request)
    if request.POST:
        new_data = request.POST.copy()
        errors = manipulator.get_validation_errors(new_data)
        if not errors:
            new_list =
            return HttpResponseRedirect(new_list.get_absolute_url())
        errors = new_data = {}
    form = forms.FormWrapper(manipulator, new_data, errors)
    return render_to_response('create_todo_list.html', {'form': form})

How to name projects and apps


Try with Facebook:


Error: django.db.utils.OperationalError: no such table


If your or similar executes code that tries to access the DB when imported, i.e. importing has side effects, then starting from scratch won't work.

wcfNote. In my, there are global serializer defined like this:

data = Doctor.objects.all()
serializer = DoctorSerializer(data, many=True)

It causes trouble when running "makemigrations", which has several checking steps. Putting the lines into function scope makes the error gone.

Error: ImportError: No module named 'MySQLdb'


pip install PyMySQL

Add in the project's

import pymysql

Execute code only once

SO: execute code when django starts once only.

Django 1.7 now has a hook for this:

########## file: myapp/
from django.apps import AppConfig
class MyAppConfig(AppConfig):
    name = 'myapp'
    verbose_name = "My Application"
    def ready(self):
        pass # startup code here

########## file: myapp/
default_app_config = 'myapp.apps.MyAppConfig'

For Django < 1.7, put the startup code in any one of your INSTALLED_APPS e.g. myapp/

def startup():
    pass # load a big thing


When using ./ runserver this gets executed twice, but that is because runserver has some tricks to validate the models first etc. Normal deployments or even when runserver auto reloads, this is only executed once.