Skip to the content.

基于Django构建Blog(08)-Templates


对于Templates的实现,可以使用Bootstrap中的资源(html/css/js),稍加修改即可。另外,这几个网站也提供了大量的优秀资源,关注一下:

DjangoTemplates是可以继承的,对于上一篇中创建的几个模板文件:home.html, archives.html, articles_of_tag.html, articles_of_category.html, article_detail.html来说,应该存在一个基础模板base.html,该模板中定义了隶属于本站的所有页面都应该具备的一般性内容,例如:导航部分,head,footer等,它是所有页面的框架,而articles_of_tag.html和articles_of_category.html的显示效果其实是与home.html完全一样的,home.html应该是它俩的父模板。

另外,根据Haystack的要求,搜索结果的展示,需要我们提供一个名叫search.html的模板,要放在templates/search目录下。我们这个搜索搜的是文章,搜索结果其实就是文章列表,很容易想到,这个search.html也应该像上面的几个模板一样,直接去继承home.html。但这里要注意的是,articles_of_tag.html和articles_of_category.html之所以能这么干,是因为他们三者所使用的与文章相关的变量名都是一样的,也就是说A模板继承了B模板的内容,A的View在给A传递数据的时候,用的这个变量B也认识,于是在渲染的时候,就把A中继承的B的内容给渲染出来了。所以说search.html直接继承home.html是没意义的,因为search.html的View是Haystack实现的,它传递数据用的变量名未必就是articles,而且变量的使用方法也可能不一样。

其实我们无非就是想复用一下home.html中展示文章信息的代码而已,可以把这块代码抽出来放到一个单独的模板文件article_info.html中,在search.html文件中include进来就行了。因为在include一个模板文件的时候是可以对被include的模板中的变量进行“赋值”的,这就解决了上面说的问题,变量名不同没问题,把值传递过去就OK了。

模板关系如下: Bootstrap提供的示例中,找一个与设计中的草图相近的,其实就有专门的Blog示例:

查看这个页面的源码,会发现里面引用了一些外部文件,有几个文件是在本地路径下的,需要把这些本地路径的文件下载到static/css或static/js目录中(.css文件放到css目录,.js文件放到js目录),另外,这个线上文件jquery.min.js也要下载下来。为方便起见,这里列出了所有需要下载的文件链接:

然后,修改这个示例的源码,作为base模板,base以及其它模板的代码如下:

base.html

{% load blog_extras %}
<!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">
	<meta name="description" content=""> 
	<meta name="author" content="">
	<title>xblog</title>
	{% block custom_styles %}
	{% endblock custom_styles %}
	<!-- Bootstrap core CSS -->
	<link href="/static/css/bootstrap.min.css" rel="stylesheet">
	<!-- Custom styles for this template -->
	<link href="/static/css/blog.css" rel="stylesheet">
	<!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
	<!--[if lt IE 9]>
	  <script src="/static/js/ie8-responsive-file-warning.js">
	  </script>
	<![endif]-->
	<script src="/static/js/ie-emulation-modes-warning.js">
	</script>
	<!-- 
	HTML5 shim and Respond.js for IE8 support 
	of HTML5 elements and media queries -->
	<!--[if lt IE 9]>
	  <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js">
	  </script>
	  <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js">
	  </script>
	<![endif]-->
 </head>
 <body>
	<div class="blog-masthead">
	  <div class="container">
		<nav class="blog-nav">
		  <a class="blog-nav-item 
			{% if column == 'home' %}active{% endif %}"
			href="{% url 'home' %}">Home
		  </a>
		  <a class="blog-nav-item 
			{% if column == 'archives' %}active{% endif %}"
			href="{% url 'archives' %}">Archives
		  </a>
		</nav>
	  </div>
	</div>
	<div class="container">
	  <div class="row">
		<div class="col-sm-8 blog-main">
		{% block main %}
		{% endblock main %}
		</div>
		<div class="col-sm-3 col-sm-offset-1 blog-sidebar">
		  <div class="sidebar-module">
			<h4>Search</h4>
			<form action="/search/" method="get">
			  <input type="text" name="q">
			  <input type="submit" value="GO!">
			</form>
		  </div>
		  <div class="sidebar-module">
			<h4>Tag</h4>
			{% GetTags %} 
		  </div>
		  <div class="sidebar-module">
			<h4>Category</h4>
			{% GetCategories %}
		  </div>
		</div>
	  </div>
	</div>
	<footer class="blog-footer">
	  <div class="row">
		<div class="col-lg-12">
		  <p>Copyright &copy; xblog 2014</p>
		</div>
	  </div>
	</footer>
	<!-- Bootstrap core JavaScript
	================================================== -->
	<!-- Placed at the end of the document so the pages load faster -->
	<script src="/static/js/jquery.min.js"></script>
	<script src="/static/js/bootstrap.min.js"></script>
	<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
	<script src="/static/js/ie10-viewport-bug-workaround.js"></script>
 </body>
</html>

该模板load了一个叫做blog_extras的模块,这个模块中注册了两个自定义的template tag:GetCategories和GetTags,有关blog_extras的详细说明在下一篇中给出。

home.html

{% extends "base.html" %}
{% load django_markdown %}
{% block main %}
{% for article in articles %}
 {% include "article_info.html" with article=article %}
{% endfor %}
{% include "articles_pagination.html" with is_query_result=False page=articles%}
{% endblock main %}

article_info.html

