Django的默认数据库是SQLite,因为Python源生支持SQLite数据库,所以你无须安装任何程序,就可以直接使用它。当然也支持其他数据库(PostgreSQL), (MySQL) , (SQLite),(Oracle) 等,考虑后续数据库迁移处理比较方便。
打开mysite/settings.py
配置文件,这是整个Django项目的设置中心。
# mysite/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
如果你想使用其他的数据库,请先安装相应的数据库操作模块,并将mysite/settings.py
文件中DATABASES位置的’default’的键值进行相应的修改,用于连接你的数据库。其中:
django.db.backends.sqlite3、django.db.backends.postgresql、django.db.backends.mysql、django.db.backends.oracle,
当然其它的也行。os.path.join(BASE_DIR, ’db.sqlite3’)
,将把该文件储存在你的项目目录下。如果你不是使用默认的SQLite数据库,那么一些诸如USER,PASSWORD和HOST的参数必须手动指定!下面给出一个基于pymysql操作Mysql数据库的例子。
# mysite/settings.py
import pymysql # 一定要添加这两行!通过pip install pymysql!
pymysql.install_as_MySQLdb()
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mysite',
'HOST': '192.168.100.12',
'USER': 'root',
'PASSWORD': 'pwd',
'PORT': '3306',
}
}
注意:
CREATE DATABASE database_name;
”。Django不会自动帮你做这一步工作。mysite/settings.py
文件中提供的数据库用户具有创建数据库表的权限,因为后面需要自动创建一个test数据表。(在实际项目中也需要确认这一条要求。)mysite/settings.py
文件时,更改TIME_ZONE
时区为Asia/Shanghai
。同时,请注意mysite/settings.py
文件中顶部的INSTALLED_APPS
设置项。它列出了所有的项目中被激活的Django应用(app)。你必须将你自定义的app注册在这里。每个应用可以被多个项目使用,并且可以打包和分发给其他人在他们的项目中使用。
默认情况,INSTALLED_APPS中会自动包含下列条目,它们都是Django自动生成的:
django.contrib.admin:admin管理后台站点
django.contrib.auth:身份认证系统
django.contrib.contenttypes:内容类型框架
django.contrib.sessions:会话框架
django.contrib.messages:消息框架
django.contrib.staticfiles:静态文件管理框架
上面的一些应用也需要建立一些数据库表,所以在使用它们之前我们要在数据库中创建这些表。使用下面的命令创建数据表:
python manage.py migrate
migrate命令将遍历INSTALLED_APPS设置中的所有项目,在数据库中创建对应的表,数据库的迁移还会跟踪应用的变化,并打印出每一条动作信息。如果你有兴趣,可以在你的数据库命令行下输入:\dt (PostgreSQL)、 SHOW TABLES;(MySQL)或 .schema(SQLite) 来显示 Django 创建的表。
提示:
对于极简主义者,你完全可以在INSTALLED_APPS内注释或删除掉任何或者全部的Django提供的通用应用。这样,migrate也不会再创建对应的数据表。
定义该应用的模型——本质上,就是定义该模型所对应的数据库设计及其附带的元数据。
Django通过自定义Python类的形式来定义具体的模型,每个模型的物理存在方式就是一个Python的类Class,每个模型代表数据库中的一张表,每个类的实例代表数据表中的一行数据,类中的每个变量代表数据表中的一列字段。Django通过模型,将Python代码和数据库操作结合起来,实现对SQL查询语言的封装。也就是说,你可以不会管理数据库,可以不会SQL语言,你同样能通过Python的代码进行数据库的操作。Django通过ORM对数据库进行操作,奉行代码优先的理念,将Python程序员和数据库管理员进行分工解耦。
在这个简单的投票应用中,我们将创建两个模型:Question和Choice。Question包含一个问题和一个发布日期。Choice包含两个字段:该选项的文本描述和该选项的投票数。每一条Choice都关联到一个Question。这些都是由Python的类来体现,编写的全是Python的代码,不接触任何SQL语句。现在,编辑polls/models.py文件,具体代码如下:
# polls/models.py
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
上面的代码非常简单。每一个类都是django.db.models.Model
的子类。每一个字段都是Field类的一个实例,例如用于保存字符数据的CharField
和用于保存时间类型的DateTimeField
,它们告诉Django每一个字段保存的数据类型。
每一个Field实例的名字就是字段的名字(如: question_text 或者 pub_date )。在你的Python代码中会使用这个值,你的数据库也会将这个值作为表的列名称。
你也可以在每个Field中使用一个可选的第一位置参数用于提供一个人类可读的字段名,让你的模型更友好,更易读,并且将被作为文档的一部分来增强代码的可读性。
一些Field类必须提供某些特定的参数。例如CharField需要你指定max_length。这不仅是数据库结构的需要,同样也用于数据验证功能。
有必填参数,当然就会有可选参数,比如在votes里我们将其默认值设为0.
最后请注意,我们使用ForeignKey定义了一个外键关系。它告诉Django,每一个Choice关联到一个对应的Question(注意要将外键写在‘多’的一方)。Django支持通用的数据关系:一对一,多对一和多对多。
上面的代码看着有点少,其实包含了大量的信息,据此,Django会做下面两件事:
CREATE TABLE
语句);Question
和Choice
对象创建基于Python的数据库访问API但是,首先得在INSTALLED_APPS中添加此应用,我们得先告诉Django项目,我们要使用投票app。
要将应用添加到项目中,需要在INSTALLED_APPS
设置中增加指向该应用的配置文件的链接。对于本例的投票应用,它的配置类文件是polls/apps.py
,引用路径格式为polls.apps.PollsConfig
,并将该路径添加到 INSTALLED_APPS
设置:
# mysite/settings.py
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
实际上,在多数情况下,我们简写成‘polls’就可以了:
# mysite/settings.py
INSTALLED_APPS = [
'polls',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
现在Django已经知道你的投票应用的存在了,并把它加入了项目大家庭。
我们需要再运行下一个命令:
python manage.py makemigrations polls
你会看到类似下面的提示:
Migrations for 'polls':
polls/migrations/0001_initial.py
- Create model Choice
- Create model Question
- Add field question to choice
通过运行makemigrations
命令,相当于告诉Django你对模型有改动,并且你想把这些改动保存为一个“迁移(migration)”。
migrations
是Django保存模型修改记录的文件,这些文件保存在磁盘上。在例子中,它就是polls/migrations/0001_initial.py
,你可以打开它看看,里面保存的都是人类可读并且可编辑的内容,方便你随时手动修改。
接下来有一个叫做migrate的命令将对数据库执行真正的迁移动作。但是在此之前,让我们先看看在migration的时候实际执行的SQL语句是什么。有一个叫做sqlmigrate的命令可以展示SQL语句,例如:
python manage.py sqlmigrate polls 0001
你将会看到如下类似的文本:
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL);
--
-- 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);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" RENAME TO "polls_choice__old";
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"));
INSERT INTO "polls_choice" ("choice_text", "votes", "id", "question_id")
SELECT "choice_text", "votes", "id", NULL FROM "polls_choice__old";
DROP TABLE "polls_choice__old";
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");
COMMIT;
请注意:
auto_increment (MySQL), serial (PostgreSQL)
, 或integer primary key (SQLite)
。 在引用字段名时也是如此 –比如使用双引号或单引号。如果你感兴趣,也可以运行python manage.py check命令,它将检查项目中的错误,并不实际进行迁移或者链接数据库的操作。
现在,我们可以运行migrate命令,在数据库中进行真正的表操作了。
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Rendering model states... DONE
Applying polls.0001_initial... OK
migrate命令对所有还未实施的迁移记录进行操作,本质上就是将你对模型的修改体现到数据库中具体的表上面。Django通过一张叫做django_migrations的表,记录并跟踪已经实施的migrate动作,通过对比获得哪些migrations尚未提交。
migrations的功能非常强大,允许你随时修改你的模型,而不需要删除或者新建你的数据库或数据表,在不丢失数据的同时,实时动态更新数据库。我们将在后面的章节对此进行深入的阐述,但是现在,只需要记住修改模型时的操作分三步:
models.py
中修改模型;python manage.py makemigrations
为改动创建迁移记录;python manage.py migrate
,将操作同步到数据库。之所以要将创建和实施迁移的动作分成两个命令两步走是因为你也许要通过版本控制系统(例如github,svn)提交你的项目代码,如果没有一个中间过程的保存文件(migrations),那么github如何知道以及记录、同步、实施你所进行过的模型修改动作呢?毕竟,github不和数据库直接打交道,也没法和你本地的数据库通信。但是分开之后,你只需要将你的migration文件(例如上面的0001)上传到github,它就会知道一切。
现在,进入Python的交互式shell,玩转这些Django提供给你的API。 使用如下命令来调用Python shell:
python manage.py shell
我们使用上述命令而不是简单地键入“python”进入python环境,是因为 manage.py
设置了 DJANGO_SETTINGS_MODULE
环境变量,该环境变量将自动按照 mysite/settings.py
配置好你的python shell环境,这样,你就可以导入和调用任何你项目内的模块了。
或者你也可以这样,先进入一个纯净的python shell环境,然后启动Django,具体如下:
import django
django.setup()
在shell中,试试数据库API:
>>> from polls.models import Question, Choice # 导入我们写的模型类
# question为空
>>> Question.objects.all()
# 新建一个Question
# 在默认设置文件中启用对时区的支持, Django推荐使用timezone.now()代替python内置的datetime.datetime.now()
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
# 调用save()方法,将内容保存到数据库中
>>> q.save()
# 默认情况,你会自动获得一个自增的名为id的主键
>>> q.id
1
# 通过python的属性调用方式,访问模型字段的值
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2018, 11, 20, 2, 11, 47, 514250, tzinfo=)
# 通过修改属性来修改字段的值,然后调用save方法进行保存。
>>> q.question_text = "What's up?"
>>> q.save()
# objects.all() 用于查询数据库内的所有questions
>>> Question.objects.all()
]>
这个对象是一个不可读的内容展示,你无法从中获得任何直观的信息。 让我们来修复这个问题,让Django在打印对象时显示一些我们指定的信息。 修改 Question 模
型(在 polls/models.py
文件中)并添加一个 __str__()
方法给 Question 和 Choice
:
polls/models.py
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible # 当你想支持python2版本的时候才需要这个装饰器
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
@python_2_unicode_compatible # 当你想支持python2版本的时候才需要这个装饰器
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
在模型中添加 str() 方法非常重要,不仅仅在处理交互时提示, 而且在Django自动生成的管理界面中也能使用。
如下添加一个自定义的方法:
polls/models.py
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
保存修改后,我们重新启动一个新的python shell
运行 python manage.py shell
,再来看看其他的API:
>>> from polls.models import Question, Choice
# 添加__str__() 后的效果.
>>> Question.objects.all()
]>
# Django提供了大量的关键字参数查询API
>>> Question.objects.filter(id=1)
]>
>>> Question.objects.filter(question_text__startswith='What')
]>
# 获取今年发布的问卷
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
# 查询一个不存在的ID,会抛出异常
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.
# Django为主键查询提供了一个缩写:pk。下面的语句和Question.objects.get(id=1)效果一样.
>>> Question.objects.get(pk=1)
# 看看我们自定义的方法用起来怎么样
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True
# 让我们试试主键查询
>>> q = Question.objects.get(pk=1)
# 显示所有与q对象有关系的choice集合,目前是空的,还没有任何关联对象。
>>> q.choice_set.all()
# C创建3个choices.
>>> q.choice_set.create(choice_text='Not much', votes=0)
>>> q.choice_set.create(choice_text='The sky', votes=0)
>>> c = q.choice_set.create(choice_text='Just hacking again', votes=0)
# Choice对象可通过API访问和他们关联的Question对象
>>> c.question
# 同样的,Question对象也可通过API访问关联的Choice对象
>>> q.choice_set.all()
, , ]>
>>> q.choice_set.count()
3
# API会自动进行连表操作,通过双下划线分割关系对象。连表操作可以无限多级,一层一层的连接。
# 下面是查询所有的Choices,它所对应的Question的发布日期是今年。(重用了上面的current_year结果)
>>> Choice.objects.filter(question__pub_date__year=current_year)
, , ]>
# 使用delete方法删除对象
>>> c = q.choice_set.filter(choice_text__startswith='Just hacking')
>>> c.delete()
这部分模块内容是Django项目的核心,也是动态网站与数据库交互的核心,务必要充分理解!!!
django提供了一个基于项目model创建的一个后台管理站点admin(给后台管理人员提供的相应的管理界面)。这个界面只给站点管理员使用,并不对大众开放。虽然admin的界面可能不是那么美观,功能不是那么强大,内容不一定符合你的要求,但是它是免费的、现成的,并且还是可定制的,有完善的帮助文档。
5.1 创建管理用户
创建一个可以登录到管理网站的用户admin
# python manage.py createsuperuser
Username (leave blank to use 'root'): admin #用户名
Email address: [email protected] #邮箱
Password: #密码
Password (again):
Superuser created successfully.
5.2 启动开发服务器
Django的管理站点是默认启用的。
python manage.py runserver 0.0.0.0:8000
打开Web浏览器,访问http://172.16.92.30:8000/admin/,会看到管理员的登录界面.
在实际环境中,为了站点的安全性,我们不能将管理后台的url随便暴露给他人,不能用/admin/这么简单的路径。
打开根url路由文件mysite/urls.py
,修改其中admin.site.urls
对应的正则表达式,换成你想要的,比如:
mysite/urls.py
from django.conf.urls import include,url
from django.contrib import admin
urlpatterns = [
url(r'hi/mysite', admin.site.urls),
]
我们必须访问http://172.16.92.30:8000/hi/mysite才能进入admin界面.
5.3. 进入admin站点
使用上面创建的超级用户admin登录,进入Django管理员index页面:
当前只有两个可编辑的内容:groups和users。它们是django.contrib.auth
模块提供的身份认证框架.
4. 在admin中注册投票应用
现在还无法看到投票应用,必须先在admin中进行注册,告诉admin站点,请将poll的模型加入站点内,接受站点的管理。
打开 polls/admin.py
文件,加入下面的内容:
polls/admin.py
from django.contrib import admin
from .models import Question
admin.site.register(Question)
5. admin站点的主要功能
注册question模型后,刷新admin页面就能看到Question栏目:
点击 Questions
,进入questions
的修改列表页面。这个页面会显示所有的数据库内的questions
对象, 你可以在这里对它们进行修改。看到下面的“What’s up?”
了么?它就是我们先前创建的一个question
, 并且通过 __str__
方法的帮助,显示了较为直观的信息,而不是一个冷冰冰的对象类型名称。
点击What’s up?
进入编辑界面:
需要注意的是:
DateTimeField、 CharField
)会对应相应的HTML输入控件。DateTimeField
在页面的底部,则是一些可选项按钮:
如果“Date published
”字段的值和你在前面创建它的时候不一致, 可能是你没有正确的配置 TIME_ZONE
,在国内,通常是8个小时的时间差别。 修改 TIME_ZONE = 'Asia/Shanghai'
配置并重新加载页面,就能显示正确的时间了。
通过“Today
”和“Now
”这两个快捷方式来更改“Date published
”字段。 然后点击 “Save and continue editing
”。然后点击右上角的“History
”按钮。 你将看到一个页面,列出了通过Django管理界面对此对象所做的全部更改的清单,包含有时间戳和修改人的姓名等信息: