书籍出处:https://www.packtpub.com/web-development/django-example
原做者:Antonio Melécss
2016年12月10日发布(没有进行校对,有不少错别字以及模糊不清的语句,请你们见谅)html
2017年2月7日精校完成(断断续续的终于完成了第一章精校,感受比直接翻译还要累,继续加油)python
2017年2月10日再次进行精校(感谢大牛@kukoo的精校!)nginx
(译者注:本人目前在杭州某家互联网公司工做,岗位是测试研发,很是喜欢python,目前已经使用Django为公司内部搭建了几个自动化平台,由于没人教没人带,基本靠野路子自学,走过好多弯路,磕磕碰碰一路过来,前段时间偶尔看到《Django By Example》这本书,瞬间泪流满面,当初怎么没有找到这么好的Django教程。在看书的过程当中不知道怎么搞的忽然产生了翻译全书的想法,正好网上找了下也没有汉化的版本,因此准备踏上这条不归路。鉴于本人英文水平极低(四级都没过),单纯靠着有道词典和本身对上下文的理解以及对书中每行代码都保证敲一遍并运行的状况下,请各位在读到语句不通的时候或看不懂的地方请告诉我,我会及时进行改正。翻译全书,主要也是为了培养本身的英文阅读水平(口语就算了),谁叫好多最新最有用的计算机文档都是用英文写的,另外也能够培养本身的耐心,还能够分享给其余人,就这样。)git
在这本书中,你将学习如何建立完整的Django项目,能够在生产环境中使用。假如你尚未安装Django,在本章的第一部分你将学习如何安装。本章会覆盖如何使用Django去建立一个简单的blog应用。本章的目的是使你对该框架的工做有个基本概念,了解不一样的组件之间是如何产生交互,而且教你一些技能经过使用一些基本功能方便地建立Djang项目。你会被引导建立一个完整的项目可是不会对全部的细节都进行详细说明。不一样的框架组件将在本书接下来的章节中进行介绍。
本章会覆盖如下几点:github
若是你已经安装好了Django,你能够直接略过这部分跳到建立你的第一个项目。Django是一个Python包所以能够安装在任何的Python的环境中。若是你尚未安装Django,这里有一个快速的指南帮助你安装Django用来本地开发。web
Django须要在Python2.7或者3版本上才能更好的工做。在本书的例子中,咱们将使用Python 3。若是你使用Linux或者Max OSX,你可能已经有安装好的Python。若是你不肯定你的计算机中是否安装了Python,你能够在终端中输入 python 来肯定。若是你看到如下相似的提示,说明你的计算机中已经安装好了Python:正则表达式
Python 3.5.0 (v3.5.0:374f501f4567, Sep 12 2015, 11:00:19) [GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>>
若是你计算机中安装的Python版本低于3,或者没有安装,下载并安装Python 3.5.0 从http://www.python.org/download/ (译者注:最新已是3.6.0了,Django2.0将再也不支持pytyon2.7,因此你们都从3版本以上开始学习吧)。sql
因为你使用的是Python3,因此你不必再安装一个数据库。这个Python版本自带SQLite数据库。SQLLite是一个轻量级的数据库,你能够在Django中进行使用用来开发。若是你准备在生产环境中部署你的应用,你应该使用一个更高级的数据库,好比PostgreSQL,MySQL或Oracle。你能获取到更多的信息关于数据库和Django的集成经过访问 https://docs.djangoproject.com/en/1.8/topics/install/#database-installation 。shell
强烈建议你使用virtualenv来建立独立的Python环境,这样你可使用不一样的包版本对应不一样的项目,这比直接在真实系统中安装Python包更加的实用。另外一个高级之处在于当你使用virtualenv你不须要任何管理员权限来安装Python包。在终端中运行如下命令来安装virtualenv:
pip install virtualenv
(译者注:若是你本地有多个python版本,注意Python3的pip命令多是pip3)
当你安装好virtualenv以后,经过如下命令来建立一个独立的环境:
virtualenv my_env
以上命令会建立一个包含你的Python环境的my_env/目录。当你的virtualenv被激活的时候全部已经安装的Python库都会带入 my_env/lib/python3.5/site-packages 目录中。
若是你的系统自带Python2.X而后你又安装了Python3.X,你必须告诉virtualenv使用后者Python3.X。经过如下命令你能够定位Python3的安装路径而后使用该安装路径来建立virtualenv:
zenx\$ *which python3* /Library/Frameworks/Python.framework/Versions/3.5/bin/python3 zenx\$ *virtualenv my_env -p /Library/Frameworks/Python.framework/Versions/3.5/bin/python3*
经过如下命令来激活你的virtualenv:
source my_env/bin/activate
shell提示将会附上激活的virtualenv名,被包含在括号中,以下所示:
(my_evn)laptop:~ zenx$
你可使用deactivate命令随时停用你的virtualenv。
你能够获取更多的信息关于virtualenv经过访问 https://virtualenv.pypa.io/en/latest/ 。
在virtualenv之上,你可使用virtualenvwrapper工具。这个工具提供一些封装用来方便的建立和管理你的虚拟环境。你能够在 http://virtualenvwrapper.readthedocs.org/en/latest/ 下载该工具。
(译者注:请注意如下的操做都在激活的虚拟环境中使用)
pip是安装Django的第一选择。Python3.5自带预安装的pip,你能够找到pip的安装指令经过访问 https://pip.pypa.io/en/stable/installing/ 。运行如下命令经过pip安装Django:
pip install Django==1.8.6
Django将会被安装在你的虚拟环境的Python的site-packages/目录下。
如今检查Django是否成功安装。在终端中运行python而且导入Django来检查它的版本:
>>> import django >>> django.VERSION DjangoVERSION(1, 8, 5, 'final', 0)
若是你得到了以上输出,Django已经成功安装在你的机器中。
Django也可使用其余方式来安装。你能够找到更多的信息经过访问 https://docs.djangoproject.com/en/1.8/topics/install/ 。
咱们的第一个项目将会是一个完整的blog站点。Django提供了一个命令容许你方便的建立一个初始化的项目文件结构。在终端中运行如下命令:
django-admin startproject mysite
该命令将会建立一个名为mysite的项目。
让咱们来看下生成的项目结构:
mysite/ manage.py mysite/ __init__.py settings.py urls.py wsgi.py
让咱们来了解一下这些文件:
默认生成的settings.py文件包含一个使用一个SQLite数据库的基础配置以及一个Django应用列表,这些应用会默认添加到你的项目中。咱们须要为这些初始应用在数据库中建立表。
打开终端执行如下命令:
cd mysite python manage.py migrate
你将会看到如下的相似输出:
Rendering model states... DONE Applying contenttypes.ooo1_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying contenttypes.0002_remove_content_type_name... OK Applying auth.0002_alter_permission_name_max_length... OK Applying auth.0003_alter_user_email_max_length...OK Applying auth.0004_alter_user_username_opts... OK Applying auth.0005_alter_user_last_login_null... OK Applying auth.0006_require_contenttypes_0002... OK Applying sessions.0001_initial... OK
这些初始应用表将会在数据库中建立。过一下子你就会学习到一些关于migrate的管理命令。
Django自带一个轻量级的web服务器来快速运行你的代码,不须要花费额外的时间来配置一个生产服务器。当你运行Django的开发服务器,它会一直检查你的代码变化。当代码有改变,它会自动重启,将你从手动重启中解放出来。可是,它可能没法注意到一些操做,例如在项目中添加了一个新文件,因此你在某些场景下仍是须要手动重启。
打开终端,在你的项目主目录下运行如下代码来开启开发服务器:
python manage.py runserver
你会看到如下相似的输出:
Performing system checks... System check identified no issues (0 silenced). November 5, 2015 - 19:10:54 Django version 1.8.6, using settings 'mysite.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
如今,在浏览器中打开 http://127.0.0.1:8000/ ,你会看到一个告诉你项目成功运行的页面,以下图所示:
你能够指定Django在定制的host和端口上运行开发服务,或者告诉它你想要运行你的项目经过读取一个不一样的配置文件。例如:你能够运行如下 manage.py命令:
python manage.py runserver 127.0.0.1:8001 \ --settings=mysite.settings
这个命令早晚会对处理须要不一样设置的多套环境启到做用。记住,这个服务器只是单纯用来开发,不适合在生产环境中使用。为了在生产环境中部署Django,你须要使用真实的web服务让它运行成一个WSGI应用例如Apache,Gunicorn或者uWSGI(译者注:强烈推荐 nginx+uwsgi+Django)。你可以获取到更多关于如何在不一样的web服务中部署Django的信息,访问 https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/ 。
本书外额外的须要下载的章节第十三章,Going Live包含为你的Django项目设置一个生产环境。
让咱们打开settings.py文件来看看你的项目的配置。在该文件中有许多设置是Django内置的,但这些只是全部Django可用配置的一部分。你能够经过访问 https://docs.djangoproject.com/en/1.8/ref/settings/ 看到全部的设置和它们默认的值。
如下列出的设置很是值得一看:
不要担忧你目前还看不懂这些设置的含义。你将会在以后的章节中熟悉这些设置。
贯穿全书,你会反复的读到项目和应用的地位。在Django中,一个项目被认为是一个安装了一些设置的Django;一个应用是一个包含模型(models),视图(views),模板(templates)以及URLs的组合。应用之间的交互经过Django框架提供的一些特定功能,而且应用可能被各类各样的项目重复使用。你能够认为项目就是你的网站,这个网站包含多个应用,例如blog,wiki或者论坛,这些应用均可以被其余的项目使用。(译者注:我去,我居然漏翻了这一节- -|||,罪过罪过,阿米头发)
如今让咱们建立你的第一个Django应用。咱们将要建立一个勉强凑合的blog应用。在你的项目主目录下,运行如下命令:
python manage.py startapp blog
这个命令会建立blog应用的基本目录结构,以下所示:
blog/ __init__.py admin.py migrations/ __init__.py models.py tests.py views.py
这些文件的含义:
咱们将要开始为你的blog设计初始的数据模型(models)。一个模型(model)就是一个Python类,该类继承了django.db.models.model,在其中的每个属性表示一个数据库字段。Django将会为models.py中的每个定义的模型(model)建立一张表。当你建立好一个模型(model),Django会提供一个很是实用的API来方便的查询数据库。
首先,咱们定义一个POST模型(model)。在blog应用下的models.py文件中添加如下内容:
from django.db import models from django.utils import timezone from django.contrib.auth.models import User class Post(models.Model): STATUS_CHOICES = ( ('draft', 'Draft'), ('published', 'Published'), ) title = models.CharField(max_length=250) slug = models.SlugField(max_length=250, unique_for_date='publish') author = models.ForeignKey(User, related_name='blog_posts') body = models.TextField() publish = models.DateTimeField(default=timezone.now) created = models.DateTimeField(auto_now_add=True) updated = models.DateTimeField(auto_now=True) status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft') class Meta: ordering = ('-publish',) def __str__(self): return self.title
这就是咱们给blog帖子使用的基础模型(model)。让咱们来看下刚才在这个模型(model)中定义的各个字段含义:
(1,2)
,那么该字段只能选择1或者2,没有其余值能够选择)就像你所看到的的,Django内置了许多不一样的字段类型给你使用,这样你就可以定义你本身的模型(models)。经过访问 https://docs.djangoproject.com/en/1.8/ref/models/fields/ 你能够找到全部的字段类型。
在模型(model)中的类Meta包含元数据。咱们告诉Django查询数据库的时候默认返回的是根据publish字段进行降序排列过的结果。咱们使用负号来指定进行降序排列。
str()方法是当前对象默认的可读表现。Django将会在不少地方用到它例如管理站点中。
若是你以前使用过Python2.X,请注意在Python3中全部的strings都使用unicode,所以咱们只使用str()方法。unicode()方法已经废弃。(译者注:Python3大法好,Python2别再学了,直接学Python3吧)
在咱们处理日期以前,咱们须要下载pytz模块。这个模块给Python提供时区的定义而且SQLite也须要它来对日期进行操做。在终端中输入如下命令来安装pytz:
pip install pytz
Django内置对时区日期处理的支持。你能够在你的项目中的settings.py文件中经过USE_TZ来设置激活或停用对时区的支持。当你经过startproject命令来建立一个新项目的时候这个设置默认为True。
为了让Django能保持跟踪你的应用而且根据你的应用中的模型(models)来建立数据库表,咱们必须激活你的应用。所以,编辑settings.py文件,在INSTALLED_APPS设置中添加blog。看上去以下所示:
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'blog', )
(译者注:该设置中应用的排列顺序也会对项目的某些方面产生影响,具体状况后几章会有介绍,这里提醒下)
如今Django已经知道在项目中的咱们的应用是激活状态而且将会对其中的模型(models)进行自审。
让咱们为咱们的模型(model)在数据库中建立一张数据表格。Django自带一个数据库迁移(migration)系统来跟踪你对模型(models)的修改,而后会同步到数据库。migrate命令会应用到全部在INSTALLED_APPS中的应用,它会根据当前的模型(models)和数据库迁移(migrations)来同步数据库。
首先,咱们须要为咱们刚才建立的新模型(model)建立一个数据库迁移(migration)。在你的项目主目录下,执行如下命令:
python manage.py makemigrations blog
你会看到如下输出:
Migrations for 'blog': 0001_initial.py; - Create model Post
Django在blog应用下的migrations目录中建立了一个0001——initial.py文件。你能够打开这个文件来看下一个数据库迁移的内容。
让咱们来看下Django根据咱们的模型(model)将会为在数据库中建立的表而执行的SQL代码。sqlmigrate命令带上数据库迁移(migration)的名字将会返回它们的SQL,但不会当即去执行。运行如下命令来看下输出:
python manage.py sqlmigrate blog 0001
输出相似以下:
BEGIN; CREATE TABLE "blog_post" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(250) NOT NULL, "slug" varchar(250) NOT NULL, "body" text NOT NULL, "publish" datetime NOT NULL, "created" datetime NOT NULL, "updated" datetime NOT NULL, "status" varchar(10) NOT NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id")); CREATE INDEX "blog_post_2dbcba41" ON "blog_post" ("slug"); CREATE INDEX "blog_post_4f331e2f" ON "blog_post" ("author_id"); COMMIT;
Django会根据你正在使用的数据库进行以上精准的输出。以上SQL语句是为SQLite数据库准备的。如你所见,Django生成的表名前缀为应用名以后跟上模型(model)的小写(blog_post),可是你也能够经过在模型(models)的Meta类中使用db_table属性来指定表名。Django会自动为每一个模型(model)建立一个主键,可是你也能够经过在模型(model)中的某个字段上设置primarry_key=True来指定主键。
让咱们根据新模型(model)来同步数据库。运行如下的命令来应用已存在的数据迁移(migrations):
python manage.py migrate
你应该会看到如下行跟在输出的末尾:
Applying blog.0001_initial... OK
咱们刚刚为INSTALLED_APPS中全部的应用进行了数据库迁移(migrations),包括咱们的blog应用。在进行了数据库迁移(migrations)以后,数据库会反映咱们模型的当前状态。
若是为了添加,删除,或是改变了存在的模型(models)中字段,或者你添加了新的模型(models)而编辑了models.py文件,你都须要经过使用makemigrations命令作一次新的数据库迁移(migration)。数据库迁移(migration)容许Django来保持对模型(model)改变的跟踪。以后你必须经过migrate命令来保持数据库与咱们的模型(models)同步。
如今咱们已经定义好了Post模型(model),咱们将要建立一个简单的管理站点来管理blog帖子。Django内置了一个管理接口,该接口对编辑内容很是的有用。这个Django管理站点会根据你的模型(model)元数据进行动态构建而且提供一个可读的接口来编辑内容。你能够对这个站点进行自由的定制,配置你的模型(models)在其中如何进行显示。
请记住,django.contrib.admin已经被包含在咱们项目的INSTALLED_APPS设置中,咱们不须要再额外添加。
首先,咱们须要建立一名用户来管理这个管理站点。运行如下的命令:
python manage.py createsuperuser
你会看下如下输出。输入你想要的用户名,邮箱和密码:
Username (leave blank to use 'admin'): admin Email address: admin@admin.com Password: ******** Password (again): ******** Superuser created successfully.
如今,经过python manage.py runserver
命令来启动开发服务器,以后在浏览器中打开 http://127.0.0.1:8000/admin/ 。你会看到管理站点的登陆页面,以下所示:
使用你在上一步中建立的超级用户信息进行登陆。你将会看到管理站点的首页,以下所示:
Group和User 模型(models) 位于django.contrib.auth,是Django权限管理框架的一部分。若是你点击Users,你将会看到你以前建立的用户信息。你的blog应用的Post模型(model)和User(model)关联在了一块儿。记住,它们是经过author字段进行关联的。
让咱们在管理站点中添加你的blog模型(models)。编辑blog应用下的admin.py文件,以下所示:
from django.contrib import admin from .models import Post admin.site.register(Post)
如今,在浏览器中刷新管理站点。你会看到你的Post模型(model)已经在页面中展现,以下所示:
这很简单,对吧?当你在Django的管理页面注册了一个模型(model),Django会经过对你的模型(models)进行内省而后提供给你一个很是友好有用的接口,这个接口容许你很是方便的排列,编辑,建立,以及删除对象。
点击Posts右侧的Add连接来添加一篇新帖子。你将会看到Django根据你的模型(model)动态生成了一个表单,以下所示:
Django给不一样类型的字段使用了不一样的表单控件。即便是复杂的字段例如DateTimeField也被展现成一个简单的接口相似一个JavaScript日期选择器。
填写好表单而后点击Save按钮。你会被重定向到帖子列页面而且获得一条帖子成功建立的提示,以下所示:
如今咱们来看下如何定制管理站点。编辑blog应用下的admin.py文件,使之以下所示:
from django.contrib import admin from .models import Post class PostAdmin(admin.ModelAdmin): list_display = ('title', 'slug', 'author', 'publish', 'status') admin.site.register(Post, PostAdmin)
咱们使用继承了ModelAdmin的定制类来告诉Django管理站点中须要注册咱们本身的模型(model)。在这个类中,咱们能够包含一些关于如何在管理站点中展现模型(model)的信息以及如何与该模型(model)进行交互。list_display属性容许你在设置一些你想要在管理对象列表页面显示的模型(model)字段。
让咱们经过更多的选项来定制管理模型(model),如使用如下代码:
class PostAdmin(admin.ModelAdmin): list_display = ('title', 'slug', 'author', 'publish', 'status') list_filter = ('status', 'created', 'publish', 'author') search_fields = ('title', 'body') prepopulated_fields = {'slug': ('title',)} raw_id_fields = ('author',) date_hierarchy = 'publish' ordering = ['status', 'publish']
回到浏览器刷新管理站点页面,如今应该以下所示:
你能够看到帖子列页面中展现的字段都是你在list-dispaly属性中指定的。这个列页面如今包含了一个右侧边栏容许你根据list_filter属性中指定的字段来过滤返回结果。一个搜索框也应用在页面中。这是由于咱们还经过使用search_fields属性定义了一个搜索字段列。在搜索框的下方,有个能够经过时间层快速导航的栏,该栏经过定义date_hierarchy属性出现。你还能看到这些帖子默认的经过Status和Publish列进行排序。这是由于你经过使用ordering属性指定了默认排序。
如今,点击Add post连接。你还会在这儿看到一些改变。当你输入完成新帖子的标题,slug字段将会自动填充。咱们经过使用prepoupulated_fields属性告诉Django经过输入的标题来填充slug字段。同时,如今的author字段展现显示为了一个搜索控件,这样当你的用户量达到成千上万级别的时候比再使用下拉框进行选择更加的人性化,以下图所示:
经过短短的几行代码,咱们就在管理站点中自定义了咱们的模型(model)的展现形式。还有更多的方式能够用来定制Django的管理站点。在这本书的后面,咱们还会进一步讲述。
如今,你已经有了一个完整功能的管理站点来管理你的blog内容,是时候学习如何从数据库中检索信息而且与这些信息进行交互了。Django自带了一个强大的数据库抽象API可让你轻松的建立,检索,更新以及删除对象。Django的Object-relational Mapper(ORM)能够兼容MySQL,PostgreSQL,SQLite以及Oracle。请记住你能够在你项目下的setting.py中编辑DATABASES设置来指定数据库。Django能够同时与多个数据库进行工做,这样你能够编写数据库路由经过任何你喜欢的方式来操做数据。
一旦你建立好了你的数据模型(models),Django会提供你一个API来与它们进行交互。你能够找到数据模型(model)的官方参考文档经过访问 https://docs.djangoproject.com/en/1.8/ref/models/ 。
打开终端运行如下命令来打开Python shell:
python manage.py shell
而后依次输入如下内容:
>>> from django.contrib.auth.models import User >>> from blog.models import Post >>> user = User.objects.get(username='admin') >>> post = Post.objects.create(title='One more post', slug='one-more-post', body='Post body.', author=user) >>> post.save()
让咱们来研究下这些代码作了什么。首先,咱们取回了一个username是admin的用户对象:
user = User.objects.get(username='admin')
get()
方法容许你从数据库取回一个单独的对象。注意这个方法只但愿在查询中有惟一的一个匹配。若是在数据库中没有返回结果,这个方法会抛出一个DoesNotExist异常,若是数据库返回多个匹配结果,将会抛出一个MultipleObjectsReturned异常。当查询执行的时候,全部的异常都是模型(model)类的属性。
接着,咱们来建立一个拥有定制标题标题,slug和内容的Post实例,而后咱们设置以前取回的user胃这篇帖子的做者以下所示:
post = Post(title='Another post', slug='another-post', body='Postbody.', author=user)
这个对象只是存在内存中不会执行到数据库中
最后,咱们经过使用save()方法来保存该对象到数据库中:
post.save()
这步操做将会执行一段SQL的插入语句。咱们已经知道如何在内存中建立一个对象而且以后才在数据库中进行插入,可是咱们也能够经过使用create()方法直接在数据库中建立对象,以下所示:
Post.objects.create(title='One more post', slug='one-more-post',body='Post body.', author=user)
如今,改变这篇帖子的标题而且再次保存对象:
>>> post.title = 'New title' >>> post.save()
这一次,save()方法执行了一条更新语句。
你对对象的改变一直存在内存中直到你执行到save()方法。
Django的Object-relational mapping(ORM)是基于查询集(QuerySet)。查询集(QuerySet)是从你的数据库中根据一些过滤条件范围取回的结果对象进行的采集。你已经知道如何经过get()方法从数据库中取回单独的对象。如你所见:咱们经过Post.objects.get()
来使用这个方法。每个Django模型(model)至少有一个管理器(manager),默认管理器(manager)叫作objects。你经过使用你的模型(models)的管理器(manager)就能得到一个查询集(QuerySet)对象。获取一张表中的全部对象,你只须要在默认的objects管理器(manager)上使用all()方法便可,以下所示:
>>> all_posts = Post.objects.all()
这就是咱们如何建立一个用于返回数据库中全部对象的查询集(QuerySet)。注意这个查询集(QuerySet)并尚未执行。Django的查询集(QuerySets)是惰性(lazy)的,它们只会被动的去执行。这样的行为能够保证查询集(QuerySet)很是有效率。若是咱们没有把查询集(QuerySet)设置给一个变量,而是直接在Python shell中编写,由于咱们迫使它输出结果,这样查询集(QuerySet)的SQL语句将立马执行:
>>> Post.objects.all()
为了过滤查询集(QuerySet),你能够在管理器(manager)上使用filter()
方法。例如,咱们能够返回全部在2015年发布的帖子,以下所示:
Post.objects.filter(publish__year=2015)
你也可使用多个字段来进行过滤。例如,咱们能够返回2015年发布的全部做者用户名为admin的帖子,以下所示:
Post.objects.filter(publish__year=2015, author__username='admin')
上面的写法和下面的写法产生的结果是一致的:
Post.objects.filter(publish__year=2015).filter(author__username='admin')
咱们构建了字段的查找方法,经过使用两个下划线
(publish__year)
来查询,除此之外咱们也能够经过使用两个下划线(author__username)
访问关联的模型(model)字段。
你能够在管理器(manager)上使用exclude()方法来排除某些返回结果。例如:咱们能够返回全部2015年发布的帖子可是这些帖子的题目开头不能是Why:
Post.objects.filter(publish__year=2015).exclude(title__startswith='Why')
经过在管理器(manager)上使用order_by()方法来对不一样的字段进行排序,你能够对结果进行排序。例如:你能够取回全部对象并经过它们的标题进行排序:
Post.objects.order_by('title')
默认是升序。你能够经过负号来指定使用降序,以下所示:
Post.objects.order_by('-title')
若是你想删除一个对象,你能够对对象实例进行下面的操做:
post = Post.objects.get(id=1) post.delete()
请注意,删除对象也将删除任何的依赖关系
只要你喜欢,你能够链接许多的过滤给查询集(QuerySet)并且不会立马在数据库中执行直到这个查询集(QuerySet)被执行。查询集(QuerySet)只有在如下状况中才会执行:
* 在你第一次迭代它们的时候
* 当你对它们的实例进行切片:例如Post.objects.all()[:3]
* 当你对它们进行了打包或缓存
* 当你对它们调用了repr()
或len()
方法
* 当你明确的对它们调用了list()
方法
* 当你在一个声明中测试它,例如bool(), or, and, or if
咱们以前提到过, objects是每个模型(models)的默认管理器(manager),它会返回数据库中全部的对象。可是咱们也能够为咱们的模型(models)定义一些定制的管理器(manager)。咱们准备建立一个定制的管理器(manager)来返回全部状态为已发布的帖子。
有两种方式能够为你的模型(models)添加管理器(managers):你能够添加额外的管理器(manager)方法或者继承管理器(manager)的查询集(QuerySets)进行修改。第一种方法相似Post.objects.my_manager()
,第二种方法相似Post.my_manager.all()
。咱们的管理器(manager)将会容许咱们返回全部帖子经过使用Post.published
。
编辑你的blog应用下的models.py文件添加以下代码来建立一个管理器(manager):
class PublishedManager(models.Manager): def get_queryset(self): return super(PublishedManager, self).get_queryset().filter(status='published') class Post(models.Model): # ... objects = models.Manager() # The default manager. published = PublishedManager() # Our custom manager.
get_queryset()
是返回执行过的查询集(QuerySet)的方法。咱们经过使用它来包含咱们定制的过滤到完整的查询集(QuerySet)中。咱们定义咱们定制的管理器(manager)而后添加它到Post 模型(model)中。咱们如今能够来执行它。例如,咱们能够返回全部标题开头为Who的而且是已经发布的帖子:
Post.published.filter(title__startswith='Who')
如今你已经学会了一些如何使用ORM的基本知识,你已经准备好为blog应用建立视图(views)了。一个Django视图(view)就是一个Python方法,它能够接收一个web请求而后返回一个web响应。在视图(views)中经过全部的逻辑处理返回指望的响应。
首先咱们会建立咱们的应用视图(views),而后咱们将会为每一个视图(view)定义一个URL模式,咱们将会建立HTML模板(templates)来渲染这些视图(views)生成的数据。每个视图(view)都会渲染模板(template)传递变量给它而后会返回一个通过渲染输出的HTTP响应。
让咱们开始建立一个视图(view)来展现帖子列。编辑你的blog应用下中views.py文件,以下所示:
from django.shortcuts import render, get_object_or_404 from .models import Post def post_list(request): posts = Post.published.all() return render(request, 'blog/post/list.html', {'posts': posts})
你刚建立了你的第一个Django视图(view)。post_list视图(view)将request对象做为惟一的参数。记住全部的的视图(views)都有须要这个参数。在这个视图(view)中,咱们获取到了全部状态为已发布的帖子经过使用咱们以前建立的published管理器(manager)。
最后,咱们使用Django提供的快捷方法render()经过给予的模板(template)来渲染帖子列。这个函数将request对象做为参数,模板(template)路径以及变量来渲染的给予的模板(template)。它返回一个渲染文本(通常是HTML代码)HttpResponse对象。render()方法考虑到了请求内容,这样任何模板(template)内容处理器设置的变量均可以带入给予的模板(template)中。你会在第三章,扩展你的blog应用学习到如何使用它们。
让咱们建立第二个视图(view)来展现一篇单独的帖子。添加以下代码到views.py文件中:
def post_detail(request, year, month, day, post): post = get_object_or_404(Post, slug=post, status='published', publish__year=year, publish__month=month, publish__day=day) return render(request, 'blog/post/detail.html', {'post': post})
这是一个帖子详情视图(view)。这个视图(view)使用year,month,day以及post做为参数经过给予slug和日期来获取到一篇已经发布的帖子。请注意,当咱们建立Post模型(model)的时候,咱们给slgu字段添加了unique_for_date参数。这样咱们能够确保在给予的日期中只有一个帖子会带有一个slug,所以,咱们能经过日期和slug取回单独的帖子。在这个详情视图(view)中,咱们经过使用get_object_or_404()快捷方法来检索指望的Post。这个函数能取回匹配给予的参数的对象,或者当没有匹配的对象时返回一个HTTP 404(Not found)异常。最后,咱们使用render()快捷方法来使用一个模板(template)去渲染取回的帖子。
一个URL模式是由一个Python正则表达,一个视图(view),一个全项目范围内的命名组成。Django在运行中会遍历全部URL模式直到第一个匹配的请求URL才中止。以后,Django导入匹配的URL模式中的视图(view)并执行它,使用关键字或指定参数来执行一个HttpRequest类的实例。
若是你以前没有接触过正则表达式,你须要去稍微了解下,经过访问 https://docs.python.org/3/howto/regex.html 。
在blog应用目录下建立一个urls.py文件,输入如下代码:
from django.conf.urls import url from . import views urlpatterns = [ # post views url(r'^$', views.post_list, name='post_list'), url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/'\ r'(?P<post>[-\w]+)/$', views.post_detail, name='post_detail'), ]
第一条URL模式没有带入任何参数,它映射到post_list视图(view)。第二条URL模式带上了如下4个参数映射到post_detail视图(view)中。让咱们看下这个URL模式中的正则表达式:
为每个应用建立单独的urls.py文件是最好的方法,能够保证你的应用能给别的项目再度使用。
如今你须要将你blog中的URL模式包含到项目的主URL模式中。编辑你的项目中的mysite文件夹中的urls.py文件,以下所示:
from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^blog/', include('blog.urls', namespace='blog', app_name='blog')), ]
经过这样的方式,你告诉Django在blog/路径下包含了blog应用中的urls.py定义的URL模式。你能够给它们一个命名空间叫作blog,这样你能够方便的引用这个URLs组。
你可使用以前定义的post_detail URL给Post对象构建标准URL。Django的惯例是给模型(model)添加get_absolute_url()方法用来返回一个对象的标准URL。在这个方法中,咱们使用reverse()方法容许你经过它们的名字和可选的参数来构建URLS。编辑你的models.py文件添加以下代码:
from django.core.urlresolvers import reverse Class Post(models.Model): # ... def get_absolute_url(self): return reverse('blog:post_detail', args=[self.publish.year, self.publish.strftime('%m'), self.publish.strftime('%d'), self.slug])
请注意,咱们经过使用strftime()方法来保证个位数的月份和日期须要带上0来构建URL(译者注:也就是01,02,03)。咱们将会在咱们的模板(templates)中使用get_absolute_url()方法。
咱们为咱们的应用建立了视图(views)和URL模式。如今该添加模板(templates)来展现界面友好的帖子了。
在你的blog应用目录下建立如下目录结构和文件:
templates/ blog/ base.html post/ list.html detail.html
以上就是咱们的模板(templates)的文件目录结构。base.html文件将会包含站点主要的HTML结构以及分割内容区域和一个导航栏。list.html和detail.html文件会继承base.html文件来渲染各自的blog帖子列和详情视图(view)。
Django有一个强大的模板(templates)语言容许你指定数据的如何进行展现。它基于模板标签(templates tags), 例如 {% tag %}
, {{ variable }}
以及模板过滤器(templates filters),能够对变量进行过滤,例如 {{ variable|filter }}
。你能够经过访问 https://docs.djangoproject.com/en/1.8/ ref/templates/builtins/ 找到全部的内置模板标签(templates tags)和过滤器(filters)。
让咱们来编辑base.html文件并添加以下代码:
{% load staticfiles %} <!DOCTYPE html> <html> <head> <title>{% block title %}{% endblock %}</title> <link href="{% static "css/blog.css" %}" rel="stylesheet"> </head> <body> <div id="content"> {% block content %} {% endblock %} </div> <div id="sidebar"> <h2>My blog</h2> <p>This is my blog.</p> </div> </body> </html>
{% load staticfiles %}
告诉Django去加载django.contrib.staticfiles应用提供的staticfiles 模板标签(temaplate tags)。经过加载它,你能够在这个模板(template)中使用{% static %}
模板过滤器(template filter)。经过使用这个模板过滤器(template filter),你能够包含一些静态文件好比说blog.css文件,你能够在本书的范例代码例子中找到该文件,在blog应用的static/目录中(译者注:给你们个地址去拷贝 https://github.com/levelksk/django-by-example-book )拷贝这个目录到你的项目下的相同路径来使用这些静态文件。
你能够看到有两个{% block %}
标签(tags)。这些是用来告诉Django咱们想在这个区域中定义一个区块(block)。继承这个模板(template)的其余模板(templates)可使用自定义的内容来填充区块(block)。咱们定义了一个区块(block)叫作title,另外一个区块(block)叫作content。
让咱们编辑post/list.html文件使它以下所示:
{% extends "blog/base.html" %} {% block title %}My Blog{% endblock %} {% block content %} <h1>My Blog</h1> {% for post in posts %} <h2> <a href="{{ post.get_absolute_url }}"> {{ post.title }} </a> </h2> <p class="date"> Published {{ post.publish }} by {{ post.author }} </p> {{ post.body|truncatewords:30|linebreaks }} {% endfor %} {% endblock %}
经过{% extends %}
模板标签(template tag),咱们告诉Django须要继承blog/base.html 模板(template)。而后咱们在title和content区块(blocks)中填充内容。咱们经过循环迭代帖子来展现它们的标题,日期,做者和内容,在标题中还集成了帖子的标准URL连接。在帖子的内容中,咱们应用了两个模板过滤器(template filters): truncatewords用来缩短内容限制在必定的字数内,linebreaks用来转换内容中的换行符为HTML的换行符。只要你喜欢你能够链接许多模板标签(tempalte filters),每个都会应用到上个输出生成的结果上。
打开终端执行命令python manage.py runserver
来启动开发服务器。在浏览器中打开 http://127.0.0.1:8000/blog/ 你会看到运行结果。注意,你须要添加一些发布状态的帖子才能在这儿看到它们。你会看到以下图所示:
这以后,让咱们来编辑post/detail.html文件使它以下所示:
{% extends "blog/base.html" %} {% block title %}{{ post.title }}{% endblock %} {% block content %} <h1>{{ post.title }}</h1> <p class="date"> Published {{ post.publish }} by {{ post.author }} </p> {{ post.body|linebreaks }} {% endblock %}
如今,你能够在浏览器中点击其中一篇帖子的标题来看帖子的详细视图(view)。你会看到相似如下页面:
当你开始给你的blog添加内容,你很快会意识到你须要将帖子分页显示。Django有一个内置的Paginator类容许你方便的管理分页。
编辑blog应用下的views.py文件导入Django的页码类修改post_list以下所示:
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger def post_list(request): object_list = Post.published.all() paginator = Paginator(object_list, 3) # 3 posts in each page page = request.GET.get('page') try: posts = paginator.page(page) except PageNotAnInteger: # If page is not an integer deliver the first page posts = paginator.page(1) except EmptyPage: # If page is out of range deliver last page of results posts = paginator.page(paginator.num_pages) return render(request, 'blog/post/list.html', {'page': page, 'posts': posts})
Paginator是如何工做的:
如今,咱们必须建立一个模板(template)来展现分页处理,它能够被任意的模板(template)包含来使用分页。在blog应用的templates文件夹下建立一个新文件命名为pagination.html。在该文件中添加以下HTML代码:
<div class="pagination"> <span class="step-links"> {% if page.has_previous %} <a href="?page={{ page.previous_page_number }}">Previous</a> {% endif %} <span class="current"> Page {{ page.number }} of {{ page.paginator.num_pages }}. </span> {% if page.has_next %} <a href="?page={{ page.next_page_number }}">Next</a> {% endif %} </span> </div>
为了渲染上一页与下一页的连接而且展现当前页面和全部页面的结果,这个分页模板(template)指望一个Page对象。让咱们回到blog/post/list.html模板(tempalte)中将pagination.html模板(template)包含在{% content %}
区块(block)中,以下所示:
{% block content %} ... {% include "pagination.html" with page=posts %} {% endblock %}
咱们传递给模板(template)的Page对象叫作posts,咱们将分页模板(tempalte)包含在帖子列模板(template)中指定参数来对它进行正确的渲染。这种方法你能够反复使用,用你的分页模板(template)对不一样的模型(models)视图(views)进行分页处理。
如今,在你的浏览器中打开 http://127.0.0.1:8000/blog/。 你会看到帖子列的底部已经有分页处理:
由于一个视图(view)的调用就是获得一个web请求而且返回一个web响应,你能够将你的视图(views)定义成类方法。Django为此定义了基础的视图(view)类。它们都从View类继承而来,View类能够操控HTTP方法调度以及其余的功能。这是一个可替代的方法来建立你的视图(views)。
咱们准备经过使用Django提供的通用ListView使咱们的post_list视图(view)转变为一个基于类的视图。这个基础视图(view)容许你对任意的对象进行排列。
编辑你的blog应用下的views.py文件,以下所示:
from django.views.generic import ListView class PostListView(ListView): queryset = Post.published.all() context_object_name = 'posts' paginate_by = 3 template_name = 'blog/post/list.html'
这个基于类的的视图(view)相似与以前的post_list视图(view)。在这儿,咱们告诉ListView作了如下操做:
model = Post
而后Django将会构建Post.objects.all() 查询集(QuerySet)给咱们。blog/post_list.html
。如今,打开你的blog应用下的urls.py文件,注释到以前的post_listURL模式,在以后添加一个新的URL模式来使用PostlistView类,以下所示:
urlpatterns = [ # post views # url(r'^$', views.post_list, name='post_list'), url(r'^$', views.PostListView.as_view(),name='post_list'), url(r'^(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/'\ r'(?P<post>[-\w]+)/$', views.post_detail, name='post_detail'), ]
为了保持分页处理能工做,咱们必须将正确的页面对象传递给模板(tempalte)。Django的ListView经过叫作page_obj的变量来传递被选择的页面,因此你必须编辑你的post_list_html模板(template)去包含使用了正确的变量的分页处理,以下所示:
{% include "pagination.html" with page=page_obj %}
在你的浏览器中打开 http://127.0.0.1:8000/blog/ 而后检查每同样功能是否都和以前的post_list视图(view)同样工做。这是一个简单的,经过使用Django提供的通用类的基于类视图(view)的例子。你将在第十章,建立一个在线学习平台以及相关的章节中学到更多的基于类的视图(views)。
在本章中,你经过建立一个基础的blog应用学习了Django web框架的基础。你为你的项目设计了数据模型(models)而且进行了数据库迁移。你为你的blog建立了视图(views),模板(templates)以及URLs,还包括对象分页。
在下一章中,你会学习到如何加强你的blog应用,例如评论系统,标签(tag)功能,而且容许你的用户经过邮件来分享帖子。
终于将第一章勉强翻译完成了,不少翻译的句子我本身都读不懂 - -|||
你们看到有错误有歧义的地方请帮忙指出,以后还会随时进行修改保证基本能读懂。
按照第一章的翻译速度,全书都翻译下来估计要2,3个月,这是很是很是乐观的估计,天天只有中午休息和下班后大概有两三小时的翻译时间。
2016年12月10日发布(没有进行校对,有不少错别字以及模糊不清的语句,请你们见谅)
2017年2月7日精校完成(断断续续的终于完成了第一章精校,感受比直接翻译还要累,继续加油)
2017年2月10日再次进行精校(感谢大牛@kukoo的精校!)