{% load django_markdown %}
{% if article.is_publish %}
<div class="blog-post">
 <h2 class="blog-post-title">
	<a href="{{ article.GetAbsoluteURL }}">
	  {{ article.title }}
	</a>
 </h2>
 <p class="blog-post-meta">
	{{ article.create_date | date:"Y/m/d" }}
	by {{ article.author }}
 </p>
 <p>
	{{ article.text | markdown | safe | truncatewords_html:20 }}
 </p>
 <p>
	<div class="readmore">
	  <a href="{{ article.GetAbsoluteURL }}">
		<span class="glyphicon glyphicon-plus">
		</span> more
	  </a>
	</div>
 </p>
 <p class="blog-post-meta">
	Category: {{ article.GetCategory }}<br>
	Tag:
	{% for tag in article.GetTags %}
	  {{ tag.name }}{% if not forloop.last %},{% endif %}
	{% endfor %}
 </p>
 <hr class="line">
</div>
{% endif %}

articles_pagination.html

<nav>
 <ul class="pagination">
	{% if page.has_other_pages %}
	<li>
	  {% if page.has_previous %}
	  <a href="?{% if is_query_result %}q={{ query }}&amp;{% endif %}page={{ page.previous_page_number }}"
		 aria-label="Previous">
		<span aria-hidden="true">&laquo;</span>
	  </a>
	  {% endif %}
	</li>
	{% for page_num in page.paginator.page_range %}
	  {% if page.number > 4 %}
		{% if page_num > page.number|add:"-4" %}
		  {% if page_num < page.number|add:"3" %}
			<li class="
			  {% if page_num == page.number %}
			  active{% endif %}">
			  <a href="?{% if is_query_result %}q={{ query }}&amp;{% endif %}page={{ page_num }}">
				{{ page_num }}<span class="sr-only">(current)</span>
			  </a>
			</li>
		  {% endif %}
		{% endif %}
	  {% elif page_num < 7 %}
	  <li class="{% if page_num == page.number %}active{% endif %}">
		<a href="?{% if is_query_result %}q={{ query }}&amp;{% endif %}page={{ page_num }}">
		  {{ page_num }}<span class="sr-only">(current)</span>
		</a>
	  </li>
	  {% endif %}
	{% endfor %}
	<li>
	  {% if page.has_next %}
	  <a href="?{% if is_query_result %}q={{ query }}&amp;{% endif %}page={{ page.next_page_number }}" aria-label="Next">
		<span aria-hidden="true">&raquo;</span>
	  </a>
	  {% endif %}
	</li>
	{% endif %}
 </ul>
</nav>  

这是对页码条的实现,这里的设定是:页码条最多显示6个页码,只有1页的话,不显示页码条

archives.html

{% extends "base.html" %}
{% block main %}
<div>
{% for year, articles in archives.items %}
	<h3>{{ year }}</h3>
	<ul>
	{% for article in articles %}
	<li>
	  <div>
		<h4>
		  <a href="{{ article.GetAbsoluteURL }}">
		  {{ article.title }}
		  </a>
		</h4>
	  </div>
	</li>
	{% endfor %}
	</ul>
{% endfor %}
</div>
{% endblock main %}

article_detail.html

{% extends "base.html" %}
{% load django_markdown django_markdown_static %}
{% block custom_styles %}
<link href="{% static 'django_markdown/preview.css' %}" rel="stylesheet">
{% endblock custom_styles %}

{% block main %}
<h2 class="blog-post-title">
{{ object.title }}
</h2>
{{ object.text | markdown }}

<!—
================= Disqus begin ================= -->

<div id="disqus_thread"></div>
<script type="text/javascript">

 /* * * CONFIGURATION VARIABLES * * */
 var disqus_shortname = 'xus123';

 /* * * DON'T EDIT BELOW THIS LINE * * */
 (function() {
	var dsq = document.createElement('script');
	  dsq.type = 'text/javascript'; dsq.async = true;
	dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
	(document.getElementsByTagName('head')[0]
	  || document.getElementsByTagName('body')[0]).appendChild(dsq);
 })();
</script>
<noscript>
 Please enable JavaScript to view the
 <a href="https://disqus.com/?ref_noscript" rel="nofollow">
	comments powered by Disqus.
 </a>
</noscript>

<!—
================= Disqus end ================= -->
{% endblock main %}

评论功能借助于第三方评论托管平台Disqus来实现,Disqus begin和end之间的代码是按照Disqus的使用说明添加的,详细内容可到官网查看。需要注意的是 var disqus_shortname = ‘xus123’ 中的xus123是我的Disqus账号,现实当中需要替换为你自己的Disqus账号,其他地方不需要修改。

除了Disqus,同类的服务平台还有:JiaThis灯鹭等,使用方法类似。

articles_of_tag.html

{% extends "home.html" %}

articles_of_category.html

{% extends "home.html" %}  

search.html

{% extends "home.html" %}
{% block main %}
{% if query %}
 {% for result in page.object_list %}
	{% include "article_info.html" with article=result.object %}
	{% empty %}<p>No results found !</p>
 {% endfor %}
 {% include "articles_pagination.html" with is_query_result=True %}
{% else %}
<p>No search query given !</p>
{% endif %}
{% endblock main %}

有关Haystack的使用,详见搜索中的介绍。



Prev-基于Django构建Blog(07)-Views
Next-基于Django构建Blog(09)-Templates续