接着我们的上一篇文章继续往下进行.在这一篇文章当中我们会设置一个数据库,创建我们的第一个model.并且快速的介绍一下Django自动生成admin站点.
数据库设置
首先打开mysite/settings.py
文件, setting.py
是存储Django设置信息的地方.
简单介绍一下settings.py
文件里INSTALLED_APPS
的含义:
django.contrib.admin : #admin站点, 稍后我们会用到
django.contrib.auth : #authentication系统
django.contrib.contenttypes : #content types的框架
django.contrib.sessions : #session框架
django.contrib.messages :#messaging框架
django.contrib.staticfiles : #管理静态文件的框架
在这些应用程序中至少需要使用一个数据库, 所以在使用之前我们需要先创建数据库.只要运行下面的代码就可以了:
python manage.py migrate
migrate
指令会查看INSTALLED_APPS
中的设置,并根据mysite/settings.py
文件中的设置创建数据库并将数据库关联到APP.
创建models
接下来会定义我们的models.
在我们的poll APP 中会创建两个模型Question
和Choice
.
Question
有一个问题的描述字段和发布日期字段.Choice
有一个文本描述字段和和统计字段.每一个Choice
都关联着一个'Question'.
这是最简单的Pyhton类.按照下面的样子编辑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)
代码非常的简单明了,每一个model都是的django.db.models.Model
的子类.每一个model都有几个变量, 每一个变量都对应着model在数据库中的一个字段.
每一个field都是 Field
类的一个实例.CharField
是用来存储字符的,DateTimeField
是用来存储时间的.这些告诉了Django每一个字段存储的数据类型.
每一个Field
实例的名字, 就是字段的名字(例如上面的question_text
和pub_date
).你会在Python的代码中使用这些值, 数据库则会使用这些字段名作为每一列的名字.
某些Field
需要洗一些必须的参数, 比如 CharField
需要你指定max_length
.这些不仅是数据库需要的信息,而且会用来做验证, 待会就知道了.
一个Field
也可以有几个可选参数.在这个例子中我们会将votes
的默认值设置为0.
最后需要注意的是我们用ForeignKey
来定义两个模型之间的关联关系.这让Django
知道每一个Choice
都关联这一个单独的Question
.
Django
支持所有的关系类型: 一对多, 多对都, 一对一.
激活models
上面那一点点代码给了Django很多信息.根据上面的信息, Django能够:
- 为我们的APP创建一个数据库的表
- 创建可以用Python访问数据库的API来访问Question 和 Choice对象.
但是首先我们应该让我们的项目知道polls app已经被安装了.
为了将app包含进我们项目里, 我们需要在
INSTALLED_APPS
中配置一个引用,PollsConfig
类在'polls/apps.py'文件中,所以用点语法的话, 他的路径应该是polls.apps.PollsConfig
, 编辑mysite/settings.py
文件, 并且将配置文件的路径添加在INSTALLED_APPS
中:
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
现在Django知道他包含了polls APP,现在我们运行另外一个命令:
ython 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你的models做了一些改变并且你想保存这些改变.
Django会将你对Models的改变存储为一个文件, 文件的名字和路径polls/migrations/0001_initial.py
,你可以通过查看这个文件来查看你所做的改变.
migrate
命令可以让数据库自动应用这些改变,我们稍后就会用到.但是首先我们来看一下这些改变会用到哪些SQL语句.sqlmigrate
可以输出这些改变名字, 并且输出这些SQL语句.
python manage.py sqlmigrate polls 0001
你应该会看到类似下面的输出:
<pre>
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;
</pre>
如果你有兴趣的话你也可以运行python manage.py check
,这个指令会检查你项目中遇到的问题,并且不会将这些改变应用到数据库上, 不会对数据库造成任何影响.
现在, 再次运行 migrate
指令, 来创建那些模型在数据库中所对应的table.
python manage.py migrate
migrate
指令会应用之前没有应用的改变.
Migrations
指令非常有用,可以让你在开发项目的过程中随时改变models,而不用删除数据库也造成任何数据的丢失.后面我们会深入讨论这些内容,但是现在请记住下面这三步对models做出的改变:
修改
models
(在models.py
文件中)运行python manage.py makemigrations
来存储这些改变运行python manage.py migrate
将这些改变应用到数据库
之所以将将这些改变的存储和应用分成几个指令是为了在你项目的版本控制系统中记录这些操作.它不仅会让你的开发工作变得非常简单, 而且这对其他开发者非常有用.
使用这些API
接下来我们进入, Python与shell的交互环节,并练习使用Django 给我们提供的API.使用下面的命令调用Python shell:
python manage.py shell
我们可以通过输入简单的 python
指令代替上面的指令,因为 manage.py
文件里设置了DJANGO_SETTINGS_MODULE
这个环境变量.它给Django的mysite/settings.py
文件提供了Python的导入路径.
注意:接下来的操作是在虚拟环境下进行的, 因为时间的关系, 在完成上面的内容后, 我退出了服务器的操作.后来在家继续进行接下来的操作的时候没办法继续往下尽心.然后就想是不是没有进入虚拟环境的问题,然后就进到虚拟环境下在自己建的项目mystie目录下继续往下操作. 果然OK!
当我们进入了shell以后, 我们就可以浏览 database 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>]>
一定要注意每一行语句前面的空格数量, 因为Python对代码样式的要求非常严格, 如果空格数量过多会包语法错误.一定要注意.
<Question: Question object>
完全无法帮助我们了解Question
对象的详细信息.所以接下来, 我们来修复这个问题, 编辑Question model
(在 polls/models.py 文件里)然后在Question
和Choice
添加一个 str()
方法.当然有些对Python语法不是很熟悉的同学可能不知道如何退出shell环境, 只需要在终端里输入:
>>> exit()
就可以了.
编辑polls/models.py
文件:
vim polls/models.py
为我们的models添加str()
方法是非常重要的,它不仅在我们开发的时候提供参考, 而且在Django自动生成的admin在使用这些对象的时候也会用到.
这些只是普通的python方法, 让我们添加一个自定义的方法, 哪怕仅仅只是做一个示范.
在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)
注意开头添加的import datetime
和from django.utils import timezone
两行代码分别引用了Python标准的 datetime
模块和Django中django.utils.timezone
时间相关的工具类.
保存这些改动.
这里给对Vim编辑器不熟悉的同学一些提示, 通过vim filename打开文件后点击i键可以进入编辑模式, 如果要退出vim的编辑模式, 先点击`esc`键, 然后点击`:wq`可以保存并退出编辑模式.
保存上面的更改并通过键入python manage.py shell
重新进入python的交互模式.
>>> 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()
想要了解更多关于模型的信息可以参考 Accessing related objects.想要了解更多或者如何使用双下划线通过API查看字段信息,可以参考 Field lookups.想要了解更多的关于数据API的详细信息可以参考 Database API reference.
Django Admin的介绍
创建一个admin用户
首先我们需要创建一个可以登录admin站点的用户.运行下面的这个命令:
python manage.py createsuperuser
输入你想要的用户名并且按enter键
Username: admin
然后会提示你输入邮件地址
Email address: admin@example.com
最后一步是输入你的密码,会提示你输入两次, 第二次是确认第一次输入的密码.
Password: **********
Password (again): *********
Superuser created successfully.
开始开发服务器
Django的admin站点, 默认是激活的.接下来我们开始开发服务器并且访问它.
如果服务器并没有运行起来, 用下面的指令启动它:
python manage.py runserver
(如果按照之前我写的从0开始搭建nginx-uWSGI-Django-python服务器配置好了uWSGI的自启动服务, 那么是不需要执行上面的指令的站点默认试运行的')
在浏览器中输入http://139.xxx.xxx.129:8000/admin/ 访问admin站点.
你应该会看到admin的登录界面
进入admin站点
现在用你上一步创建的超级用户登录admin站点, 你应该会看到Django admin站点的首页.
你应该看到了可以编辑groups和users, 这些是有Django的与认证相关的django.contrib.auth
框架提供的.
让poll app在admin中可以编辑
但是我们Polls APP去哪里了呢?它并没有显示在admin站点的首页.
只要做一件事就可以了: 我们只用告诉 adminQuestion
对象是admin的一个接口就可以了.所以我们打开polls/admin.py
文件, 并按照下面编辑:
from django.contrib import admin
from .models import Question
admin.site.register(Question)
探索自由的管理功能
现在我们注册了Question
,现在Django知道了他应该在首页显示Question
.
注意: 这里我遇到了一个坑, 就是我按照上面的步骤在admin.py中导入了Question 以后, 刷新admin首页并没有出现Question 列表, 而是再我重新启动服务器以后再访问的时候才出现了Question 列表
点击Questions
, 现在你应该位于questions
的修改修改列表页,这里显示了数据库中所有的questions你可以选择并修改他们.这里有一个我们之前创建的“What’s up?”的question.
点击“What’s up?” question并且编辑它.
这里有几点需要注意:
- 这个表单是从Question model中自动生成的
- model中不同类型的属性字段((DateTimeField
, CharField
))有相应类型的输入框.Django的adimn站点知道如何正确的显示不同类型的输入框 - 每一个 DateTimeField
都会有相应的JavaScript的快捷按钮, 日期有一个Today
的快捷按钮并且有一个日历的弹框,时间有一个Now
的快捷按钮, 并且有一个快捷按钮让你可以选择时间.
在这个页面的底部有几个选项: - Save - 爆粗努修改并返回上一页
- Save and continue editing - 保存修改并且重新加载这一页
- Save and add another - 保存修改, 并且加载一个这种类型的对象的空表单.
- Delete - 显示一个确认删除的页面.
如果“Date published”的值与你在上一篇文章中创建的时候的时间不一致.
通过点击 “Today” 和 “Now”按钮改变“Date published”的值.然后点击页面下面的“Save and continue editing.”.然后点击右上角“History” .你就会看到通过Django的admin站点对这个对象所有的修改历史, 包括修改的时间和修改的人.
.
现在了你已经熟悉了models 的API和admin站点.在下移偏重我们会学习如何为我们的 polls app添加更多的views.