1.1 安装python包管理器:php
wget https://bootstrap.pypa.io/get-pip.py sudo python get-pip.py
1.2 安装python虚拟环境virtualenv virtualenvwrappercss
首先说明下为何要装这两个包:html
First, it’s important to understand that a virtual environment is a special tool used to keep the dependencies required by different projects in separate places by creating isolated, independent Python environments for each of them.java
In short, it solves the “Project X depends on version 1.x, but Project Y needs 4.x” dilemma. It also keeps your global site-packages neat, tidy, and free from clutter.node
If you would like a full explanation on why Python virtual environments are good practice, absolutely give this excellent blog post on RealPython a read.python
用虚拟开发环境能够为每一个工程提供独立的python开发环境、独立的包、独立的版本,每一个独立的环境会在~/.virtualenvs/下造成资源包~mysql
sudo pip install virtualenv virtualenvwrapper sudo rm -rf ~/.cache/pip
以后在~/.profile文件最后添加下面几行:linux
# virtualenv and virtualenvwrapper export WORKON_HOME=$HOME/.virtualenvs source /usr/local/bin/virtualenvwrapper.sh
以后若是想用python虚拟环境,在每次打开一个新的terminal就要执行一次source ~/.profilenginx
source ~/.profile
接下来咱们生成一个python虚拟环境来用于python-web的开发提供环境:(这里用的是python2.7)git
mkvirtualenv python_web -p python2
注:再次说明python虚拟环境是彻底独立的,也就是说在python_web的环境下安装的python包,步适用于全局;在全局安装的包,不适合python_web。
如何验证你如何将python_web环境生成好了呢?——新开一个terminal,执行下列命令:
source ~/.profile workon python_web
若是terminal前面的文字变成了(python_web)代表成功建立了名为cv的python虚拟环境;
从官网上得知2.7版本的python可以使用最高1.11版本的Django,所以在python_web环境中安装:
pip install Django==1.11
测试Django有没有安装成功,进入python命令交互模式:
import django django.VERSION
找到你的django-admin.py文件,并把它加入系统路径。若是用的是setup.py工具安装的Django,django-admin.py应该已被加入了系统路径中。个人django-admin.py的目录为:
/root/.virtualenvs/python_web/lib/python2.7/site-packages/django/bin
进入该目录下,运行以下命令,新建一个项目:
python django-admin.py startproject mysite
startproject命令建立一个目录,包含一个名为mysite的文件夹和一个名为manage.py的文件。其中mysite文件夹下包含有四个文件,分别为:
(python_web) ➜ mysite tree . ├── db.sqlite3 ├── manage.py └── mysite ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py
为了安装后更多的体验,让咱们运行一下django开发服务器看看咱们的准系统。django开发服务是可用在开发期间的,一个内建的,轻量的web服务。 咱们提供这个服务器是为了让你快速开发站点,也就是说在准备发布产品以前,无需进行产品级 Web 服务器(好比 Apache)的配置工做。 开发服务器监测你的代码并自动加载它,这样你会很容易修改代码而不用重启动服务。若是你还没启动服务器的话,请切换到你的项目目录里 (cd mysite),运行下面的命令:
python manage.py runserver
你会看到以下内容:
Django version 1.11, using settings 'mysite.settings' Starting development server at http://127.0.0.1:3000/ Quit the server with CTRL-BREAK
这将会在端口3000启动一个本地服务器, 而且只能从你的这台电脑链接和访问。 既然服务器已经运行起来了,如今用网页浏览器访问 http://127.0.0.1:8000/ 。 你应该能够看到一个使人赏心悦目的淡蓝色Django欢迎页面。 代表它开始工做了。
可是个人服务器搭在阿里云上,而且绑定了phage.cc的域名,所以能够经过这样的方式使之能访问:
python manage.py runserver 0.0.0.0:3000
注:0.0.0.0”这个IP地址,告诉服务器去侦放任意的网络接口。
注:采用phage.cc:3000去访问会报错误 alid HTTP_HOST header: 'www.phage.cc:3000'. You may need to add u'www.phage.cc' to ALLOWED_HOSTS.
能够经过添加容许来实现经过:
settings.py : ALLOWED_HOSTS = [u'www.phage.cc']
4.1 静态视图hello world
在文件夹mysite中新建一个views.py的文件:
from django.http import HttpResponse def hello(request): return HttpResponse("Hello world")
在这段代码中:咱们定义一个叫作hello 的视图函数,这个函数只有简单的一行代码: 它仅仅返回一个HttpResponse对象,这个对象包含了文本“Hello world”。
注:每一个视图函数至少要有一个参数,一般被叫做request。 这是一个触发这个视图、包含当前Web请求信息的对象,是类django.http.HttpRequest的一个实例。在这个示例中,咱们虽然不用request作任何事情,然而它仍必须是这个视图的第一个参数。
注:视图函数的名称并不重要;并不必定非得以某种特定的方式命名才能让 Django 识别它。 在这里咱们把它命名为:hello,是由于这个名称清晰的显示了视图的用意。
4.2 URLconf将视图和URL绑定(相似nodejs中的路由)
URLconf 就像是 Django 所支撑网站的目录。 它的本质是 URL 模式以及要为该 URL 模式调用的视图函数之间的映射表。 你就是以这种方式告诉 Django,对于这个 URL 调用这段代码,对于那个 URL 调用那段代码。
这个映射表在urls.py中,咱们想要实现访问/hello/调用hello视图,返回hello world须要作下面样子修改:
from django.conf.urls import url urlpatterns = [ url(r'^hello/$', hello), ]
注: 这里的^hello/$是正则表达式,匹配全部/hello/形式的请求。
以后咱们运行该服务器,在浏览器中能够访问hello视图: http://www.phage.cc:3000/hello/
4.3 动态内容视图请求当前时间
在views.py中添加一个新视图current_datatime:
from django.http import HttpResponse import datetime def hello(request): return HttpResponse("Hello world") def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
相似hello视图,这里用了python的datetime工具,获取时间并合成一个html字符串,做为视图返回。
同理,咱们也须要在urls.py中作url映射:
from django.conf.urls import url from mysite.views import hello, current_datetime urlpatterns = [ url(r'^hello/$', hello), url(r'^time/$', current_datetime), ]
这样咱们经过访问 http://www.phage.cc:3000/time/ 能够获取time视图返回。
4.4 动态URL视图
在咱们的current_datetime
视图范例中,尽管内容是动态的,可是URL ( /time/ )是静态的。 在 大多数动态web应用程序,URL一般都包含有相关的参数。 举个例子,一家在线书店会为每一本书提供一个URL,如:/books/243/、/books/81196/。
让咱们建立第三个视图来显示当前时间和加上时间误差量的时间,设计是这样的: /time/plus/1/ 显示当前时间+1个小时的页面 /time/plus/2/ 显示当前时间+2个小时的页面 /time/plus/3/ 显示当前时间+3个小时的页面,以此类推。
注: 在java或php中有可能见到这样的实现:/time/plus?hours=3,但这样被认为不漂亮
以前咱们已经看到url是以正则表达式的形式出现,所以想要实现/time/plus/xxx/也就比较容易了:
from django.conf.urls import url from mysite.views import hello, current_datetime, hours_ahead urlpatterns = [ url(r'^hello/$', hello), url(r'^time/$', current_datetime), url(r'^time/plus/(\d{1,2})/$', hours_ahead), ]
那么咱们如是实现hours_ahead来接收请求中的xxx数字呢?
from django.http import Http404, HttpResponse import datetime ... def hours_ahead(request, offset): try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt) return HttpResponse(html)
hours_ahead 和咱们之前写的 current_datetime 很象,关键的区别在于: 它多了一个额外参数,时间差。
注: offset 是从匹配的URL里提取出来的。 例如:若是请求URL是/time/plus/3/,那么offset将会是3;若是请求URL是/time/plus/21/,那么offset将会是21。请注意:捕获值永远都是字符串(string)类型,而不会是整数(integer)类型,即便这个字符串全由数字构成(如:“21”)。
注: 在这里咱们命名变量为 offset ,你也能够任意命名它,只要符合Python 的语法。 变量名是可有可无的,重要的是它的位置,它是这个函数的第二个 参数 (在 request 的后面)。 你还可使用关键字来定义它,而不是用 位置。
5.1 最简单的模板DEMO
模板的好处是将python和html分开,下面是一个最简单的例子:
def template_test(request): now = datetime.datetime.now() t = Template("<html><body>It is now {{ current_date }}.</body></html>"); html = t.render(Context({'current_date': now})) return HttpResponse(html)
上面的例子在html中嵌入一个 current_date 变量,经过context给变量赋值,经过render来渲染。除了双大括号表示的变量,还有循环、条件等各类玩法: https://docs.djangoproject.com/en/2.1/ref/templates/builtins/ 。
5.2 将html和python完全分离
可是上面咱们并无真正将html和python分离,更进一步的作法是将html单独放置:
1) 在mysite下新建一个文件夹:templates,并在其中新建一个template_test1.html:
<html><body>It is now {{ current_date }}.</body></html>
2) 而咱们的template_test就能改形成:
def template_test1(request): now = datetime.datetime.now() t = get_template('template_test1.html'); html = t.render({'current_date': now}) return HttpResponse(html)
3) 最后咱们得经过下面方法让get_template的输入参数不用写完整路径:
TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),], 'APP_DIRS': True, 'OPTIONS': {
注:咱们还能够用render_to_response来简化template_test操做:
def template_test2(request): now = datetime.datetime.now() return render_to_response('template_test1.html', {'current_date': now})
5.3 模板继承
一个多页面的网站,其每一个页面可能会有相同的头部、尾部的结构,主页面的内容存在更新变更。若是咱们为每一个页面单首创建一个独立的html将会产生大量冗余,此外若是咱们想要对全部页面的头部作一个修改,也将比较麻烦。此时咱们能够采用模板的思想来完美解决这个问题:
1)新建一个母版html(base.html)
(python_web) ➜ templates git:(master) cat base.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>{% block title %}{% endblock %}</title> </head> <body> <h1>My helpful timestamp site</h1> {% block content %}{% endblock %} {% block footer %} <hr> <p>Thanks for visiting my site.</p> {% endblock %} </body> </html>
2) 建立一个继承base.html的template_test2_use_base_1.html:
(python_web) ➜ templates git:(master) cat template_test2_use_base_1.html {% extends "base.html" %} {% block title %}The current time{% endblock %} {% block content %} <p>It is now {{ current_date }}.</p> {% endblock %}
3) 再建立一个继承base.html的template_test2_use_base_2.html:
(python_web) ➜ templates git:(master) cat template_test2_use_base_2.html {% extends "base.html" %} {% block title %}Future time{% endblock %} {% block content %} <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> {% endblock %}
可见base.html中的{% block title %}{% endblock %} 、{% block content %}{% endblock %} 、{% block footer %}{% endblock %} 均可以被继承者们从新实现!
注:固然,若是继承者没有实现,则不会显示。
6.1 安装MYSQL数据库
咱们先在linux上安装数据库:
sudo apt-get install mysql-server sudo apt-get install libmysqlclient-dev
安装过程当中会提示设置密码什么的,注意设置了不要忘了,安装完成以后可使用以下命令来检查是否安装成功:
sudo netstat -tap | grep mysql
经过上述命令检查以后,若是看到有mysql 的socket处于 listen 状态则表示安装成功。
登录mysql数据库能够经过以下命令:
mysql -u root -p
-u 表示选择登录的用户名, -p 表示登录的用户密码,上面命令输入以后会提示输入密码,此时输入密码就能够登陆到mysql。
下面是一些命令行中操做的DEMO,可作从此参考:
mysqladmin -u root -p create blog mysql mysql -u root -p show databases; use blog; CREATE TABLE IF NOT EXISTS `blog_table`( `blogId` BIGINT UNSIGNED, `url` VARCHAR(100) NOT NULL, `title` VARCHAR(1000) NOT NULL, `support` INT UNSIGNED, `pageView` INT UNSIGNED, PRIMARY KEY ( `blogId` ) )ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `tag_table`( `tagId` INT UNSIGNED AUTO_INCREMENT, `tagName` VARCHAR(100) NOT NULL, PRIMARY KEY ( `tagId` ) )ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `blog_tag_relation_table`( `relationId` INT UNSIGNED AUTO_INCREMENT, `blogId` BIGINT UNSIGNED, `tagId` INT UNSIGNED, PRIMARY KEY ( `relationId` ) )ENGINE=InnoDB DEFAULT CHARSET=utf8; show tables; desc blog_table; desc tag_table; desc blog_tag_relation_table; //change blogId int 2 bigint alter table blog_table change blogId blogId BIGINT UNSIGNED; //show data select * from blog_table; //delete data delete from blog_table where blogId=201801021423; INSERT INTO blog_table(blogId,url,title,support,pageView) VALUES(201801021423,'http://106.14.226.191:3000/blog/201607281658.html','[商业_法务] 一、公司一款新消费类电子产品如何快速全面的专利保护',0,0); //too short alter table blog_table change title title VARCHAR(1000) NOT NULL; INSERT INTO tag_table(tagId,tagName) VALUES(0,'硬件_模拟电路'); select * from blog_table; select * from tag_table; select * from blog_tag_relation_table; delete from blog_table where blogId>0; delete from tag_table where tagId>=0; delete from blog_tag_relation_table where relationId >= 0; select a.title , a.url, b.tagName from blog_table a, tag_table b, blog_tag_relation_table c WHERE a.blogId = c.blogId AND a.blogId = 201602021408 AND b.tagId = c.tagId; select a.title , a.url, b.tagName from blog_table a, tag_table b, blog_tag_relation_table c WHERE a.blogId = c.blogId AND b.tagId = c.tagId ORDER BY b.tagId;
为了python操做mysql须要执行下面命令:
pip install MySQL-python
6.2 配置及测试数据库
在settings.py中下面几项是对数据库的配置:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'pyserver', 'USER': 'root', 'PASSWORD': '123456', } }
一旦在输入了那些设置并保存以后应当测试一下你的配置。 咱们能够在mysite
项目目录下执行python manage.py shell
来进行测试(没有错误表示成功):
from django.db import connection cursor = connection.cursor()
6.3 建立books app
在mysite
项目文件下输入下面的命令来建立books
app:
python manage.py startapp books
这个命令并无输出什么,它只在 mysite 的目录里建立了一个 books 目录。 让咱们来看看这个目录的内容:
(python_web) ➜ books tree . ├── admin.py ├── apps.py ├── __init__.py ├── migrations │ └── __init__.py ├── models.py ├── tests.py └── views.py
这个目录包含了这个app的模型和视图。
6.4 编写模型
编辑models.py
:
from django.db import models class Publisher(models.Model): name = models.CharField(max_length=30) address = models.CharField(max_length=50) city = models.CharField(max_length=60) state_province = models.CharField(max_length=30) country = models.CharField(max_length=50) website = models.URLField() class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField() class Book(models.Model): title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher) publication_date = models.DateField()
Publisher 模块至关于SQL语句:
CREATE TABLE "books_publisher" ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(30) NOT NULL, "address" varchar(50) NOT NULL, "city" varchar(60) NOT NULL, "state_province" varchar(30) NOT NULL, "country" varchar(50) NOT NULL, "website" varchar(200) NOT NULL );
6.5 由模型自动生成建立表SQL
再次编辑settings.py,将下面列出选项加#
注释掉,并添加‘mysite.books’
到INSTALLED_APPS
的末尾:
INSTALLED_APPS = [ #'django.contrib.admin', #'django.contrib.auth', #'django.contrib.contenttypes', #'django.contrib.sessions', #'django.contrib.messages', #'django.contrib.staticfiles', 'books', ] MIDDLEWARE = [ #'django.middleware.security.SecurityMiddleware', #'django.contrib.sessions.middleware.SessionMiddleware', #'django.middleware.common.CommonMiddleware', #'django.middleware.csrf.CsrfViewMiddleware', #'django.contrib.auth.middleware.AuthenticationMiddleware', #'django.contrib.messages.middleware.MessageMiddleware', #'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
你可能会执行python manage.py validate ,而后你会特别伤心的看到人家提示Unknown command: 'validate'Type 'manage.py help' for usage.,对吧?因此你要用以下这个命令:
python manage.py check
而后你还想生成sql语句,你就运行了python manage.py sqlall books,错误提示是Unknown command: 'sqlall'Type 'manage.py help' for usage.一样若是你想提交sql语句到数据库而运行syncdb,错误提示是Unknown command: 'syncdb'
Type 'manage.py help' for usage. 为何没有这些命令,由于它们被淘汰了。因此你只需运行以下的命令:
python manage.py makemigrations books #用来检测数据库变动和生成数据库迁移文件 python manage.py migrate #用来迁移数据库(直接到数据库) python manage.py sqlmigrate books 0001 # 用来把数据库迁移文件转换成数据库语言
6.6 基本数据访问
一旦你建立了模型,Django自动为这些模型提供了高级的Python API。 运行 python manage.py shell 并输入下面的内容试试看:
>>> from books.models import Publisher >>> p1 = Publisher(name='Apress', address='2855 Telegraph Avenue', ... city='Berkeley', state_province='CA', country='U.S.A.', ... website='http://www.apress.com/') >>> p1.save() >>> p2 = Publisher(name="O'Reilly", address='10 Fawcett St.', ... city='Cambridge', state_province='MA', country='U.S.A.', ... website='http://www.oreilly.com/') >>> p2.save() >>> publisher_list = Publisher.objects.all() >>> publisher_list [<Publisher: Publisher object>, <Publisher: Publisher object>]
其余经常使用基本操做以下:
p1 = Publisher.objects.create(....)
p1.name = 'Apress Publishing'
Publisher.objects.filter(country="U.S.A.", state_province="CA")
Publisher.objects.get(name="Apress")
Publisher.objects.order_by("state_province", "address")
Publisher.objects.filter(country="U.S.A.").order_by("-name")
Publisher.objects.order_by('name')[0]
or [0:2]
Publisher.objects.filter(id=52).update(name='Apress Publishing')
p.save()
p.delete()
注意:上述操做除了删除,每一个操做以后都别忘了保存!
7.1 基本操做
编辑settings.py:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'books', ] MIDDLEWARE = [ #'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', #'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', #'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
以后运行python manage.py migrate
这一步将生成管理界面使用的额外数据库表。 当你把'django.contrib.auth'加进INSTALLED_APPS后,第一次运行syncdb命令时, 系统会请你建立一个超级用户。 若是你不这么做,你须要运行python manage.py createsuperuser来另外建立一个admin的用户账号,不然你将不能登入admin(我这里设置user:admin password:xxxxxx)
将admin访问配置在URLconf(记住,在urls.py中)
from django.conf.urls import url from django.contrib import admin from django.conf.urls import include #from mysite.views import hello from mysite.views import hello, current_datetime, hours_ahead, template_test, template_test1, template_test2, template_test3, template_test4 admin.autodiscover() urlpatterns = [ url(r'^admin/', include(admin.site.urls)), ... ]
此时运行python manage.py runserver 0.0.0.0:8080
,而后在浏览器中访问: http://www.phage.cc:8080/admin/
注:NameError: name 'include' is not defined错误须要from django.conf.urls import include;
注:django nginx admin css丢失须要在settings.py中INSTALLED_APPS中加django.contrib.staticfiles;
7.2 管理工具简介
管理界面的设计是针对非技术人员的,因此它应该是自我解释的。 尽管如此,这里简单介绍一下它的基本特性:
1)登陆页面(用户名密码就是刚刚生成的admin,xxxxxxxxx)
你要使用你原来设置的超级用户的用户名和密码。 若是没法登陆,请运行python manage.py createsuperuser
,确保你已经建立了一个超级用户。
2)一旦登陆了,你将看到管理页面:
这个页面列出了管理工具中可编辑的全部数据类型。 如今,因为咱们尚未建立任何模块,因此这个列表只有寥寥数条类目: 它仅有两个默认的管理-编辑模块:用户组(Groups)和用户(Users)。
3)点进去USER能够添加、修改、删除等操做,很是方便:
7.3 将其余Models加入到Admin管理中
有一个关键步骤咱们还没作。 让咱们将本身的模块加入管理工具中,这样咱们就可以经过这个漂亮的界面添加、修改和删除数据库中的对象了。 咱们将继续第五章中的book
例子。在其中,咱们定义了三个模块: Publisher 、 Author 和 Book 。
编辑mysite/books/admin.py
,而后输入:
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.contrib import admin from books.models import Publisher, Author, Book admin.site.register(Publisher) admin.site.register(Author) admin.site.register(Book) # Register your models here.
重启服务器,如今再去admin主页,就会看到Publisher 、 Author 和 Book模块,这样就能编辑这些模块了!
7.4 工做原理
当服务启动时,Django从url.py
引导URLconf,而后执行admin.autodiscover()
语句。 这个函数遍历INSTALLED_APPS配置,而且寻找相关的 admin.py文件。 若是在指定的app目录下找到admin.py,它就执行其中的代码。
在books
应用程序目录下的admin.py
文件中,每次调用admin.site.register()
都将那个模块注册到管理工具中。 管理工具只为那些明确注册了的模块显示一个编辑/修改的界面。
7.5 设置字段可选
email = models.EmailField(**blank=True** )
email = models.EmailField(blank=True, **verbose_name='e-mail'** )
自定义列表:
class Author(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True, verbose_name='e-mail') **def __unicode__(self):** **return u'%s %s' % (self.first_name, self.last_name)**
注:更多展现自定义能够参考[12]. The Django Book - 第六章 Django站点管理
8.1 URL相关信息
HttpRequest对象包含当前请求URL的一些信息:
属性/方法 | 说明 | 举例 |
---|---|---|
request.path | 除域名之外的请求路径,以正斜杠开头 | "/hello/" |
request.get_host() | 主机名(好比,一般所说的域名) | "127.0.0.1:8000" or "www.example.com" |
request.get_full_path() | 请求路径,可能包含查询字符串 | "/hello/?print=true" |
request.is_secure() | 若是经过HTTPS访问,则此方法返回True, 不然返回False | True 或者 False |
8.2 一个简单的SEARCH表单
views.search()
def search(request): error = False if 'q' in request.GET: q = request.GET['q'] if not q: error = True else: books = Book.objects.filter(title__icontains=q) return render_to_response('search_results.html',{'books': books, 'query': q}) return render_to_response('search_form.html',{'error': error})
search_form.html
<html> <head> <title>Search</title> </head> <body> {% if error %} <p style="color: red;">Please submit a search term.</p> {% endif %} <form action="" method="get"> <input type="text" name="q"> <input type="submit" value="Search"> </form> </body> </html>
search_results.html
<p>You searched for: <strong>{{ query }}</strong></p> {% if books %} <p>Found {{ books|length }} book{{ books|pluralize }}.</p> <ul> {% for book in books %} <li>{{ book.title }}</li> {% endfor %} </ul> {% else %} <p>No books matched your search criteria.</p> {% endif %}
更高级的用法咱们在后面的DEMO中介绍!
项目地址: https://github.com/zmrenwu/django-blog-tutorial
项目master: https://github.com/zmrenwu
9.1 将项目部署在咱们买AliYun上
下载项目到本地:
cd ~/App/ git clone https://github.com/zmrenwu/django-blog-tutorial.git
建立并激活虚拟环境(必定要注意是python3):
virtualenv blogproject_env -p python3 source blogproject_env/bin/activate
安装依赖并数据迁移(sqlite的):
pip install -r requirements.txt python manage.py migrate
建立后台管理员帐户并启动服务器(我这里其余端口被占用,所以用8080):
python manage.py createsuperuser python manage.py runserver 0.0.0.0:8080
因为咱们不是在本地运行,所以还得在settings.py中添加: ALLOWED_HOSTS = [u'www.phage.cc']
。此时,即可以访问 http://www.phage.cc:8080/admin/ 对品类、文章、标签、用户等进行管理了:
访问: http://www.phage.cc:8080/ 即可看到咱们在后台添加的 python-django 文章:
9.2 代码解析
首先看看全部支持的url入口配置文件:/blog/urls.py
from django.conf.urls import url from . import views app_name = 'blog' urlpatterns = [ url(r'^$', views.IndexView.as_view(), name='index'), url(r'^post/(?P<pk>[0-9]+)/$', views.PostDetailView.as_view(), name='detail'), url(r'^archives/(?P<year>[0-9]{4})/(?P<month>[0-9]{1,2})/$', views.ArchivesView.as_view(), name='archives'), url(r'^category/(?P<pk>[0-9]+)/$', views.CategoryView.as_view(), name='category'), url(r'^tag/(?P<pk>[0-9]+)/$', views.TagView.as_view(), name='tag'), # url(r'^search/$', views.search, name='search'), ]
其主页调用views.IndexView.as_view()实现的,可是为何有第三个参数name='idnex'呢?咱们看/blog/view.py的IndexView就明白了,这里类IndexView继承Django的Generic display views来实现的,看一下Generic display views中的ListViewd的用法就明白了。其余的各类入口则依此类推:
class IndexView(ListView): ... class PostDetailView(DetailView): ... class ArchivesView(ListView): ... class CategoryView(ListView): ... class TagView(ListView): ...
咱们倒着分析各个入口的实现(倒着由浅入深),看第一个TagView的实现:
class TagView(ListView): model = Post template_name = 'blog/index.html' context_object_name = 'post_list' def get_queryset(self): tag = get_object_or_404(Tag, pk=self.kwargs.get('pk')) return super(TagView, self).get_queryset().filter(tags=tag)
TagView继承ListView:重设置model和tempale_name为会致使 —— 通用视图将查询数据库以获取指定model(Post)的全部记录,而后呈现位于/templates/blog/index.html的模板;而context_object_name重定义的意义在于 —— your own name for the list as a template variable;重写get_queryset方法 —— 从数据库中过滤出全部tag,将get_queryset方法添加到基于类的自定义视图中,并指定order_by()。
这里的get_object_or_404的功能在于若是找不到记录,就引起Http404异常的快捷方式,见下面的例子:
def book_detail_view(request, primary_key): try: book = Book.objects.get(pk=primary_key) except Book.DoesNotExist: raise Http404('Book does not exist') return render(request, 'catalog/book_detail.html', context={'book': book}) 利用get_object_or_404来实现: from django.shortcuts import get_object_or_404 def book_detail_view(request, primary_key): book = get_object_or_404(Book, pk=primary_key) return render(request, 'catalog/book_detail.html', context={'book': book})
接下来的CategoryView、ArchivesView和TagView同样,咱们重点看PostDetailView和IndexView:
class IndexView(ListView): model = Post template_name = 'blog/index.html' context_object_name = 'post_list' paginate_by = 10 def get_context_data(self, **kwargs): ... def pagination_data(self, paginator, page, is_paginated): ...
上面已经介绍:
等效于:
blog/views.py def index(request): post_list = Post.objects.all() return render(request, 'blog/index.html', context={'post_list': post_list})
而PostDetailView则继承了DetailView,该模板用于从数据库中取出一条记录并渲染,其中model、template、context_object_name和ListView相似;这里覆写了get方法是为了阅读量加1的运算,同时注意到用super继承了原来的response并返回;覆写 get_object 方法的目的是由于须要对 post 的 body 值进行渲染;覆写 get_context_data 的目的是由于除了将 post 传递给模板外(DetailView 已经帮咱们完成),还要把评论表单、post 下的评论列表传递给模板。
更详细的操做你们能够从GIT上获取: https://github.com/zmrenwu/django-blog-tutorial
: 完~
: 你们以为不错,能够点推荐给更多人~
[1]. 0二、PI3安装openCV开发环境作图像识别(详细版)
[2]. 利用Django进行Web开发系列(一)
[3]. 博客园python web关键词搜索
[4]. The Django Book
[5]. The Django Book - 第三章 视图和URL配置
[6]. Built-in template tags and filters
[7]. The Django Book - 第五章 模型
[8]. Ubuntu下安装MySQL及简单操做
[9]. MySQL-python 1.2.5
[10]. 在Django中使用数据库遇到的问题
[11]. Django manage.py Unknown command: 'syncdb'
[12]. The Django Book - 第六章 Django站点管理
[13]. Chapter 6: The Django Admin Site
[14]. The Django Book PDF
[15]. The Django Book - 第八章:高级视图和URL配置
[16]. Django Tutorial Part 6: Generic list and detail views
[17]. 基于类的通用视图:ListView 和 DetailView
@beautifulzzzz 智能硬件、物联网,热爱技术,关注产品 博客:http://blog.beautifulzzzz.com 园友交流群:414948975