第8章 美化网站:布局,样式及测试方法
8.1 如何在功能测试中测试布局和样式
如果执行Python manage.pu runserver 时,出现错误:“table lists_item has no column named list_id".需要执行python manage.py migrate ,更新本地数据库,让models.py中的改动生效。如果提醒IntegrityErrors,就删除数据库文件,然后重试。
functionl_tests/tests.py
class NewVisitorTest(LiveServerTestCase):
[...]
def test_layout_and_styling(self):
# 乔伊访问首页
self.browser.get(self.live_server_url)
self.browser.set_window_size(1024, 768)
# 她看到输入框完美地居中显示
inputbox = self.browser.find_element_by_id('id_new_item')
self.assertAlmostEqual(
inputbox.location['x'] + inputbox.size['width'] / 2,
512,
delta=10
)
AssertionError: 86.66666412353516 != 512 within 10 delta
改一下home.html让测试通过,然后再改回来
<p style="text-align: center">
<input type="text" id="id_new_item" placeholder="Enter a to-do item" name="item_text">
</p>
通过之后继续增加测试
# 她新建了一个清单,看到输入框仍完美地居中显示
inputbox.send_keys('testing')
inputbox.send_keys(Keys.ENTER)
self.wait_for_row_in_list_table('1: testing')
inputbox = self.browser.find_element_by_id('id_new_item')
self.assertAlmostEqual(
inputbox.location['x'] + inputbox.size['width'] / 2,
512,
delta=10
)
再次测试
AssertionError: 86.66666412353516 != 512 within 10 delta
8.2 使用CSS框架美化网站
下载bootstrap ,把它放在lists应用中一个新文件夹static里
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<title>Bootstrap 101 Template</title>
<!-- Bootstrap -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
<!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
<!--[if lt IE 9]>
<script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
<![endif]-->
</head>
<body>
<h1>你好,世界!</h1>
<!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
<script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
<!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
</body>
</html>
8.3 模板继承
lists/templates/base.html
<html>
<head>
<meta charset="UTF-8">
<title>To-Do lists</title>
</head>
<body>
<h1>{% block header_text %}{% endblock %}</h1>
<form method="POST" action="{% block form_action %}{% endblock %}">
{% csrf_token %}
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item" >
</form>
{% block table %}
{% endblock %}
</body>
</html>
基模板定义了多个block区域,其他模板可以在这些区域插入自己所需的内容。
home.html
{% extends 'base.html' %}
{% block header_text %}Start a new To-Do list{% endblock %}
{% block form_action %}/lists/new{% endblock %}
lists.html
{% extends 'base.html' %}
{% block header_text %}Your To-Do list{% endblock %}
{% block form_action %}/lists/{{ list.id }}/add_item{% endblock %}
{% block table %}
<table id="id_list_table">
{% for item in list.item_set.all %}
<tr><td>{{ forloop.counter }}: {{ item.text }}</td></tr>
{% endfor %}
</table>
{% endblock %}
功能测试:AssertionError: 86.66666412353516 != 512 within 10 delta
8.4 继承bootstrap
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>To-Do lists</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="text-center">
<h1>{% block header_text %}{% endblock %}</h1>
<form method="POST" action="{% block form_action %}{% endblock %}">
{% csrf_token %}
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item">
</form>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">
{% block table %}
{% endblock %}
</div>
</div>
</div>
</body>
</html>
AssertionError: 86.66666412353516 != 512 within 10 delta
8.5 django中的静态文件
settings.py
STATIC_URL = '/static/'
django自动查找static文件夹
修改base.html
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
运行服务器:python manage.py runserver
发现布局改变了,但是运行测试布局还是没有生效
使用一个新的测试类:
from django.test import LiveServerTestCase #删掉
from django.contrib.staticfiles.testing import StaticLiveServerTestCase #增加
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
from selenium.common.exceptions import WebDriverException
MAX_WAIT = 10
class NewVisitorTest(StaticLiveServerTestCase):
通过测试
8.6 使用bootstrap组件改进网站外观
超大文本块、大型输入框
base.html
<div class="col-md-6 col-md-offset-3 jumbotron">
<div class="text-center">
<h1>{% block header_text %}{% endblock %}</h1>
<form method="POST" action="{% block form_action %}{% endblock %}">
{% csrf_token %}
<input name="item_text" id="id_new_item" placeholder="Enter a to-do item" class="form-control input-lg">
样式化表格
lists.html
<table id="id_list_table" class="table">
8.7 使用自己编写的CSS
base.html
<title>To-Do lists</title>
<link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
<link rel="stylesheet" href="/static/base.css">
base.css
#id_new_item{
margin-top: 2ex;
}
git commit -m 'Use bootstrap to improve layout'
8.8 collectstatic命令和其他静态目录
项目同级创建static目录--不把此目录纳入版本控制
settings设置static_root
STATIC_URL = '/static/'
STATIC_ROOT = os.path.abspath(os.path.join(BASE_DIR,'../static'))
python manage.py collectstatic -- > 78 static files copied
INSTALLED_APPS = [
# 'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'lists',
]
rm -rf ../static/ 重新python manage.py collectstatic --> 17 static files copied to
总之将所有静态文件集中到一个文件夹
git commit -m 'set STATIC_ROOT in settings and disable admin'