做者:Hubery 时间:2018.7.24html
能写web的语言有好多。python算是难度较低,入门较快的脚本语言。Django是python的web框架,详情很少叙,见:java
Django-wiki介绍python
# Django历史---------->>>>>这段能够不看。
在 Web 早期阶段,开发者手动编写每一个页面。更新网站要编辑 HTML;
从新设计要从新制做每个网页,而 且一次只能改一个网页。
随着网站体量的增大,这种方式立马变得繁琐、浪费时间,最终变得不切实际。
NCSA(National Center for Supercomputing Applications,国家超级计算应用中心,
第一款图形 Web 浏览器 Mosaic 就是在这里开发出来的)一群富于创新的黑客
解决了这个问题,他们让 Web 服务器派生外部程序, 动态生成 HTML。
他们把这一协议称为通用网关接口(Common Gateway Interface,CGI),
自此,Web 彻底 变了样。现在,很难想象 CGI 带来的变革:
CGI 再也不把 HTML 页面视做硬盘中存储的文件,而是把页面看 作资源,
能够按需动态生成。
CGI 的开发促使了第一代动态网站的出现。然而,CGI 自身也有问题:
CGI 脚本包含大量重复的样板代码, 致使代码难以复用,并且新手难以编写和理解。
PHP 解决了这些问题中的多数,在 Web 开发界引发了一阵风暴。
PHP 如今是建立动态网站最流行的工具,
多门相似的语言(ASP、JSP,等等)都参照了 PHP 的设计原则。
PHP 的主要创新是易于使用:PHP 代码直 接嵌入普通的 HTML 中;
对学过 HTML 的人来讲,学习曲线极为平缓。
可是,PHP 也有自身的问题:就是由于易于使用,写出的代码凌乱、重复,设计不周。
更糟的是,PHP 没有 为程序员提供多少防止安全漏洞的保护机制,
不少 PHP 开发者意识到这一点再去学习相关的知识就晚了。
上述问题以及相似的缺陷直接促使了“第三代”Web 开发框架的涌现。
Web 开发的新方式也提高了人们的雄 心,如今 Web 开发者天天所作的工做愈来愈多。
Django 就是为了迎接这些雄心而诞生的。
Django 是从真实的应用中成长起来的,由美国堪萨斯州劳伦斯的一个 Web 开发团队编写。
它诞生于 2003 年秋天,那时 Lawrence Journal-World 报社的 Web 开发者
Adrian Holovaty 和 Simon Willison 在尝试使用 Python 构建应用。
World Online 团队负责制做和维护本地的几个新闻网站,在新闻界特有的快节奏开发
环境中逐渐发展壮大。
那些网站(包括 LJWorld.com、Lawrence.com 和 KUsports.com)的
记者(和管理层)不断要求增长功能,
并且整个应用要在紧张的周期内快速开发出来,一般只有几天或几小时。
所以,Simon 和 Adrian 别无他法,只 能开发一个节省时间的 Web 开发框架,
这样他们才能在极短的截止日期以前构建出易于维护的应用。
通过一段时间的开发后,那个框架已经足够驱动世界上最大的在线网站了。
2005 年夏天,团队(彼时 Jacob Kaplan-Moss 已经加入)决定把框架做为开源软件发布出来。
他们在 2005 年 7 月发布了那个框架,将其命名 为 Django——取自爵士吉他手 Django Reinhardt。
这段历史至关重要,由于说清了两件要事。首先是 Django 的“发力点”。
Django 诞生于新闻界,所以它提供了几个特别适合“内容型”网站使用的功能(如管理后台)。
这些功能适合 Amazon.com、craigslist.org 和 washingtonpost.com 这样动态的数据库驱动型网站使用。
不过,不要所以而灰心。虽然 Django 特别适合开发这种网站,
可是这并无阻碍它成为开发任何动态网站的有效工具。(某些方面“特别”高效与某些方面不高效是由区别的。)
第二点是,Django 最初的理念塑造了开源社区的文化。Django是从真实代码中提取出来的,
而不是科研项目或商业产品,它专一于解决Django的开发者自身所面对的问题。所以,
Django一直在积极改进,几乎每一天都有变化。
Django框架的维护者一心确保它能节省开发者的时间,确保开发出的应用易于维护,
并且在高负载下的性能良好。
使用 Django 能在极短的时间内构建全面动态的网站。Django 的主旨是让你集中精力在有趣
的工做上,减轻 重复劳做的痛苦。为此,它为经常使用的 Web 开发模式提供了高层抽象,为常
见的编程任务提供了捷径,还为解 决问题提供了清晰的约定。与此同时,Django 尽可能作到
不挡路,容许你在必要时脱离框架。
复制代码
写项目就比如骑自行车,看完上面的背景,接下来就上代码体验了,直接开撸。mysql
按照草拟的项目结构,大体上有5块内容:linux
项目初步规划要完成一个电影列表/详情的查看,评论,投票,得分,支持文件上传,内容安全, 注册/登录/登出,内容缓存等。git
大体构思了下,要写好仍是须要处理很多细节问题的。好比了解下Django的编码套路,处理关联关系,数据库的CRUD等,一步步的来吧。程序员
本文主要实现项目的第一部分,启动项目
部分。github
不一样平台安装方式可能不一样,自行百度一个。 www.python.org/downloads/web
pip:pip install packages缩写,是python的包管理工具,用于安装python包。
复制代码
pip install django // 安装最新版
pip install django==2.*.* // 安装具体版本
复制代码
从网上下载一个就好了,而后搜一个激活码完事儿。sql
什么平台都同样,mac/linux/win,都记得配置环境变量
;我用的Mac环境。
这个软件安装部分,仍是得多百度,可能存在平台差别。
顺便提一句,若是有任何语言的开发基础,其实回头看python都会以为简单,老说没有python基础,看书啊! 忽然宋小宝的画面出现了,哈哈哈。有时候一门语言可能知道40%左右就能够开干了,边撸边回头翻书就好。
命令行建立
django-admin
cd workspace
django-admin startproject MyMovie
复制代码
能够用pycharm建立 默认项目结构
MyMovie\
MyMovie\
__init__.py\
settings.py\
urls.py\
wsgi.py\
manage.py\
复制代码
项目结构解析:
外层MyMovie根目录是项目容器。这个外层名称对Django来讲没什么用,能够根据喜爱更名。
根目录manage.py 是一个命令行实用脚本,能够根据不一样方式与Django项目交互。如数据库迁移,跑测试,启动开发server等,会常常用到manage.py。
内层MyMovie目录,是项目的Python包。导入这里面的内容时要用该目录名称。如MyMovie.urls。
内层MyMovie/init.py是个空文件,目的是让Python知道该目录是Python包。
内层MyMovie/settings.py是Django项目的配置。
内层MyMovie/urls.py是整个项目的URL配置,即Django驱动的网站的目录。每一个Web app的请求都会被指向urls文件中已配置过的匹配的第一个view。
内层MyMovie/wsgi.py是兼容WSGI的web服务器的接口,用于服务项目。SWGI,Web Server Gateway Interface,让Django项目与web服务器互相交互的接口。如将Django项目部署到Docker上。
TIME_ZONE = 'UTC'. # 时区
# Django中自带的激活的所有Django应用,自建的app也要配置到这里面
INSTALLED_APPS = [
'django.contrib.admin', # 管理后台
'django.contrib.auth', # 身份验证系统
'django.contrib.contenttypes', # 内容类型框架
'django.contrib.sessions', # 会话框架
'django.contrib.messages', # 消息框架
'django.contrib.staticfiles', # 管理静态文件的框架
]
复制代码
Django项目中默认包含这些app,为常见场景作的约定。 若是用到数据库表,使用以前要在数据库中先建表,为此,运行如下命令:
python manage.py migrate
复制代码
数据库配置 用mysql示例,前提是系统中有数据库,且user/password等信息都OK; 终端建立mymovie数据库
# 命令行进入mysql 并输入密码
mysql -uroot -p
# 查看当前存在的数据库
mysql> show databases;
# 建立数据库
mysql> create database mymovie;
Query OK, 1 row affected (0.10 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| blog_project_db |
| information_schema |
| mymdb |
| mymovie |
| mysql |
| performance_schema |
| sys |
+--------------------+
7 rows in set (0.00 sec)
mysql>
复制代码
在MyMovie/init.py文件中配置mysql数据库:
import pymysql
pymysql.install_as_MySQLdb()
复制代码
settings.py文件中配置mysql
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # 数据库引擎
'NAME': 'mymovie',
'USER': 'root',
'PASSWORD': 'root@123456',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
复制代码
Django应用遵循MVT模式,与传统的MVC模式无异,只是叫法不一样:
MVT模型 | 职责说明 |
---|---|
Models | 用来处理数据库读写操做 |
Views | 用来处理HTTP请求,启动模型的操做而后返回HTTP响应数据 |
Templates | 用来展现响应内容 |
cd MyMovie
python manage.py startapp core
复制代码
settings.py文件中 添加刚建立的core app 每一个注册的app后面必须带【,】
INSTALLED_APPS = [
'core',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
复制代码
Django model是从Model衍生继承过来的,有多个Fields字段。
数据库方面,一个Model对应一个数据库表,一个Model实例对应一行,Field字段对应一列。
Django model | 对应数据库 |
---|---|
Model类 | 表 |
Model实例 | 行 |
Field字段 | 列 |
用Django的ORM,用Python和Django来写model类来处理数据库,而不是直接写SQL语句。
core/models.py
from django.db import models
# 编写第一个model Movie
class Movie(models.Model):
NOT_RATED = 0
RATED_G = 1
RATED_PG = 2
RATED_R = 3
# 评分 级别
RATINGS = (
(NOT_RATED, 'NR - 没有评分'),
(RATED_G, 'G - 普通观众'),
(RATED_PG, 'PG - 父母的引导和规范'),
(RATED_R, 'R - 限制级'),
)
title = models.CharField(max_length=140)
plot = models.TextField()
year = models.PositiveIntegerField()
rating = models.IntegerField(
choices=RATINGS,
default=NOT_RATED
)
runtime = models.PositiveIntegerField()
website = models.URLField(blank=True)
def __str__(self):
return '{} ({})'.format(self.title, self.year)
复制代码
Movie继承自models.Model,models.Model
是全部Django模型的基类。
title
会转成数据库表中的一个列字段,长度为140,类型为varchar;
plot
会转成数据库的text
列,
year
会转成数据库的integer
列,Django存储以前会验证数据,确保是0或者更高。
rating
多选列。是一个integer列。可选参数choices有一个集合的游标。
Django会向model种新增一个实例方法:get_rating_display()
,返回存储在模型中符合第二个参数条件的数据。
runtime
与year同样。
website
大多数数据库列字段没有URL类型
,但数据驱动web应用常常须要存储URL。URLField
默认是长度200的varchar
列,也能够经过max_length参数设置。URLField自带了验证逻辑,能够鉴别该URL是否为有效。blank参数由admin应用使用,用来确认该参数是否能够为空。
__str__(self)
方法,将Django模型转化成可视化的字符串,相似java中的toString()。有助于debug以及输出对象内容。
Django的ORM会自动增长一个字增加的列:id
。咱们无需关心该字段。
Django的DRY理论:Donnot Repeat Yourself
咱们有了模型,须要在数据库中建立匹配该模型的表table。
用Django能够生成该表。
cd MyMovie
python manage.py makemigrations
# 一键操做 迁移全部的app的数据库 根据model建表
python manage.py migrate
复制代码
终端执行结果
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, 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 auth.0009_alter_user_last_name_max_length... OK
Applying sessions.0001_initial... OK
复制代码
执行完以后,数据库中就会生成一张表: core_movie
mysql> show tables;
+----------------------------+
| Tables_in_mymovie |
+----------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| core_movie |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+----------------------------+
11 rows in set (0.00 sec)
mysql>
复制代码
在Django的应用中才会存在数据库迁移,而不是在项目目录。
相似python,Django提供了一个交互式的REPL来尝试一下。 Django的交互脚本彻底连接数据库,因此咱们能够在shell中进行model的增删改查。
cd MyMovie
python manage.py shell
# 执行CRUD
复制代码
也能够在pycharm的python console窗口中进行操做,同样的道理。 建立一条Movie数据:
sleuth = Movie.objects.create(title='Sleuth', plot='an snobbish writer who loves games', year=1972, runtime=138,)
clear
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'clear' is not defined
sleuth.id
3
sleuth.get_rating_display()
'NR - 没有评分'
复制代码
查看数据库表中是否有刚才建立的Movie对象; 能够在命令行中访问数据库表,也能够在pycharm的database窗口中可视化查看。
mysql> select * from core_movie;
+----+--------+------------------------------------+------+--------+---------+---------+
| id | title | plot | year | rating | runtime | website |
+----+--------+------------------------------------+------+--------+---------+---------+
| 1 | Sleuth | an snobbish writer who loves games | 1972 | 0 | 138 | |
+----+--------+------------------------------------+------+--------+---------+---------+
1 row in set (0.00 sec)
mysql>
复制代码
objects, 是模型model的默认manager。是一个查询model表的接口。同时提供了一个**create()**方法来建立和保存实例。每一个model必须至少有一个manager,Django默认提供了一个manager。一般能够自定义manager,这个会在后续会详述。
id,是数据库表的主键,Django自动生成的。
get_rating_display(), 由Django生成,由于rating字段提供了一个choices的元祖。咱们在调用create()的时候没有提供rating字段值,由于rating字段有默认值0.
get_rating_display()方法查找并返回响应的value。Django将生成一个方法,遍历拥有choices参数的全部字段。
接下来用Django Admin app来建立一个后台,来管理movies。
快速生成一个后端UI,来快速填充项目数据。 为了让Django的admin app使用咱们新建的models,执行下列步骤:
1 注册咱们的model 2 建立一个superuser,能够访问后台 3 运行开发server 4 浏览器中访问后台
将Movie注册到admin中, core/admin.py
from django.contrib import admin
from core.models import Movie
admin.site.register(Movie)
复制代码
注册成功。 建立一个superuser hubery hubery2018
$ python manage.py createsuperuser
Username (leave blank to use 'hubery'): hubery
Email address: 934531487@qq.com
Password:
Password (again):
Superuser created successfully.
复制代码
运行开发server
$ python manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
July 19, 2018 - 05:35:58
Django version 2.0.6, using settings 'MyMovie.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
复制代码
浏览器中打开提示的连接:
http://127.0.0.1:8000/
复制代码
会显示出Django加载成功的页面。
进入admin后台页: 浏览器中输入:
http://127.0.0.1:8000/admin
复制代码
根据提示,输入刚才建立的superuser信息,成功登录进去以后,能够能够在线编辑数据。
为了方便,咱们能够趁热打铁的录入一批movies。
当Django接收到一个请求request,它用request的路径和项目的URLConf来匹配,找到找到在URLConf中配置的view并将该请求传进去,这个view会返回一个HTTP response。
Django视图View能够是函数,也能够是类。
FBVs Function-Based Views 基于函数的View CBVs Class-Based Views 基于类的View
咱们写一个视图展现movie列表。
core/views.py
from django.http import HttpResponse
from django.views.generic import ListView
from core.models import Movie
# 基于class的视图
class MovieList(ListView):
model = Movie
# 基于函数的视图
def test(request):
return HttpResponse('hello world.')
复制代码
ListView至少须要一个model属性。将会查询model的全部行rows,将结果传递给template展现,在返回结果中渲染出template。同时提供了好多回调函数,使得咱们能够用来替换默认行为。
ListView是怎么知道如何查询Movie的全部对象的? 针对这个问题,咱们得研究下manager和QuerySet类。每一个model都有一个默认manager。Manager主要用来提供各类方法来查询对象,如all(), 这些方法返回QuerySet。
QuerySet类是Django查询数据库的结果集,有不少方法,包含:**filter()**来限制查询结果。QuerySet一个很好的特性是:它是惰性的,在咱们从QuerySet获取model以前,不会赋值。另外一个不错的功能是:例如filter()之类的方法,使用查找表达式,这些表达式能够是字段名称,也能够跨越关系模型。
咱们将会在整个项目中这样处理。
注:全部manager类(objects)都有一个all()方法,返回一个QuerySet,
Movie.objects.all()
复制代码
至关于:
select * from core_movie;
复制代码
因此,ListView会检查该ModelList视图是否拥有model属性,若是存在,它会知道Model类拥有一个默认manager(即objects),而且这个manager拥有all()方法。
模版引擎会搜索project和app工程结构下的templates文件目录,根据视图view来找相应的template;
ListView同时也提供了一个约定/规矩/惯例:template的存放目录位置,咱们自定义的模版必须遵照这个约定,如: <app_name>/<model_name>_list.html
core/movie_list.html
即:在core app中, app_name是core, model_name是Movie; 因此模版文件名为: <model_name>_list.html =>>> movie_list.html
movie_list.html模版的存放位置: core/templates/core/movie_list.html 这样,模版引擎就能准确找到视图对应的模版。
测试:
TemplateDoesNotExist at /movies
core/movie_list.html
复制代码
因此, 切记
: 必定要严格遵照模版引擎的约定:正确存放自定义模版的位置,且:模版文件名也要按照约定来命名,两个条件缺一不可。 依照惯例,模版的命名: core/movie_list.html settings.py的配置文件中,有一个默认的template目录,将从这个目录查找模版。 若是不听从这个惯例约定,可能就加载不出模版。 这个目录能够被各个app覆盖。 'DIRS': [os.path.join(BASE_DIR, 'templates')] 'APP_DIRS': True,
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
复制代码
开始编码template core/templates/core/movie_list.html 没有相应目录,就地建立
<!DOCTYPE html>
<html>
<body>
<ul>
{% for movie in object_list %}
<li>
{{ movie }}
</li>
{% empty %}
<li>
没有电影列表。
</li>
{% endfor %}
</ul>
<p>
用的 https?
{{ request.is_secure|yesno }}
</p>
</body>
</html>
复制代码
Django的template是标准HTML,内置了变量variables和标签tags。
内置参数 | 参数说明 |
---|---|
{{variables}} | variables等待被赋值的变量, 将指定变量的值插入到这里 |
{% for item in item_list %} | 模版标签 只要能让模版系统作些事儿的 就是标签 |
{{ ship_date|date: “F J, Y” }} | 过滤器相似Unix的管道,把ship_date传递给date过滤器,并给date过滤器指定“F J, Y”参数 |
其余特性用到了再细分讨论,先忙正事儿。 [Django内置template和filters](docs.djangoproject.com/en/2.0/ref/…)
按照这个逻辑,模版中,{% extends '' %} {% block %} {% for movie in object_list %} {% url %} 是标签; {{ movie }}是变量。
接下来就是将视图连接到URLConf上。
以前的篇幅中已经准备好了model,view和template,咱们得利用URLConf告知Django哪一个request应该被路由指向到Movielist视图上。
什么是URLConf?每一个项目中都有个根URLConf,由Django建立的。
对于Django开发者来讲,最好的办法是每一个app应用都有本身的URLConf。那么接下来,根URLConf会经过**include()**函数 引入各个app目录下的URLConf。
在core下建立一个URLConf, 即建立文件:core/urls.py,
from django.urls import path
from core import views
app_name = 'core'
urlpatterns = [
# 基于class的视图,必须调用View基类的静态函数as_view()
# 返回一个可调用的字符串 传入path中
path('movies',
views.MovieList.as_view(),
name='MovieList',),
# 基于函数的视图,能够直接将函数传入url,可直接执行
url(r'$', views.test),
]
复制代码
最简单的理解,一个URLConf就是一个拥有urlpatterns属性的module,是一个path集合。
一个path由一个描述字符串的字符串组成,描述了有问题的和可调用的字符串。
FBVs Function-Based Views 基于函数的View CBVs Class-Based Views 基于类的View
CBVs不可调用,因此View的基类用一个静态函数**as_view()**返回一个可调用的字符串;
FBVs能够做为回调直接传入,不须要**()操做符**,直接能够执行。
每一个**path()**都应该起个名字,这样对于当咱们须要在template中引用这个path时颇有用。
既然一个URLConf能够被其余URLConf引用include(),因此咱们可能不知道view的全路径。
Django提供了一个reverse()函数和url模版标签,能够经过一个name找到一个view的全路径。
app_name变量,设定了URLConf属于哪一个app。这样,咱们能够区分一个被命名的path,不至于多个app中有同名path的时候Django没法区分。相似于命名空间
如,appA:index, appB:index, appC:index。
将core/urls.py连接到MyMovie/urls.py; 编辑MyMovie/urls.py
from django.contrib import admin
from django.urls import path, include
import core.urls
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(core.urls, namespace='core')),
]
复制代码
cd MyMovie
python manage.py runserver
复制代码
浏览器中输入:
http://127.0.0.1:8000/movies
复制代码
其中,基于函数的视图直接返回了HttpResponse对象,能够在任何http测试工具中测试:
http://127.0.0.1:8000/test
复制代码
这个外界测试Http接口,后续会单独介绍如何写api。
既然已经完成了项目的布局,那咱们能够加快进度。咱们已经记录了每一个movie的信息。咱们来建立一个视图,专门显示具体的movie信息。
咱们须要作三件事:
相似Django提供的ListView,同时也提供了DetailView,来显示单个model的详细信息。
core/views.py
from django.http import HttpResponse
from django.shortcuts import render
from django.views.generic import (
ListView, DetailView
)
from core.models import Movie
# 基于class的视图
class MovieList(ListView):
model = Movie
# movie详情 视图
class MovieDetail(DetailView):
model = Movie
复制代码
DetailView须要一个path()对象,引入一个pk或者slug,所以DetailView能够向QuerySet传递参数来查询特定的model实例。
一个slug是一个简短的URL友好标签,一般用于内容繁多的网站。
已经有了视图view,那么紧接着建立一个对应的模版。
Django的template支持复用,标记block部分,其余模版能够重写该block部分。这样就能够抽象出一个基类模版
,其余模版能够继承该基类模版进行拓展。
基类模版, MyMovie/templates/base.html
目录默承认能没有,手动建立
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{% block title %} {% endblock %}
</title>
<style>
.mymdb-masthead {
background-color: #EEEEEE;
margin-bottom: 1em;
}
</style>
</head>
<body>
<div class="mymdb-masthead">
<div class="container">
<nav class="nav">
<div class="navbar-brand">MyMDB</div>
<a class="nav-link"
href="{% url 'core:MovieList' %}">
Movies
</a>
</nav>
</div>
</div>
<div class="container">
<div class="row">
<div class="clo-sm-8 mymdb-main">
{% block main %} {% endblock %}
</div>
<div class="col-sm-3 offset-sm-1 mymdb-sidebar">
{% block sidebar %}
{% endblock %}
</div>
</div>
</div>
</body>
</html>
复制代码
该base.html包含三块block:title/main/sidebar
{%block %}: 告诉模版引擎,这部份内容能够被子模版覆盖。
{% block title %}MyMovie{% endblock %}, 建立了一个title的block,其余templates能够替换该部分。若是其余模版没替换,即沿用默认基类的。
href="{% url 'core:MovieList' %}" url标签会生成一个URL的path,URL的名字应该这样命名:<app_namespace>:, 好比:core是namespace,name是MovieList,那么url标签后面跟的就是core:MovieList。
建立一个简单的模版 core/templates/core/movie_detail.html
{% extends 'base.html' %}
{% block title %}
{{ object.title }} - {{ block.super }}
{% endblock %}
{% block main %}
<h1>{{ object }}</h1>
<p class="lead">
{{ object.plot }}
</p>
{% endblock %}
{% block sidebar %}
<div>
这个电影排名:
<span class="badge badge-primary">
{{ object.get_rating_display }}
</span>
</div>
{% endblock %}
复制代码
这个模版只有不多的HTML部分,由于大部分HTML在base.html中已经包含了。movie_detail.html须要作的就是给base.html中定义的blocks提供数值。
看下新的标签:
{% extends 'base.html' %} 用extends来实现继承
另一个模版。Django先找到base模版先执行,而后再替换blocks。
{% object.title %} - {% block.super %}
{% block.super %} 魔法变量,从base模版中的block中获取内容,提供base模版中渲染后的文本。
{{ object.get_rating_display }} Django模版不用()来执行函数,直接用函数名字就能够执行。
from django.conf.urls import url
from django.urls import path
from core import views
app_name = 'core'
urlpatterns = [
# 基于class的视图,必须调用View基类的静态函数as_view()
# 返回一个可调用的字符串 传入path中
path('movies',
views.MovieList.as_view(),
name='MovieList',),
# 向MovieDetail视图中传递pk参数 获取特定的movie对象
path('movie/<int:pk>',
views.MovieDetail.as_view()),
# 基于函数的视图,能够直接将函数传入url,可直接执行
url(r'$', views.test),
]
复制代码
浏览器中输入:
http://127.0.0.1:8000/movie/2
复制代码
待截图显示
core/movie_list.html
{% extends 'base.html' %}
{% block title %}
全部Movies
{% endblock %}
{% block main %}
<ul>
{% for movie in object_list %}
<li>
<a href="{% url 'core:MovieDetail' pk=movie.id %}">
{{ movie }}
</a>
</li>
{% endfor %}
</ul>
{% endblock %}
复制代码
url标签,用了一个叫pk(primary key)的参数,由于MovieDetail URL须要一个pk参数。若是没有参数,渲染过程当中Django会抛一个NoReverseMatch的异常,致使500错误。
刷新浏览器
http://127.0.0.1:8000/movies
复制代码
会发现movies列表显示的是超连接样式,点击能够进入到详情页。 截图:
Model中新增一个内部类 Meta 指定ordering字段
from django.db import models
# 编写第一个model Movie
class Movie(models.Model):
#省略以前的部分
# Model内部类 能够指定Model的信息。
class Meta:
ordering = ('-year', 'title')
def __str__(self):
return '{} ({})'.format(self.title, self.year)
复制代码
ordering字段,指定排序参照的字段,year降序,title。对应sql语句:
order by year desc, title;
复制代码
刷新浏览器,能够发现,movie列表是降序排列。
分页有点儿问题 代码先放上, 先跳过这部分
。
既然movies已经排序了,直接给加上分页。Django的ListView视图额外已经内置了分页,因此直接用就好。
Pagination由GET参数控制page页的显示。
将分页功能加到block main的底部;
{% extends 'base.html' %}
{% block title %}
全部Movies
{% endblock %}
{% block main %}
<ul>
{% for movie in object_list %}
<li>
<a href="{% url 'core:MovieDetail' pk=movie.id %}">
{{ movie }}
</a>
</li>
{% endfor %}
</ul>
{% comment 添加分页 先注释掉 %}{% if is_paginated %}
<nav>
<ul class="pagination">
<li class="page-item">
<a href="{% url 'core:MovieList' %}?page=1"
class="page-link">First</a>
</li>
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link"
href="{% url 'core:MovieList' %}?page={{ page_obj.previous_page_num}}">
{{ page_obj.previous_page_number }}
</a>
</li>
{% endif %}
<li class="page-item active">
<a href="{% url 'core:MovieList' %}?page={{ page_obj.number }}">
{{ page_obj.number }}
</a>
</li>
{% if page_obj.has_next %}
<li class="page-item">
<a href="{% url 'core:MovieList' %}?page={{ page_obj.next_page_number }}"
class="page-link">
{{ page_obj.next_page_number }}
</a>
</li>
{% endif %}
<li>
<a href="{% url 'core:MovieList' %}?page=last"
class="page-link">
Last
</a>
</li>
</ul>
</nav>
{% endif %}{% endcomment %}
{% endblock %}
复制代码
若是URL输入错误,就会出现404,资源不存在错误;能够自定义404提示页面,这个也无伤大雅,回头补充。
相似于java的junit测试,先不写了。
建模部分,涉及到外键, 一对多
, 多对多
关系的梳理。
综上,你会发现,用Django的套路是:
Django用的是MVT模式
,本质就是MVC。
至于MVT各个模块之间怎么衔接起来的,那就问Django了呵。开个玩笑,Django框架自己处理的很是完美,后续好好梳理下这个调用的流程。
宗旨:尽可能不重复造轮子。
关于源码,还在梳理整合,须要留言,回头发布到github上。
天星技术团QQ:557247785
。