这个教程接着第一个部分。我们将安装数据库,创建你的第一个模型,并且得到一个快速的介绍关于Django自动生成的管理站点。
1. 数据库安装
现在,打开mysite/settings.py。他是一个正常的Python模块,带有模块级的变量表明Django的设置。
默认的,配置使用SQLITE.如果你是一个数据新手,或者你仅仅对Django感兴趣,这将是最简单的选择。SQLite包含在Python中,所以你不需要安装任何其他的东西来支持你的数据库。当开始你的第一个真是项目时,然而你也许想使用一个可扩展的数据库例如PostgreSQL,来避免在路上切换数据库的麻烦。
如果你想使用另外一个数据库,安装喜爱的数据库绑定并且在数据库”默认“项中更改如下键来匹配你的数据库连接设置:
- ENGINE--要么'django.db.backends.sqlite3','django.db.backends.postgresql','django.db.backends.mysql',或者'django.db.backends.oracle'.其他后端同样可以。
- NAME--你的数据库的名称。如果你使用SQLite,数据库是你电脑上的一个文件;在那种情况下,NAME应该是全部的绝对地址,包括文件名。默认值,os.path.join(BASE_DIR,'db.sqlite3'),将文件储存在你的项目目录下。
当你在编辑mysite/settings.py时,将TIME_ZONE添加到你的时区。
同样,注意在文件顶部的INSTALLED_APPS设置。那是在Django实例中激活的所有Django应用的名称。应用可以被用于多个项目,你可以打包并分发它们,以供其他人在他们的项目中使用。
默认的,INSTALLED_APPS包含如下的应用,都是伴随Django的:
- django.contrib.admin -- 管理站点。你稍后就将使用它。
- django.contrib.auth -- 一个计算系统。
- django.contrib.contenttypes -- 内容类型的框架。
- django.contrib.sessions -- 会话框架。
- django.contrib.messages -- 消息框架。
- django.contrib.staticfiles -- 管理静态文件的框架。
$ python manage.py migrate
为了极简主义
像上面说的,默认的应用包含在普通的情况中,但并不是每个人都需要。如果你不需要任何它们或者不需要所有的,你可以在运行migrate之前从INSTALLED_APPS中自由注释或者删除相关的行。migrate命令只会运行在INSTALLED_APPS中的应用。
2. 创建模型
现在我们来定义你的模型--本质上,你的数据库布局,带有额外的元数据。
哲理
模型是一个关于你的数据的单独的,明确的源的真相。它包含必要的字段和你储存数据的行为。Django遵循DRY Principle。目的是在一个地方定义你的数据模型并且自动从里面获取东西。
这包含迁移--不像Ruby On Rails,例如,迁移完全从你的模型文件中派生,并且实际是Django能读取来更新你的数据结构来匹配你当前的模型。
在我们简单的poll应用中,我们将创建2个模型:Question和Choice。一个Question有一个问题和一个出版日期。一个Choice有2个字段:choice的文本和一个投票结果。每一个Choice都关联到一个Question。
这些概念由简单的Python类展示。编辑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_data)都是字段的名称,以一种机器友好的格式。你将在Python代码中使用这个值,你的数据库会将它用作一个列名称。
你可以对一个Field使用一个可选的第一位置参数来设计一个人类可读的名称。那被用在许多Django的内置部分,作为文档的时候更多。如果这个字段没有提供,Django将会使用机器可读名称。在上面例子中,我们只定义了一个人类可读的名称Question.pub_data。对于这个模型的所有其他字段来说,这个字段的机器可用名称足以作为人类可读名称。
一些Field类有需要的参数,CharField,例如,需要你给他max_length。那不仅仅在数据结构中使用,同样也在校验的时候,我们稍后会看到。
一个Field同样有不同的可选参数;在这个例子中,我们将votes的default指设为0.
最终,注意一个关联被定义了,使用ForeignKey。它告诉Django每一个Choice被关联到了一个Question。Django支持所有的常见的数据库关系:多对一,多对多,一对一。
3. 激活模型
那一点模型代码给Django提供了很多信息。使用它,Django可以:
- 为这个应用创建一个数据库结构(CREATE TABLE 语句)。
- 创建一个Python数据库访问API用于访问Question和Choice对象。
哲理
Django应用是“可插拔的”:你可以在多个项目中使用一个应用,你也可以分开应用,因为他们不必和一个指定的Django安装绑定在一起
为了在我们的项目中包含应用,我们需要在他的INSTALLED_APPS设置的配置类中添加一个引用。PollsConfig类在Polls/apps.py文件中,所以它的带点路径是polls.apps.PollsConfig。编辑mysite/settings.py文件并且添加点路径到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',
]
$ python manage.py makemigrations polls
Migrations for 'polls':
polls/migrations/0001_initial.py:
- Create model Choice
- Create model Question
- Add field question to choice
$ python manage.py sqlmigrate polls 0001
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL
);
--
-- Create model Question
--
CREATE TABLE "polls_question" (
"id" serial NOT NULL PRIMARY KEY,
"question_text" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
--
-- Add field question to choice
--
ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL;
ALTER TABLE "polls_choice" ALTER COLUMN "question_id" DROP DEFAULT;
CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id");
ALTER TABLE "polls_choice"
ADD CONSTRAINT "polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id"
FOREIGN KEY ("question_id")
REFERENCES "polls_question" ("id")
DEFERRABLE INITIALLY DEFERRED;
COMMIT;
- 准确的输出取决你你使用的数据库。上面的例子是由PostgreSQL产生的。
- 表名通过组合应用的名字和模型的小写名字--question和choice来自动产生(你可以覆写这个行为。)
- 主键(IDs)是自动被添加的。(你也可以覆写这个)
- 根据惯例,Django添加“_id”在外键的字段名称上。(是的,你也可以覆写这个。)
- 外键关系是通过FOREIGN KEY的约束来显示形成的。不要担心DEFERRABLE部分;那就是告诉PostgreSQL在事务结束前不要强制执行外键。
- 它会根据你使用的数据库来自适应,所以数据库指定的特殊字段诸如auto_increment(MySql),serial(PostgreSQL),或者integer primary key autoincrement(SQLite)将会为你自动处理。引用字段名也一样--例如,使用双引号或单引号。
- sqlmigrate命令实际上不会在你的数据库上执行迁移--它仅仅将它打印到屏幕上所以你可以看到Django认为什么样的SQL是需要的。检查Django将做的事情是很重要的或者如果你的数据库管理员要求改变SQL脚本。
$ 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
- 改变你的模型(在models.py)
- 执行python manage.py makemigrations来为这些改变创建迁移
- 执行python manage.py migrate来讲这些改变应用到你的数据库
4. 使用API
$ python manage.py shell
绕过manage.py
如果你不想使用manage.py,没问题。只要设置在mysite.settings中的DJANGO_SETTINGS_MODULE环境变量,启动一个普通的Python shell,设置Django:
>>> import django
>>> django.setup()
如果这抛出一个AttributeError,你可能正在使用一个不匹配这个教程版本的Django版本。那么你可以切换到老的教程或者升级你的Django版本。
你必须从manage.py相同的路径来运行python,或者确保那个路径在Python的路径中,那样import mysite才会生效。
想看更多关于这个的嘻嘻,你可以阅读django管理文档。
一旦你在shell,就可以探索数据API:>>> from polls.models import Question, Choice # Import the model classes we just wrote.
# No questions are in the system yet.
>>> Question.objects.all()
<QuerySet []>
# Create a new Question.
# Support for time zones is enabled in the default settings file, so
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())
# Save the object into the database. You have to call save() explicitly.
>>> q.save()
# Now it has an ID. Note that this might say "1L" instead of "1", depending
# on which database you're using. That's no biggie; it just means your
# database backend prefers to return integers as Python long integer
# objects.
>>> q.id
1
# Access model field values via Python attributes.
>>> q.question_text
"What's new?"
>>> q.pub_date
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?"
>>> q.save()
# objects.all() displays all the questions in the database.
>>> Question.objects.all()
<QuerySet [<Question: Question object>]>
polls/models.py
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible # only if you need to support Python 2
class Question(models.Model):
# ...
def __str__(self):
return self.question_text
@python_2_unicode_compatible # only if you need to support Python 2
class Choice(models.Model):
# ...
def __str__(self):
return self.choice_text
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)
>>> from polls.models import Question, Choice
# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>
# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith='What')
<QuerySet [<Question: What's up?>]>
# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>
# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
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.objects.get(pk=1)
<Question: What's up?>
# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
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.
>>> q.choice_set.all()
<QuerySet []>
# 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.
>>> c.question
<Question: What's up?>
# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
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.objects.filter(question__pub_date__year=current_year)
<QuerySet [<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')
>>> c.delete()
5. 引进Django管理
哲理
为你的工作人员或者客户生成管理站点来添加,修改和删除内容是不需要太多创造性的乏味的工作。因为那个原因,Django使用模型完全自动创建了管理接口。
Django是在一个新闻工作室环境下编写的,它在“内容出版商”和“公共”站点上分隔的非常清楚。站点管理者使用系统来添加新闻故事,时间,体育得分等等,并且那些内容显示在公共站点上。Django解决了这个问题,创建一个统一的接口给站点管理员和内容编辑者。
管理界面并不是为站点访问者准备的,它是给站点管理员使用的。
5.1 创建一个管理用户
$ python manage.py createsuperuser
Username: admin
Email address: admin@example.com
最后一步式输入你的密码。你将会被要求输入密码2次,第二次是密码确认。
Password: **********
Password (again): *********
Superuser created successfully.
5.2 启动开发服务器
$ python manage.py runserver
5.3 进入管理站点
5.4 让poll应用在管理站点可修改
polls/admin.py
from django.contrib import admin
from .models import Question
admin.site.register(Question)
5.5 体验免费的管理功能
- 表单自动从Question模型生成。
- 不同的模型字段类型(DateTimeFiled,CharField)对应于适当的HTML输入小部件。每一个字段的类型都知道如何在Django管理站点显示自己。
- 每一个DateTimeField都有免费的JavaScript缩写。Dates有“Today”缩写和日历弹窗,times有一个“Now”的缩写和一个方便的弹窗,列出了日常输入的时间。
- save --保存修改并且返回这个对象的修改列表页面
- Save and continue editing -- 保存修改并重载这个对象的管理页面
- Save and add another -- 保存修改并且加载一个这个对象类型的新的,空白的形式。
- Delete -- 显示一个删除确认页面。