This page looks best with JavaScript enabled

Django Development Conventions (Part 1)

This article mainly lays out a few things to watch out for during Django development. A consistent coding style and sound design principles help a project’s development and maintenance, and are worth developers studying and discussing continuously.

1. Encoding Declaration

When the Python interpreter executes code, it needs to be told the encoding of the code. Python code is in fact text data; if the encoding of the code does not match the encoding the interpreter uses to read it, the code will fail to execute because of an encoding error. When the Python 2 interpreter reads code, the default encoding is ASCII, so if a non-ASCII character appears in the code, it raises an error. At that point you need to declare the encoding of the Python code.

1.1 Setting the Encoding the Interpreter Uses to Read Code

To keep the format the Python interpreter uses to read code consistent, it is recommended to add a utf-8 encoding declaration uniformly at the head of the code file:

1
# coding:utf-8

The following style, re-setting the encoding inside the code, is forbidden:

1
2
3
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

This way of setting things causes two problems:

  • Character arguments that require ASCII encoding cannot be passed through
  • When Chinese is used as a dict key value, bizarre program behavior appears: the comparison behavior of in and == becomes inconsistent.

1.2 The Encoding of Strings

There are three string types in Python:

  • unicode, text string, text data
  • str, byte string, binary data
  • basestring, the parent class of the previous two.

In Python 2 the string ‘xxx’ denotes str, and u’xxx’ denotes unicode. In Python 3, both u’xxx’ and ‘xxx’ denote unicode. And b’xxx’ denotes binary data in both Python 2 and Python 3.

In Python 2, __future__ provides the unicode_literals module, which turns all strings in the current file into unicode, for compatibility with Python 3 character encoding.

1
2
3
4
# coding:utf-8
from __future__ import unicode_literals

print type('测试')
<type 'unicode'>

A str stored as bytes must have the b prefix. In the example below, because unicode_literals is set, strings in the code default to unicode encoding, whereas the strftime function accepts a binary string. At that point you need to explicitly declare %m月%d日 %H:%M as a binary string; otherwise it raises an error at execution time.

1
2
3
4
5
6
# coding:utf-8
from __future__ import unicode_literals

from datetime import datetime

print datetime.now().strftime(b'%m月%d日 %H:%M')

2. PEP8

2.1 Naming

  • Module names
    All lowercase where possible; underscores are also acceptable module django_module
  • Global variables\constants
    All uppercase + underscore-style camel case GLOBAL_VAR
  • Class names
    Capitalized-style camel case ClassName()
  • Function names
    All lowercase + underscore camel case is_valid_data()
  • Local variables
    All lowercase + underscore-style camel case this_is_var

2.2 flake 8

Flake8 is a tool released by the Python project to help detect whether Python code conforms to the conventions. Flake8 contains three tools:

  • PyFlakes
    A tool that statically checks Python code for logical errors.
  • Pep8
    A tool that statically checks the PEP8 coding style.
  • NedBatchelder’s McCabe script
    A tool that statically analyzes the complexity of Python code.

How to install:

1
pip install flake8

Usage:

1
2
3
4
5
6
7
# 查看使用帮助文档
flake8 -h
# 检查某个文件
flake8 your.py
your.py:1:1: E265 block comment should start with '# '
# 检查当前目录
flake8 ./

flake8 detects whether the code has logical errors, whether it conforms to the PEP8 conventions, and the code’s complexity. More importantly, flake8 gives detailed hints, down to the line and column, along with suggested fixes.

3. Package Imports

3.1 import Order

  1. Standard library
  2. Third-party libraries
  3. The project itself

3.2 import Format

  • On a separate line
  • Use absolute paths. Python 2 imports are relative by default, Python 3 imports are absolute by default; it is recommended to use absolute paths uniformly. Absolute-path imports avoid a submodule shadowing a standard library module. __future__ provides the absolute_import module for support.
  • Use import x to import packages and modules; do not use import *
  • Use from x import y, where x is the package prefix and y is the module name without the prefix.
  • Use from x import y as z, if the two modules to import are both named y, or y is too long.

3.3 isort

isort is a Python utility/library that sorts imports alphabetically and automatically splits them into sections. It provides a command-line utility, a Python library, and plugins for various editors, so you can quickly sort all imports. It currently cleanly supports Python 2.7 - 3.6, with no dependencies.

Installation:

1
pip install isort

Usage:

1
2
3
4
# 对单个文件中的导入排序
isort you.py
# 对整个目录进行导入排序
isort ./

4. Order of Definitions Inside models

  • Database fields
  • Non-database fields
  • The default objects manager
  • Custom manager attributes (i.e. other managers)
  • class Meta
  • def natural_key() (because it is closely tied to the model)
  • All @cached_property properties
  • Any method decorated with @classmethod
  • def __unicode__()
  • def __str__()
  • Any method starting with __ (such as __init__())
  • def save()
  • def delete()
  • def get_absolute_url()
  • def get_translate_url()
  • Any custom method

It is worth noting here that displaying an object’s name in the Django admin uses __unicode__() on Python 2 and __str__() on Python 3. To be compatible with both styles, you can use the python_2_unicode_compatible decorator.

1
2
3
4
5
6
7
8
from django.db import models
from django.utils.encoding import python_2_unicode_compatible

@python_2_unicode_compatible
class MyModel(models.Model):
# ...
    def __str__(self):              # __unicode__ on Python 2
        return self.my_show_name

5. The Zen of Python

The best exposition of the Python philosophy is none other than the Zen of Python, summarized by core developer Tim Peters.

1
import this
  • Python aims for writing beautiful code
  • Code should be clear, with consistent naming and similar style
  • Code should be concise, without complex internal implementations
  • If complexity is unavoidable, there still should not be hard-to-understand relationships between pieces of code; keep interfaces concise
  • Code should be flat, without too much nesting
  • Code should be spaced appropriately; do not expect one line of code to solve everything
  • Code should have good readability
  • Even when there are special cases, do not violate these principles
  • Catch exceptions precisely; do not write code in the except: pass style
  • When multiple possibilities exist, do not try to guess
  • If you are unsure, use brute force
  • You are not the father of Python; some problems cannot be solved
  • Think the approach through before writing code
  • If you cannot clearly describe an implementation to others, then it is certainly not a good approach
  • Make good use of namespaces

6. Code Commit Comments

1
2
3
4
5
6
7
bugfix : 线上功能 Bug 修复
sprintfix:未上线代码修改
minor:不重要的修改(换行,拼写错误等)
feature :新功能说明
improvement :已有功能优化
documentation :新增说明文档,比如 readme.md 文件
refactoring:代码重构

7. References


微信公众号
WRITTEN BY
微信公众号