第2章 Django 速成:构建一个Blog:
2.1 创建项目:
[root@node01 app]# pip install django
Downloading/unpacking django
Downloading Django-1.11.5-py2.py3-none-any.whl (6.9MB): 6.9MB downloaded
Downloading/unpacking pytz (from django)
Downloading pytz-2017.2-py2.py3-none-any.whl (484kB): 484kB downloaded
Installing collected packages: django, pytz
Successfully installed django pytz
Cleaning up...
[root@node01 app]# django-admin.py startproject mysite
[root@node01 app]# ls
mysite
[root@node01 app]# cd mysite/
[root@node01 mysite]# ls
manage.py mysite
[root@node01 mysite]# cd mysite/
[root@node01 mysite]# ls
__init__.py settings.py urls.py wsgi.py
除了__init__.py ,startproject命令还创建了以下三个文件:
1.manage.py 文件是一个同这个Django项目一起工作的工具,你可以从它在目录列表中的权限里看到它是可以执行的。
[root@node01 mysite]# ls -ltr
total 8
-rwxr-xr-x 1 root root 804 Sep 8 00:54 manage.py
drwxr-xr-x 2 root root 4096 Sep 8 00:54 mysite
2.settings.py 文件包含了项目的默认设置,
3.urls.py 文件在Django里叫URLconf,它是一个将URL模式映射到你应用程序上的配置文件。
2.2 运行开发服务器;
启动dev的命令如下:
node2:/app/mysite#./manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
August 23, 2017 - 16:59:47
Django version 1.11, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
CommandError: "192.168.137.3" is not a valid port number or address:port pair.
node2:/app/mysite#python manage.py runserver 192.168.137.3:8000
Performing system checks...
System check identified no issues (0 silenced).
August 23, 2017 - 17:04:21
Django version 1.11, using settings 'mysite.settings'
Starting development server at http://192.168.137.3:8000/
Quit the server with CONTROL-C.
2.3 创建Blog应用:
有了项目以后,就可以在它下面创建应用(按Django的说法是"app")了。
我们再次使用mange.py来创建这个blog app
node2:/app/mysite#./manage.py startapp blog
node2:/app/mysite#
这样就完成项目的创建了,现在我们在项目的目录下有了一个blog目录。
node2:/app/mysite/blog#ls -ltr
total 24
-rw-r--r-- 1 root root 148 Aug 24 13:15 apps.py
-rw-r--r-- 1 root root 128 Aug 24 13:15 views.py
-rw-r--r-- 1 root root 122 Aug 24 13:15 models.py
-rw-r--r-- 1 root root 125 Aug 24 13:15 tests.py
-rw-r--r-- 1 root root 0 Aug 24 13:15 __init__.py
-rw-r--r-- 1 root root 128 Aug 24 13:15 admin.py
drwxr-xr-x 2 root root 4096 Aug 24 13:15 migrations
node2:/app/mysite/blog#
和项目一样,app也是一个包,现在models.py和views.py 里还没有真正的代码,它们只是先占住位子而已。
要告诉Django这个app是项目里的一部分,你需要去编辑settings.py文件(也称之为"配置文件").
打开配置文件并在文件尾部找到INSTALLED_APPS元组。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Django 用INSTALLED_APPS来决定系统里不同部分的配置,包括自动化的admin应用以及测试框架。
2.4 设计你的Model:
现在我们来到了这个基于Django的blog应用的核心部分:models.py文件,这是我们定义blog数据结构的地方。
根据DRY原则,Django会尽量利用你提供给应用程序的model信息。
我们先来创建一个基本的model,看看Django用这个信息为我么做了点什么:
node2:/app/mysite/blog#cat models.py
# -*- coding: utf-8 -*-
from django.db import models
# Create your models here.
class BlogPost (models.Model):
title = models.CharField(max_length=150)
body = models. TextField()
timestamp = models .DateTimeField()
这是一个完整的model,代表了一个有3个变量的"BlogPost"对象。(严格来说应该有4个,Django会默认在每个model自动
加上一个自增的,唯一的id变量)。
这个新建的BlogPost类是django.db.models.Module的一个子类。
这是Django为数据model准备和标准基类,它是Django强大的对象关系映射(ORM)系统的核心。
使用数据库服务器:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'pydb',
'USER': 'root',
'PASSWORD': '1234567',
'HOST': '192.168.137.3',
'PORT': '3306',
}
}
现在你可以告诉Django用你提供的连接信息去连接数据库并且设置应用程序所需的表:
python manage.py makemigrations
python manage.py migrate
class BlogPost (models.Model):
title = models.CharField(max_length=150)
body = models. TextField()
timestamp = models .DateTimeField()
mysql> desc blog_blogpost
-> ;
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(150) | NO | | NULL | |
| body | longtext | NO | | NULL | |
| timestamp | datetime(6) | NO | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)
当你执行syncdb命令时,Django会查找INSTALLED_APPS里的每一个models.py文件,
并找到的每一个model都创建一张数据库表。
node2:/app/mysite#python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... 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 auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying blog.0001_initial... OK
Applying sessions.0001_initial... OK
设置admin:
manage.py createsuperuser
node2:/app/mysite#manage.py createsuperuser
-bash: manage.py: command not found
node2:/app/mysite#./manage.py createsuperuser
Username (leave blank to use 'root'): admin
Email address: admin@163.com
Password:
Password (again):
The password is too similar to the email address.
This password is too short. It must contain at least 8 characters.
This password is too common.
Password:
Password (again):
Superuser created successfully.
自动化的后台应用程序admin称的上是Django "皇冠上的明珠".
设置完app以后,我们需要为它指定一个URL这样才能访问它,你应该已经注意到了在自动生成的urls.py中的这样两行代码:
1.8以上的版本:
from django.conf.urls import url
from django.contrib import admin
from blog import views as blog_view
urlpatterns =(
url(r'^admin/', admin.site.urls),
url(r'^index/$',blog_view.index),
)
最后,你的应用
根据官方文档修改了blog / views.py里的内容,可以正常显示了
from __future__ import unicode_literals
# from django.shortcuts import render, render_to_response
from .models import *
# Create your views here.
from django.http import HttpResponse
from django.template import loader
def index(req):
# get all blogpost objects
blog_list = BlogPost.objects.all()
template = loader.get_template('index.html')
context = {
'blog_list': blog_list
}
return HttpResponse(template.render(context, req))
打开:
node2:/app/mysite/blog#cat models.py
# -*- coding: utf-8 -*-
from django.db import models
# Create your models here.
class BlogPost (models.Model):
title = models.CharField(max_length=150)
body = models. TextField()
timestamp = models .DateTimeField()
node2:/app/mysite#cat blog/views.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
# from django.shortcuts import render, render_to_response
from .models import *
# Create your views here.
from django.http import HttpResponse
from django.template import loader
def index(req):
# get all blogpost objects
blog_list = BlogPost.objects.all()
template = loader.get_template('index.html')
context = {
'blog_list': blog_list
}
return HttpResponse(template.render(context, req))
node2:/app/mysite#./manage.py runserver 192.168.137.3:8000
Performing system checks...
System check identified no issues (0 silenced).
August 24, 2017 - 06:45:36
Django version 1.11, using settings 'mysite.settings'
Starting development server at http://192.168.137.3:8000/
Quit the server with CONTROL-C.
给你的帖子取一个名字然后往里填一点内容,至于时间戳,
2.8 建立Blog的公共部分:
完成我们应用的数据库部分和admin部分后,现在来看看面向公众的页面部分。
从Django的角度来说,一个页面具有3个典型的组件:
1.一个模板(template),模块负责将传递进来的信息显示出来(HTML页面)
2.一个视图(view)函数,它负责获取要显示的信息,通常都是从数据库获得
3.一个URL模式,它用来把收到的请求和你的视图函数匹配,有时也会向视图传递一些参数。
创建模板:
Django的模板语言相当简单,我们直接来看代码,这是一个简单的显示单个blog帖子的模板:
node2:/app/mysite/blog/templates#cat archive.html
{%for post in posts%}
<h2?{{post.title}}</h2>
<p>{{post.timestamp}}</p>
<p>{{post.body}}</p>
{% endfor %}
它就是一个HTML (虽然Django模块可以用于任何形式的输出)加上一些大括号的特殊模板标签。
这些是标量标签(variable tag),用于显示传递给模板的数据。
在变量标签里,你可以用Python风格的dotted-notation(点记号)
来访问传递给模板的对象的属性。
例如,这里假设你传递了一个叫"post"的BlogPost对象。
创建一个视图函数:
现在我们来编写一个从数据库读取所有blog帖子的视图函数,并且我们的模板将它们显示出来。
打开blog/views.py文件并输入:
node2:/app/mysite/blog#cat views.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
# from django.shortcuts import render, render_to_response
from .models import *
# Create your views here.
from django.http import HttpResponse
from django.template import loader
def index(req):
# get all blogpost objects
blog_list = BlogPost.objects.all()
template = loader.get_template('archive.html')
context = {
'blog_list': blog_list
}
return HttpResponse(template.render(context, req))
node2:/app/mysite/blog#vim views.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
# from django.shortcuts import render, render_to_response
from .models import *
# Create your views here.
from django.http import HttpResponse
from django.template import loader
def index(req):
# get all blogpost objects
blog_list = BlogPost.objects.all()
template = loader.get_template('index.html')
context = {
'blog_list': blog_list
}
return HttpResponse(template.render(context, req))
{% extends "base.html" %}
{% block content %}
{% for post in blog_list %}
<h2>{{ post.title }}</h2>
<p>{{ post.timestamp | date:"1,F jS"}}</p>
<p>{{ post.body }}</p>
{% endfor %}
{% endblock %}
url(r'^index/$',blog_view.index), 调用blog下的view类的index方法 --入口
node2:/app/mysite/blog#vim views.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
# from django.shortcuts import render, render_to_response
from .models import *
# Create your views here.
from django.http import HttpResponse
from django.template import loader
def index(req):
# get all blogpost objects
blog_list = BlogPost.objects.all()
template = loader.get_template('index.html')
context = {
'blog_list': blog_list
}
return HttpResponse(template.render(context, req))
blog_list = BlogPost.objects.all() :获取数据库里面所拥有BlogPost对象
render_to_response()返回一个页面(index.html),顺带把数据库中查询出来的所有博客内容(blog_list)也一并返回。
把响应内容给模板Index.html
按日期排序:
node2:/app/mysite/blog#cat models.py
from django.db import models
from django.contrib import admin
# Create your models here.
class BlogPost(models.Model):
title = models.CharField(max_length = 150)
body = models.TextField()
timestamp = models.DateTimeField()
class Meta:
ordering =('-timestamp',)
通过模板过滤器格式时间戳:
虽然时间戳很好用,但是它的ISO8601格式却有点怪异。我们现在用Django模板系统里
另一个很酷的特性:过滤器(filter)来把它弄得人性化一点: