本文接上篇 Django 学习笔记(一)—— 快速建站,前提是已经完成了 Django 开发环境的搭建和 MySQL 数据库的关联。
本教程将创建一个基本的投票应用程序,包含供人们参与投票的公共站点和一个可操作后台数据的管理平台。
主要参考自 Django 2.2 官方文档。
一、创建项目
$ django-admin startproject mysite
该命令会在当前目录下创建一个 mysite 目录,并且该框架中已经包含了一个初始 Django 项目必需的所有组件。
其目录结构如下:1
2
3
4
5
6
7mysite
├── 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.
访问效果如下:
二、创建投票应用
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
16mysite
├── 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
4from 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
6from 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
7from 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 ,最终效果如下:
三、创建模型(Model)
在 Django 中,对于一个数据驱动的 Web 应用,定义模型(即数据库的结构设计)是非常必要的一个操作。
本应用中需要创建两个模型:
- 问题 Question 模型:包含问题描述和发布时间
- 选项 Choice 模型:包含选项描述和当前票数
编辑 polls/models.py
文件,具体结构定义如下:1
2
3
4
5
6
7
8
9
10from 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 | INSTALLED_APPS = [ |
运行 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
16from 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/,使用刚刚创建的管理员账户登录,效果如下:
将 poll 应用添加至后台
修改 polls/admin.py
文件,将 Question 对象添加至后台面板:1
2
3
4from django.contrib import admin
from .models import Question
admin.site.register(Question)
启动测试服务器,访问后台页面效果如下:
PS:中文界面可以修改配置文件 mysite/settings.py
,将 LANGUAGE_CODE
项改为如下形式:LANGUAGE_CODE = 'zh-Hans'
之后便可以在后台页面直接对之前 MySQL 中创建的 polls_question 数据表进行编辑操作: