Django 学习笔记(二)—— 第一个自定义应用 上篇

本文接上篇 Django 学习笔记(一)—— 快速建站,前提是已经完成了 Django 开发环境的搭建和 MySQL 数据库的关联。
本教程将创建一个基本的投票应用程序,包含供人们参与投票的公共站点和一个可操作后台数据的管理平台。
主要参考自 Django 2.2 官方文档

一、创建项目

$ django-admin startproject mysite

该命令会在当前目录下创建一个 mysite 目录,并且该框架中已经包含了一个初始 Django 项目必需的所有组件。
其目录结构如下:

1
2
3
4
5
6
7
mysite
├── manage.py
└── mysite
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py

进入 manage.py 所在的目录下,运行 python manage.py runserver 0000:8000 即可运行一个用于开发的简易服务器:

1
2
3
4
5
6
7
8
9
10
$ python manage.py runserver 0.0.0.0:8000
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

June 22, 2019 - 07:47:04
Django version 2.2.2, using settings 'mysite.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.

访问效果如下:
django

二、创建投票应用

PS:“应用”是一个专门用于做某件事的应用程序,比如博客或者简单的投票程序,“项目”则是一个网站所包含的配置和应用的合集。
一个项目可以包含多个应用,一个应用也可以被多个项目使用。

Django 中的每个应用都是一个 Python 包,可以通过 manage.py 创建应用的基础目录结构:
$ python manage.py startapp polls

当前目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
mysite
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── polls
├── admin.py
├── apps.py
├── __init__.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

编辑视图(View)

编辑 polls/views.py 文件,代码如下:

1
2
3
4
from django.http import HttpResponse

def index(request):
return HttpResponse("Hello Wrold. This is the index page.")

创建 URL 映射

polls 目录下创建 urls.py 文件,编辑输入如下内容以完成到 index 页面的 URL 映射

1
2
3
4
5
6
from django.urls import path
from . import views

urlpatterns = [
path('',views.index, name='index'),
]

根 URLconf 文件中(即 mysite/urls.py)引入刚刚创建的 polls.urls 模块(即 polls/urls.py):

1
2
3
4
5
6
7
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]

运行测试服务器,访问 http://127.0.0.1:8000/polls ,最终效果如下:
index page

三、创建模型(Model)

在 Django 中,对于一个数据驱动的 Web 应用,定义模型(即数据库的结构设计)是非常必要的一个操作。

本应用中需要创建两个模型:

  • 问题 Question 模型:包含问题描述和发布时间
  • 选项 Choice 模型:包含选项描述和当前票数

编辑 polls/models.py 文件,具体结构定义如下:

1
2
3
4
5
6
7
8
9
10
from django.db import models

class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')

class Choice(model.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)

上述模型代码可以被 Django 用来创建本应用的数据库 schema(生成 CREATE TABLE 语句)。
不过需要先在 mysite/settings.py 配置文件中修改 INSTALLED_APPS 变量,Django 需要依据该变量中对应用的指定进行数据库迁移操作。

1
2
3
4
5
6
7
8
9
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]

运行 python manage.py makemigrations polls 命令创建数据库迁移文件:

1
2
3
4
5
$ python manage.py makemigrations polls
Migrations for 'polls':
polls/migrations/0001_initial.py
- Create model Question
- Create model Choice

运行 python manage.py migrate 命令完成数据库迁移操作:

1
2
3
4
5
6
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Applying polls.0001_initial... OK
...

PS:在运行 migrate 命令之前,可以使用 python manage.py sqlmigrate polls 0001 查看该次迁移操作具体会执行哪些 SQL 语句:

1
2
3
4
5
6
7
8
9
10
11
12
 python manage.py sqlmigrate polls 0001
BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "question_text" varchar(200) NOT NULL, "pub_date" datetime NOT NULL);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "choice_text" varchar(200) NOT NULL, "votes" integer NOT NULL, "question_id" integer NOT NULL REFERENCES "polls_question" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;

四、数据库 API

可以通过运行 python manage.py shell 进入 Python 交互式命令行,尝试 Django 提供的各种数据库 API 。示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ python manage.py shell
Python 3.7.3 (default, Apr 3 2019, 05:39:12)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet []>
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
>>> q.save()
>>> q.id
1
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2019, 6, 24, 15, 34, 47, 614267, tzinfo=<UTC>)
>>> q.question_text = "What's up"
>>> q.save()
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
>>>

上面的示例中,<Question: Question object (1)> 类型的输出不便于了解对象的细节,可以通过修改 Question 模型的代码来改变 Question.objects.all() 函数的行为。
polls/models.py 内容改为如下形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from django.db import models

class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')

def __str__(self):
return self.question_text

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

此时再次尝试使用数据库 API :

1
2
3
4
5
6
7
8
9
$ python manage.py shell
Python 3.7.3 (default, Apr 3 2019, 05:39:12)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet [<Question: What's up>]>
>>>

给模型增加 __str__() 方法只是其中一种形式,实际上可以添加任意需要的函数以供后期调用。

五、后台管理系统(Django admin)

Django admin 是任何一个初始的 Django 项目(完成数据库同步之后)默认开启的应用,用于对项目关联的数据库表进行基本的增删改查操作。

首先需要创建用于登录后台系统的管理员账户:

1
2
3
4
5
6
$ python manage.py createsuperuser
Username (leave blank to use 'starky'):
Email address:
Password:
Password (again):
Superuser created successfully.

开启测试服务器(python manage.py runserver 0000:8000),访问 http://127.0.0.1:8000/admin/,使用刚刚创建的管理员账户登录,效果如下:
login
Django admin

将 poll 应用添加至后台

修改 polls/admin.py 文件,将 Question 对象添加至后台面板:

1
2
3
4
from django.contrib import admin
from .models import Question

admin.site.register(Question)

启动测试服务器,访问后台页面效果如下:
POLLS

PS:中文界面可以修改配置文件 mysite/settings.py,将 LANGUAGE_CODE 项改为如下形式:LANGUAGE_CODE = 'zh-Hans'

之后便可以在后台页面直接对之前 MySQL 中创建的 polls_question 数据表进行编辑操作:
edit table

参考资料

Django 2.2 官方文档