参考资料:《Python编程:从入门到实践》——【美】Eric Matthes 著 袁国忠译
Python版本:3.9.5
django版本:3.2.6
系统:Windows 10
文章目录
上一篇中记录了建立项目、创建应用程序这两个步骤的详细过程,这一篇中将记录后面两个步骤的详细过程——创建主页和创建其他网页。
下面让我们开始吧!
3. 创建主页
使用Django创建网页的过程通常分为三个阶段:定义 URL 、编写视图和编写模板。首先,你必须定义URL模式。URL模式描述了URL是如何设计的,让Django知道如何将浏览器请求与网站URL匹配,以确定返回哪个网页。
每个URL都被映射到特定的视图——视图函数获取并处理网页所需的数据。视图函数通常调用一个模板,后者生成浏览器能够理解的网页。
3.1 映射 URL
用户通过在浏览器中输入URL以及单击链接来请求网页,因此我们需要确定项目需要哪些URL。当前基础URL(http://127.0.0.1:8000/
)返回默认的Django网站,让我们知道正确地建立了项目。我们将修改这一点,将这个基础URL映射到我们的项目hahaproject
的主页。
当前项目主文件夹hahaproject
中的文件urls.py
中有如下内容:
urls.py
"""hahaproject URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
文档字符串的第一行给出来这个文件的说明:hahaproject URL Configuration
。主体部分的urlpatterns
是重点——在这个针对整个项目的urls.py
文件中,变量urlpatterns
包含了项目中的应用程序的URL。当前唯一存在的URLadmin.site.urls
,这个模块定义了可在管理网站中请求的所有URL。
下面,我们就需要包含我们自己创建的应用程序hahaprojects
的URL了:
urls.py
"""hahaproject URL Configuration"""
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(('hahaprojects.urls', 'hahaprojects'), namespace='hahaprojects')),
]
列表中新添加的一行代码便是包含应用程序hahaprojects
的URL的代码了。关于path
函数以及include()
函数的使用可参考官方文档。不要忘记include()
函数第一个参数是一个二元元组,其中要给出app_namespace
,不给出的话会报错。
总之,这一行代码的作用便是:当我们请求基础URL时,会调用include()
函数,函数会包含应用程序hahaprojects
中的模块hahaprojects.urls
。而目前文件夹hahaprojects
中还没有urls.py
,因此,下面我们就来创建这个urls.py
。
在应用程序hahaprojects
的文件夹hahaprojects
中创建名为urls
的.py
文件,内容如下:
urls.py
"""定义hahaprojects的URL模式"""
from django.urls import path
from . import views
urlpatterns = [
#主页
path('', views.index, name='index'),
]
path()
函数的第一个参数是基础URL后面的URL,而这个是空字符串,所以它对应的便是基础URL。第二个参数指定了要调用的视图函数。第三个参数则将这个URL模式的名称指定为index
,让我们能够在代码的其他地方引用它。每当需要提供到这个主页的链接时,我们都将使用这个名称,而不必再次编写URL。因此总的来说,当我们请求基础URL时,Django将调用views.index
,这是个视图函数,稍后编写。
3.2 编写视图
视图函数接受请求中的信息,准备好生成网页所需的数据,再将这些数据发送给浏览器——这通常是使用定义了网页是什么样的模板实现的。
hahaprojects
中的文件views.py
是执行命令python manage.py startapp
时自动生成的,其中只有一行import
语句和一行注释,下面在其中定义index
函数,修改后的代码如下:
views.py
from django.shortcuts import render
def index(request):
"""项目的主页"""
return render(request, 'hahaprojects/index.html')
render()
函数根据视图提供的数据渲染响应。URL请求与我们刚才定义的模式匹配时,Django将在文件views.py
中查找函数index()
,再将请求对象传递给这个视图函数。
3.3 编写模板
模板定义了网页的结构。模板指定了网页是什么样的,而每当网页被请求时,Django将填入相关的数据。模板让你能够访问视图提供的任何数据。我们的主页视图没有提供任何数据,因此相应的模板非常简单。
下面我们需要创建index.html
这个模板。创建的位置需要进行一些特殊处理——我们首先在hahaprojects
中创建名为templates
的文件夹,再在其中创建名为hahaprojects
的文件夹,这个文件夹便是创建模板的位置。我们创建文件index.html
,然后编写如下代码:
index.html
<p>HahaProject</p>
<p>
HahaProject 帮助你记录你周围的笑(不必觉得这是个没用的Project,因为我们只是拿它来学习)。
</p>
现在三个步骤——**定义 URL(编写主文件夹中的urls.py
和在应用程序中添加urls.py
) 、编写视图(编写views.py
)和编写模板(编写.html
文件)**全部完成了,下面在浏览器中输入基础URLhttp://127.0.0.1:8000
,你将会看到下面的界面:
没错,这里显示的就是我们编写的index.html
中的内容。
创建网页的过程看起来可能很复杂,但将URL、视图和模板分离的效果实际上很好。这让我们能够分别考虑项目的不同方面,且在项目很大时,让各个参与者可专注于其最擅长的方面。
4. 创建其他网页
通过创建主页我们熟悉了创建网页的流程,下面我们扩充我们的hahaproject
项目。我们将创建两个显示数据的网页,一个用来显示笑的主人,另一个显示笑出现的若干原因(一对多的关系)。对于每个网页,我们都将指定URL模式,编写一个视图函数,并编写一个模板。但由于大多数模板都会有相同的部分,所以我们要用到模板继承,即先创建一个父模板,项目中的其他模板都将继承它。
4.1 模板继承
编写一个包含通用元素的父模板能让修改项目的整体外观容易得多。
1. 父模板
在index.html
所在目录中创建名为base.html
的模板。这个文件包含所有页面都有的元素;其他的模板则都继承base.html
。由于我们将在每个页面中包含这个模板,所以我们将这个标题设置为到主页的链接:
base.html
<p>
<a href="{% url 'hahaprojects:index' %}">HahaProject</a>
</p>
{% block content %}{% endblock content %}
第二行实际上是个超链接,但是链接的地址我们并没有直接给出URL,而是使用了一个模板标签来生成,它是用大括号和百分号{% %}
表示的。模板标签是一小段代码,生成要在网页中显示的信息。在这里,生成的URL与hahaprojects/urls.py
中定义的名为index
的URL模式匹配。hahaprojects
是一个namespace
,而index
则是该namespace
中一个独特的URL模式(这里与前面编写的两个urls.py
相呼应)。
末尾则是插入的一对块标签,这个块名为content
,是一个占位符,其中包含的信息将由子模板指定。
2. 子模板
现在需要重新编写index.html
,使其继承base.html
,如下所示:
index.html
{% extends "hahaprojects/base.html" %}
{% block content %}
<p>HahaProject</p>
<p>
HahaProject 帮助你记录你周围的笑(不必觉得这是个没用的Project,因为我们只是拿它来学习)。
</p>
{% endblock content %}
第一行是继承语句,让Django知道它继承了哪个父模板。紧接着的是{% block content %}
和{endblock content}
,这二者之间填充的便是当前网页特有的内容。
4.2 显示所有笑的主人
这个网页会显示当前数据库中存储的所有笑的主人,它需要使用数据,下面让我们开始编写吧!
编写步骤依然是三步——定义URL、编写视图、编写模板。
1. URL模式
通常,使用一个简单的URL片段来指出网页显示的信息;我们将使用单词laughters
,因此URLhttp://127.0.0.1:8000/laughters
将返回显示所有笑的主人的页面。下面修改应用程序hahaprojects
中的urls.py
文件:
urls.py
"""定义hahaprojects的URL模式"""
from django.urls import path
from . import views
urlpatterns = [
#主页
path('', views.index, name='index'),
#显示所有笑的主人
path('laughters/', views.laughters, name='laughters'),
]
我们在列表urlpatterns
中又添加了一行语句,其URL与该模式匹配的请求都将交给views.py
中的函数laughters()
进行处理。下面我们在views.py
中添加这个函数。
2. 视图
函数laughters
需要从数据库中获取一些数据,并将其发送给模板。所以我们需要从models.py
中导入类(即模型),然后在定义的laughters()
函数中使用它。修改后的views.py
文件如下:
views.py
from django.shortcuts import render
from .models import Laughter
def index(request):
"""项目的主页"""
return render(request, 'hahaprojects/index.html')
def laughters(request):
"""显示所有的笑的主人"""
laughters = Laughter.objects.order_by('date_added')
context = {'laughters': laughters}
return render(request, 'hahaprojects/laughters.html', context)
第2行我们导入了类Laughter
,然后我们定义了函数laughters()
。在这个函数中,我们首先调用order_by
函数对类Laughter
的所有实例依照属性date_added
进行排序,返回的查询集存储在laughters
中,然后我们定义了一个将要发送给模板的上下文 context
,这是一个字典,键是我们将在模板中用来访问的数据的名称,值是我们要发送给模板的数据。可以看到,我们将变量context
也传给了render()
函数。下面要做的就是编写laughters.html
。
3. 模板
在index.html
所在文件夹中创建名为laughters
的.html
文件,下面对其进行编写:
laughters.html
{% extends "hahaprojects/base.html" %}
{% block content %}
<p>Owners of Laughter</p>
<ul>
{% for laughter in laughters %}
<li>{{ laughter }}</li>
{% empty %}
<li>No laughters have been added yet.</li>
{% endfor %}
</ul>
{% endblock content %}
我们这里使用了一个相当于for
循环的模板标签,它遍历字典context
中的列表laughters
。这其实并不是标准HTML语法,而是用来给Django读取的。最终产生的效果便是显示一个无序列表,每一个条目都是列表laughters
中的元素。
下面我们需要修改父模板,使其包含到显示所有笑的主人的页面的链接:
base.html
<p>
<a href="{% url 'hahaprojects:index' %}">HahaProject</a> -
<a href="{% url 'hahaprojects:laughters' %}">Owners of Laughter</a>
</p>
{% block content %}{% endblock content %}
我们添加了一行超链接,URL还是使用模板标签来生成,它生成的链接与hahaprojects/urls.py
中名为laughters
的URL模式匹配。
现在我们在浏览器中刷新主页,就可以看到下面的界面:
我们看到开头有两个超链接,第一个是链接到主页的,第二个是链接到所有笑的主人的页面。
4.3 显示特定的笑的原因的页面
下面我们创建一个显示特定的笑的若干原因的页面。还是那三个步骤,定义URL,编写视图,编写模板。同时我们还将修改刚才的laughters.html
,让每一个条目都是链接,链接到这个特定的笑的原因的页面。下面让我们开始吧!
1. URL模式
显示特定笑的原因的页面与前面的所有URL模式都稍有不同,因为它将使用laughter
的id
属性来指出请求的是哪个笑。例如URLhttp://http://127.0.0.1:8000/laughters/1/
就应该对应着id
为1的笑的详细页面。下面是与这个URL匹配的模式,它包含在hahaprojects/urls.py
中,修改后的文件如下:
urls.py
"""定义hahaprojects的URL模式"""
from django.urls import path
from . import views
urlpatterns = [
#主页
path('', views.index, name='index'),
#显示所有笑的主人
path('laughters/', views.laughters, name='laughters'),
#特定的笑的原因
path('laughters/<int:laughter_id>/', views.laughter, name='laughter'),
]
我们在列表urlpatterns
中又添加了一个URL,其中/<int:laughter_id>/
与包含在两个斜杠内的整数匹配,并将这个整数存储到名为laughter_id
的实参中。如果URL与这个模式匹配,那么Django将调用视图函数laughter()
,并将存储在laughter_id
中的值作为实参传递给它。在这个函数中,我们将使用laughter_id
的值来获取相应的主题。
2. 视图
函数laughter()
需要从数据库中获取指定的笑的主人以及与之相关联的所有笑的原因,如下所示:
views.py
from django.shortcuts import render
from .models import Laughter
def index(request):
"""项目的主页"""
return render(request, 'hahaprojects/index.html')
def laughters(request):
"""显示所有的笑的主人"""
laughters = Laughter.objects.order_by('date_added')
context = {'laughters': laughters}
return render(request, 'hahaprojects/laughters.html', context)
def laughter(request, laughter_id):
"""显示单个笑的主人及笑的所有原因"""
laughter = Laughter.objects.get(id=laughter_id)
laugh_reasons = laughter.laughreason_set.order_by('-date_added')
context = {'laughter': laughter, 'laugh_reasons': laugh_reasons}
return render(request, 'hahaprojects/laughter.html', context)
这个视图函数除了包含request
对象外还包含另一个形参。在laughter()
函数中,我们使用get()
来获取指定的笑。然后我们使用.laughreason_set
来获取与这个笑相关联的条目,并将它们按date_added
降序排列(-
指定按降序排列)。再将laughter
和laugh_reason
都存储在字典context
中,再将这个字典发送给模板laughter.html
。下面我们就来编写这个模板。
3. 模板
这个模板需要显示笑的主人和笑的若干原因;如果当前这个笑不包含任何原因,我们还需要指出这一点。
laughter.html
{% extends "hahaprojects/base.html" %}
{% block content %}
<p><b>Owner of Laughter:</b> {{ laughter }}</p>
<p><b>Reasons of laughing:</b></p>
<ul>
{% for laugh_reason in laugh_reasons %}
<li>
<p>{{ laugh_reason.date_added|date:'M d, Y H:i' }}</p>
<p>{{ laugh_reason.reason|linebreaks }}</p>
</li>
{% empty %}
<li>
There are no reasons for this laughter yet.
</li>
{% endfor %}
</ul>
{% endblock content %}
第10行,|
表示模板过滤器,即对模板变量的值进行修改的函数。过滤器date:'M d, Y H:i'
以这样的格式显示时间戳:January 1, 2021 00:00。下面一行的过滤器linebreaks
将包含换行符的长条目转换成浏览器能够理解的格式,以免显示为一个不间断的文本块。
4. 将显示所有笑的主人的页面中的每个条目都设置为链接
下面我们修改laughters.html
,让其中每个条目都链接到相应网页:
laughters.html
{% extends "hahaprojects/base.html" %}
{% block content %}
<p>Owners of Laughter</p>
<ul>
{% for laughter in laughters %}
<li>
<a href="{% url 'hahaprojects:laughter' laughter.id %}">{{ laughter }}</a>
</li>
{% empty %}
<li>No laughters have been added yet.</li>
{% endfor %}
</ul>
{% endblock content %}
我们使用模板标签url
根据hahaprojects
中名为laughter
的URL模式来生成合适的链接。这个URL模式需要提供实参laughter_id
,因此我们在模板标签中添加了属性laughter.id
。现在每个笑的主人的列表中每一个条目都是一个链接,链接到显示相应原因的页面。
下面我们单击其中一个条目,看到如下界面:
Django 入门部分的内容到此结束了,我们通过创建Web应用程序的几个重要步骤——创建项目、创建应用程序、创建网页——学习了如何使用Django创建Web应用程序。这也为更深入地学习Django打下了基础。