Views, Templates, and Static Files
目前我们已经有一个名为 home
“Hello, World!”的视图。在我们应用程序的主页中。
myproject/urls.py
代码语言:javascript复制from django.conf.urls import url
from django.contrib import admin
from boards import views
urlpatterns = [
url(r'^$', views.home, name='home'),
url(r'^admin/', admin.site.urls),
]
boards/views.py
代码语言:javascript复制from django.http import HttpResponse
def home(request):
return HttpResponse('Hello, World!')
我们可以以此为起点。如果您还记得我们的线框图,图 5显示了主页应该是什么样子。我们想要做的是在表格中显示板列表以及其他一些信息。
首先要做的是导入boards models并列出所有现有的boards:
boards/views.py
代码语言:javascript复制from django.http import HttpResponse
from .models import Board
def home(request):
boards = Board.objects.all()
boards_names = list()
for board in boards:
boards_names.append(board.name)
response_html = '<br>'.join(boards_names)
return HttpResponse(response_html)
结果将是这个简单的 HTML 页面:
板主页 HttpResponse
但让我们就此打住。我们不会像这样渲染 HTML。对于这个简单的视图,我们只需要一个板列表;那么渲染部分是Django Template Engine 的工作 。
Django templates引擎设置
在board和mysite文件夹旁边创建一个名为templates 的新文件夹:
myproject/
|-- myproject/
| |-- boards/
| |-- myproject/
| |-- templates/ <-- here!
| -- manage.py
-- venv/
现在在templates 文件夹中,创建一个名为home.html 的 HTML 文件:
templates/home.html
代码语言:javascript复制<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Boards</title>
</head>
<body>
<h1>Boards</h1>
{% for board in boards %}
{{ board.name }} <br>
{% endfor %}
</body>
</html>
在上面的示例中,我们将原始 HTML 与一些特殊标签和 . 它们是 Django 模板语言的一部分。上面的例子展示了如何使用. 该呈现在HTML模板基板的名称,生成动态HTML文档。<span class="p">{</span><span class="err">%</span><span class="w"><span> </span></span><span class="err">for</span><span class="w"><span> </span></span><span class="err">...</span><span class="w"><span> </span></span><span class="err">in</span><span class="w"><span> </span></span><span class="err">...</span><span class="w"><span> </span></span><span class="err">%</span><span class="p">}</span>``<span class="p">{</span><span class="err">{</span><span class="w"><span> </span></span><span class="err">variable</span><span class="w"><span> </span></span><span class="p">}</span><span class="err">}</span>``for``<span class="p">{</span><span class="err">{</span><span class="w"><span> </span></span><span class="err">board.name</span><span class="w"><span> </span></span><span class="p">}</span><span class="err">}</span>
在我们可以使用这个 HTML 页面之前,我们必须告诉 Django 在哪里可以找到我们应用程序的模板。
打开settings.py 里面的myproject 目录和搜索 TEMPLATES
变量,并设置 DIRS
关键 os.path.join(BASE_DIR, 'templates')
:
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',
],
},
},
]
基本上,这一行的作用是找到项目目录的完整路径并在其后附加“/templates”。
我们可以使用 Python shell 调试它:
python manage.py shell
from django.conf import settings
settings.BASE_DIR
'/Users/vitorfs/Development/myproject'
import os
os.path.join(settings.BASE_DIR, 'templates')
'/Users/vitorfs/Development/myproject/templates'
看?它只是指向我们在前面步骤中创建的templates文件夹。
现在我们可以更新我们的home视图:
boards/views.py
代码语言:javascript复制from django.shortcuts import render
from .models import Board
def home(request):
boards = Board.objects.all()
return render(request, 'home.html', {'boards': boards})
The resulting HTML:
Boards Homepage render
We can improve the HTML template to use a table instead:
templates/home.html
代码语言:javascript复制<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Boards</title>
</head>
<body>
<h1>Boards</h1>
<table border="1">
<thead>
<tr>
<th>Board</th>
<th>Posts</th>
<th>Topics</th>
<th>Last Post</th>
</tr>
</thead>
<tbody>
{% for board in boards %}
<tr>
<td>
{{ board.name }}<br>
<small style="color: #888">{{ board.description }}</small>
</td>
<td>0</td>
<td>0</td>
<td></td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
Boards Homepage render
Testing the Homepage
Testing Comic
这将是一个反复出现的主题,我们将在整个教程系列中共同探索不同的概念和策略。
让我们编写我们的第一个测试。现在,我们将在board应用程序中的tests.py 文件中工作:
boards/tests.py
代码语言:javascript复制from django.core.urlresolvers import reverse
from django.test import TestCase
class HomeTests(TestCase):
def test_home_view_status_code(self):
url = reverse('home')
response = self.client.get(url)
self.assertEquals(response.status_code, 200)
这是一个非常简单的测试用例,但非常有用。我们正在测试响应的状态代码 。状态码 200 表示成功 。
我们可以在控制台查看响应的状态码:
响应 200
如果有未捕获的异常、语法错误或其他任何事情,Django 将返回状态代码500 ,这意味着Internal Server Error 。现在,假设我们的应用程序有 100 个视图。如果我们为所有视图编写这个简单的测试,只用一个命令,我们将能够测试所有视图是否都返回成功代码,因此用户不会在任何地方看到任何错误消息。如果没有自动化测试,我们将需要逐页检查。
执行 Django 的测试套件:
代码语言:javascript复制python manage.py test
代码语言:javascript复制Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.041s
OK
Destroying test database for alias 'default'...
现在我们可以测试 Django 是否为请求的 URL 返回了正确的视图函数。这也是一个有用的测试,因为随着开发的进行,您将看到urls.py 模块变得非常庞大和复杂。URL conf 都是关于解析正则表达式的。在某些情况下,我们有一个非常宽松的 URL,因此 Django 最终可能会返回错误的视图函数。
这是我们如何做到的:
boards/tests.py
代码语言:javascript复制from django.core.urlresolvers import reverse
from django.urls import resolve
from django.test import TestCase
from .views import home
class HomeTests(TestCase):
def test_home_view_status_code(self):
url = reverse('home')
response = self.client.get(url)
self.assertEquals(response.status_code, 200)
def test_home_url_resolves_home_view(self):
view = resolve('/')
self.assertEquals(view.func, home)
在第二个测试中,我们正在使用该 resolve
功能。Django 使用它来将请求的 URL 与urls.py 模块中列出的 URL 列表进行匹配。此测试将确保作为 /
根 URL 的 URL 返回主视图。
再测试一下:
代码语言:javascript复制python manage.py test
代码语言:javascript复制Creating test database for alias 'default'...
System check identified no issues (0 silenced).
..
----------------------------------------------------------------------
Ran 2 tests in 0.027s
OK
Destroying test database for alias 'default'...
要查看有关测试执行的更多详细信息,请将详细程度 设置为更高级别:
代码语言:javascript复制python manage.py test --verbosity=2
代码语言:javascript复制Creating test database for alias 'default' ('file:memorydb_default?mode=memory&cache=shared')...
Operations to perform:
Synchronize unmigrated apps: messages, staticfiles
Apply all migrations: admin, auth, boards, contenttypes, sessions
Synchronizing apps without migrations:
Creating tables...
Running deferred SQL...
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 boards.0001_initial... OK
Applying sessions.0001_initial... OK
System check identified no issues (0 silenced).
test_home_url_resolves_home_view (boards.tests.HomeTests) ... ok
test_home_view_status_code (boards.tests.HomeTests) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.017s
OK
Destroying test database for alias 'default' ('file:memorydb_default?mode=memory&cache=shared')...
Verbosity 确定将打印到控制台的通知和调试信息的数量;0 是无输出,1 是正常输出,2 是详细输出。
版权属于:Cyril
本文链接:https://cloud.tencent.com/developer/article/1858344
转载时须注明出处及本声明