内容简介:能写web的语言有好多。python算是难度较低,入门较快的脚本语言。Django是python的web框架,详情不多叙,见:写项目就好比骑自行车,看完上面的背景,接下来就上代码体验了,直接开撸。
能写web的语言有好多。python算是难度较低,入门较快的脚本语言。Django是 python 的web框架,详情不多叙,见:
# 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 尽量做到 不挡路,允许你在必要时脱离框架。 复制代码
写项目就好比骑自行车,看完上面的背景,接下来就上代码体验了,直接开撸。
按照草拟的项目结构,大致上有5块内容:
- 启动项目
- 新增用户
- 文件安全
- 缓存列表
- 项目部署
项目初步规划要完成一个电影列表/详情的查看,评论,投票,得分,支持文件上传,内容安全, 注册/登陆/登出,内容缓存等。
大致构思了下,要写好还是需要处理不少细节问题的。比如了解下Django的编码套路,处理关联关系,数据库的CRUD等,一步步的来吧。
本文主要实现项目的第一部分, 启动项目 部分。
1 环境准备
- 安装python 默认的就是最新的3.6.*
不同平台安装方式可能不同,自行百度一个。 https://www.python.org/downloads/
- 安装django 默认的是最新的2.*
pip:pip install packages缩写,是python的包管理工具,用于安装python包。 复制代码
pip install django // 安装最新版 pip install django==2.*.* // 安装具体版本 复制代码
- 安装pycharm IDE
从网上下载一个就行了,然后搜一个激活码完事儿。
- 安装mysql
什么平台都一样,mac/linux/win,都记得 配置环境变量 ;我用的Mac环境。
这个软件安装部分,还是得多百度,可能存在平台差异。
顺便提一句,如果有任何语言的开发基础,其实回头看python都会觉得简单,老说没有python基础,看书啊! 突然宋小宝的画面出现了,哈哈哈。有时候一门语言可能知道40%左右就可以开干了,边撸边回头翻书就好。
2 创建项目 MyMovie
命令行创建
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 上。
2.1 解析settings.py文件
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',
}
}
复制代码
2.2 创建core应用
Django应用遵循MVT模式,与传统的MVC模式无异,只是叫法不同:
| MVT模型 | 职责说明 |
|---|---|
| Models | 用来处理数据库读写操作 |
| Views | 用来处理HTTP请求,启动模型的操作然后返回HTTP响应数据 |
| Templates | 用来展示响应内容 |
2.2.1 命令行 创建app
cd MyMovie python manage.py startapp core 复制代码
2.2.2 注册新建的core app
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', ] 复制代码
2.2.3 创建Model Movie
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
2.2.4 数据库迁移
我们有了模型,需要在数据库中创建匹配该模型的表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的应用中才会存在数据库迁移,而不是在项目目录。
2.2.5 创建第一个Movie
类似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。
2.2.6 创建Movie的admin
快速生成一个后端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。
2.2.7 创建MovieList视图
当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()方法。
2.2.8 添加用来展示movieList的模版template
模版引擎会搜索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 这样,模版引擎就能准确找到视图对应的模版。
测试:
- 将movie_list.html的目录变化一下, core/templates/core/movie_list.html 变成: core/templates/movie_list.html 刷新浏览器就会报错,在模版引擎中对应的正确位置上没发现模版:
TemplateDoesNotExist at /movies core/movie_list.html 复制代码
- 然后再将目录还原: core/templates/movie_list.html 变成: core/templates/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 ](https://docs.djangoproject.com/en/2.0/ref/templates/builtins/)
按照这个逻辑,模版中,{% extends '' %} {% block %} {% for movie in object_list %} {% url %} 是标签; {{ movie }}是变量。
2.2.9 通过URLConf将请求定位到视图View
接下来就是将视图链接到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')),
]
复制代码
2.2.10 运行开发server 查看结果
cd MyMovie python manage.py runserver 复制代码
浏览器中输入:
http://127.0.0.1:8000/movies 复制代码
其中,基于函数的视图直接返回了HttpResponse对象,可以在任何http测试 工具 中测试:
http://127.0.0.1:8000/test 复制代码
这个外界测试Http接口,后续会单独介绍如何写api。
2.3 创建Movie相关页面
既然已经完成了项目的布局,那我们可以加快进度。我们已经记录了每个movie的信息。我们来创建一个视图,专门显示具体的movie信息。
我们需要做三件事:
2.3.1 创建MovieDetailView
类似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友好标签,通常用于内容繁多的网站。
2.3.2 创建movie_detail.html模版
已经有了视图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模版不用()来执行函数,直接用函数名字就可以执行。
2.3.3 将MovieDetail视图配置到URLConf中
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 复制代码
待截图显示
2.4 处理Movie列表分页 点击跳转
2.4.1 给MovieList.html增加点击跳转到详情页功能
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列表显示的是超链接样式,点击可以进入到详情页。 截图:
2.4.2 设置排序
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列表是降序排列。
2.4.3 添加分页
分页有点儿问题 代码先放上, 先跳过这部分 。
既然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 %}
复制代码
2.4.4 404错误
如果URL输入错误,就会出现404,资源不存在错误;可以自定义404提示页面,这个也无伤大雅,回头补充。
2.4.5 测试视图和模版
类似于java的junit测试,先不写了。
2.5 添加Person和model关系
建模部分,涉及到外键, 一对多 , 多对多 关系的梳理。
[ Django2 web实战01-启动项目-model处理 ](https://www.jianshu.com/p/7186d2e323b2)
3 小结
综上,你会发现,用Django的套路是:
- 配置项目属性,settings.py
- 创建一个应用core
- 在core/models.py中编写模型处理数据库数据
- 再core/views.py中编写视图用来处理HTTP
- 在core/urls.py中配置应用路径,使得视图view可到达
- 再将core/urls.py链接到Django项目的urls.py中
- 如果需要展示视图的http返回内容或者数据库返回内容,借助Django模版
Django用的是 MVT模式 ,本质就是MVC。
至于MVT各个模块之间怎么衔接起来的,那就问Django了呵。开个玩笑,Django框架本身处理的非常完美,后续好好梳理下这个调用的流程。
宗旨:尽量不重复造轮子。
关于源码,还在梳理整合,需要留言,回头发布到github上。
天星技术团QQ: 557247785 。
以上所述就是小编给大家介绍的《Django2 web实战01-启动项目》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Machine Learning in Action
Peter Harrington / Manning Publications / 2012-4-19 / GBP 29.99
It's been said that data is the new "dirt"—the raw material from which and on which you build the structures of the modern world. And like dirt, data can seem like a limitless, undifferentiated mass. ......一起来看看 《Machine Learning in Action》 这本书的介绍吧!