系统说明
- Python 3.7.3
- Django 3.04
项目与应用(Project&Application)
- 项目:可以认为是一系列文件,用来创建并运行一个完整的Web站点
- 应用:具有特定功能的子模块
- 关系:在项目文件夹下,有一个或多个子文件夹,每个子文件夹有特定的功能,称为应用
创建项目
创建项目的命令:
- django-admin startproject project_name
这里的project_name就是自己的项目名称,比如,django-admin startproject mysite
此时的目录结构为:
- mysite
- _init_.py--------------------------------------告诉Python其所在目录是一个Python包
- settings.py ---------------------项目相关的初始化配置,比如配置数据库、添加应用
- urls.py 全局URL配置(URLconf)主将url映射到应用程序上(某个应用的url.py文件)
- wigs.py ----------------------------------------Web server gateway interface的缩写
- manage.py
- django-admin startproject project_name .
project_name 后面加一个空格和点,旨在将项目内容放到当前目录
运行Django的命令(* 命令行需要切换到manag.py所在目录)
- python manage.py runserver
- python manage.py runserver 8000 -----------------可以在命令行指定服务器运行端口
此时目录下会多出一个db.sqlite3。
- mysite
- _init_.py
- settings.py
- urls.py
- wigs.py
- db.sqlite3
- manage.py
SQLite是python默认安装的数据库,Django中默认使用,因为此时我们尚未配置数据库,所以就有了这个默认文件(该默认文件是在settings.py中的DATABASES里设置的),SQLite将数据库另存为文件系统中的单个文件。访问控制就是简单的文件访问权限。
- HOST一项留空,表示数据库服务器与应用程序运行在同一台计算机上
- PORT的值只有数据库服务器在非标准端口上运行时才需要指定(Mysql服务器默认情况下会使用3306端口)
创建应用
创建应用的命令:
- django-admin startapp app_name
- python manage.py startapp app_name
这里的app_name就是自己的应用的名称,比如,python manage.py startapp blog
blog就是项目mysite的一个应用。此时的目录结构是
- admin.py:管理工具,比如设置管理界面(admin)能够管理的应用模型
- apps.py:应用的配置,比如为管理功能提供一个合适的应用名称
- migrations:存储应用的数据库表结构指令,这些指令可以修改和创建数据库
- models.py :(应用的)数据模型
- tests.py:单元测试文件
- views.py: 视图函数(即MVC中的控制器)文件,用于响应各种请求的函数(基于函数的视图)或类(基于类的视图)。可以使用其它文件名称,但views是习惯使用的文件名称。
注册应用
为了让Django知道这个新的应用(blog)是项目的一部分,需要在配置文件settings.py中的INSTALLED_APPS定义(或注册)这个应用。
当创建完应用(django-admin startapp app_name)后,为了防止下一节创建(设计)的模型进行数据迁移(也就是执行python manage.py makemigration 和python manage.py migrate)无效,我们需要第一时间在INSTALLED_APPS注册我们上一节创建的应用
- INSTALLED_APPS中的应用django.contrib.auth是创建项目时就有的,是Django默认(内置)的用户权限管理应用
创建(设计)模型
模型models.py是Django系统的核心.
BlogPost类是dango.db.models.Model的子类。Model是Django中用于数据模型的标准基类,是DjangoORM的核心。
创建表
- python manage.py makemigrations
- python manage.py migrate
此时,已经完成了数据模型部分。如果了解WEb应用设计中MVC模式,会意识到已经完成了模型,但还缺少试图(面向用户的HTML、模版等)和控制器(应用逻辑)
Django社区使用另外一种形式的MVC模式,在Django中被称为MVC模式,即模型-模板-试图。
- 数据模型保持不变
- MVC中的视图在Django中是模板,因为模板是用来定义用户可见的内容
- Django中的视图表示视图函数(基于函数的视图和基于类的视图),它们组成控制器的逻辑
创建超级用户
为了方便后续的操作,我们需要创建一个超级用户。
- python manage.py createsuperuser
管理应用admin
自动管理后台应用,简称admin,被誉为Django皇冠上的明珠。admin是一个应用,每个Web站点都要,因为需要确认应用能够创建、更新或删除记录。
Django自带admin应用,在上面的INSTALLED_APPS中第一个就是,并且在创建表中已经完成。每次在向项目中添加新的应用是,都需要执行创建表的命令,来确保在数据库中创建所需的表。
admin设置完成后,要访问admin页面,就需要给给定一个URL。在自动生成的项目中urls.py中,可以看到默认给的url.
当用户访问Web站点的127.0.0.1:8000/admin/时,在服务器开启的情况下,Django就能载入默认的admin界面。
输入上面创建的超级用户的username和password,点击 Log in,出现下面的管理页面
Groups和Users是Django在用户管理应用默认的的用户分类。
为什么这里没有列出我们之前创建的BlogPost类呢?
因为我们没有通过admin.site.register()注册BlogPost。应用需要告知Django哪个模型需要在admin页面中显示并编辑。因此我们需要到应用blog的admin.py中注册类BlogPost。
另外两个常见的原因是:
- 应用的models.py文件存在错误
- 忘记将应用添加到settings.py文件中的INSTALLED_APPS中
刷新页面(如果增加了新文件,一般需要重启Django服务),会看到我们创建的BlogPost
现在来看看admin的真正力量:数据处理能力。单击Blog post链接,会跳转到一个新的页面,该页面会列出数据库中所有的BlogPost对象。
Django为什么为BlogPost对象使用这么拗口的“BlogPost object”标签?因为Django可以处理不同类型的内容,所以不会猜测某个对象最合适的标签,而是直接使用一个通用标签。
我们点击右上角的 ADD BLOG POST 来添加2条blog,添加成功后会显示如下页面
此时有2条blog无法区分,因为所有的blog都会使用“BlogPost object”标签。Django是否会有更好的方法来区分显示或使显示变得有用呢?答案是肯定的。
此前,我们使用最精的配置启用了admin,即使用admin应用本身注册了模型。
现在,我们通过额外两行代码,修改并注册调用,来更好地显示blog。
创建用户界面
前面完成仅仅是针对开发者。从Django的角度来看,Web页面应该有以下3个组件。
- 模板:用于显示通过Python类字典对象传入的信息
- 视图函数:用于处理针对请求的的核心逻辑。视图会从数据库获取信息并格式化显示
- URL模式:将传入的请求映射到对应的视图,同时将参数传输传递给视图。
Django是如何处理请求的?
- 查找匹配的url
- 调用对应的视图函数
- 将渲染好的数据通过模版展现给用户
这里我们采用稍微不同上面的顺序来构建应用
- 创建模版,用于可以观察的内容
- 设计URL,用与让Django可以立刻访问应用
- 开发视图函数,并在此基础上迭代开发
创建模板
首先需要在应用文件夹下创建一个templates文件夹用来存储我们的模版。
templates目录是Django默认存放应用所需模板的目录,因此模板目录名必须是templates。默认情况下,搜索模板时,Django会在每个安装应用的子目录中搜索templates目录。
*(其实模板目录名不必须是templates,可以自定义,详见下章的“自定义模板位置”)
此时的目录结构变为
- {%...%}:块标签
- {{...}}:变量标签
- 传给模版的变量时特殊的Python字典,称为上下文(context)
设计url
用户浏览器中的URL的路径名如何映射到应用的不同部分?当用户通过浏览器发出一个请求时,因特网会将主机名与IP地址映射起来(用户也可以直接使用IP地址),然后客户端在80或者其它端口与服务器地址连接起来。服务器通过WSGI将请求传递给Django。接受请求的路径(URL中除了协议、主机、端口之外的内容)传递到项目的URLconf文件(例如mysite/url.py)并通过正则表达式匹配到响应的路径(否则,服务器会返回404错误):
- 要么是URL需要匹配的视图函数
- 要么是include()函数中另一个URLconf文件
如果是单应用的项目,可以直接在./mysite/url.py中配置,但这样会混淆项目和应用的URL。我们希望在其它地方也能使用blog应用,所以需要应用能自己负责自己的URL。这样更符合代码重用、DRY、在一处调试相同的代码等准则。为了正确分离项目和应用的URL配置,需要通过两步来定义URL映射规则,即创建两个URLconf:一个用于项目,一个用于应用。
include()函数将动作推迟到应用的URLconf。当使用include()函数时,其参数“blog/urls”会移除当前的URL路径头,路径中剩下的部分传递给下游的URLconf。
例如,当在客户端浏览器输入http://127.0.0.1:8000/blog/foo/bar这个URL时:
- 项目的URLconf接受到的是blog/foo/bar,
- 匹配“^blog”正则表达式,并找到一个include()函数(与视图函数相反),
- 移除blog/,
- 将剩下的部分,也就是将foo/bar传递给mysite/blog/urls.py中匹配到的视图函数。
为什么上图中的blog/urls用引号括起来,而admin.site.urls没有?这不是一个输入错误。
include()函数可以接受字符串或对象。一般使用字符串,但有些开发者更愿意传递对象。当传递对象时,需要确保已经导入该对象。
path()第一个参数为空字符串,表示访问根目录,又因为在blog应用中,所以访问的是blog应用的根。
创建视图函数
视图函数通常写在project/app/views.py文件中,比如mysite/blog/views.py中。当然,也可以写到任何符合文件命名的文件中。我们在此遵循惯例。
- blog_title()函数是在视图文件中编写的一个函数,这种方式被称为“基于函数的视图”。还有一种方式是“基于类的视图”,我们在此不作介绍。
- blog_title()函数的参数request是响应所接收到的请求,必不可少且总位于第一参数位置。当客户端通过URL向服务器发送请求时,Django会创建一个HttpRequest对象,request是HttpRequest的替代。
- render()函数的作用是将数据渲染到模板上,render_to_response()也可以实现render()函数的效果。二者的区别是,render()是render_to_response()的快捷方式,会自动使用RequestContext。