Thursday, February 05, 2009

投票与评论












介绍


我们应用程序的主要目的是为用户提供方便的方法来查找和共享书签。实现这一功能的方法是允许用户想其他人推荐书签。由于我们的应用程序的主要除了欢迎消息之外什么都没有,我们将通过允许用户在主页上提交最爱书签的方式来实现书签共享的功能。之后我们将允许用户通过应用程序对他们喜欢的书签进行投票,之后我们会创建一个专门的页面显示投票最多的书签。这一系列的功能将提供一个显示所有用户感兴趣的书签的列表。在本章的第二部分,我们将实现允许用户对书签添加评论的功能,用户之间可以据此交换观点并将他们的讨论内容张贴在书签网站上。本章将展示很多有趣的功能,你还将学到一些新的Django提供的功能。


在本章中,你将学到一下内容:


  • 允许用户在主页上共享书签。
  • 允许用户对他们喜欢的书签进行投票。
  • 显示最近共享的和最流行的书签。
  • 允许用户对书签进行评论。


在主页上共享书签


目前为止,我们可以在应用程序中通过浏览标签页面和用户页面来查找书签。让我们为用户提供一个新的方法让用户共享和查找书签。当用户保存书签的时候我们将提供一个选项让用户可以在应用程序主页上共享这个书签。当一个书签被共享之后,如果愿意其他用户可以对这个共享的书签进行投票,我们还将创建一个页面用于显示投票最多的书签。这一功能对我们的应用程序来说非常重要,因为它将改变应用程序主页来显示最新共享的书签,在这里用户可以查找他们感兴趣的书签。


我们将分以下几步来实现这个功能:


  • 我们将创建一个数据模型来保存在主页上显示的书签信息,这个模型将保存被共享书签的部分内容。
  • 我们将修改保存书签的表单,以便让用户可以在主页上共享书签。
  • 我们还将修改应用程序主页,让他可以显示最近被共享的书签。每一个书签标题的旁边都有一个投票按钮。
  • 我们将创建一个视图函数,这个视图函数将接受投票请求并更新投票数。

为了实现这个功能我们需要作大量的工作,但这一切都是值得的,我们在这一过程中将学到很多新的知识,让我们开始吧。



被共享书签的数据模型


如果需要在主页上共享书签,我们需要在数据库中存储以下信息:


  • 书签共享的时间:我们需要利用这个信息来显示一段时间内最流行的书签。
  • 对这个书签的投票数。
  • 给这个书签投票的用户信息。保存这个信息是为了防止一个用户对同一书签多次投票。

为此,我们需要创建一个新的数据模型名为 SharedBookmark。打开bookmarks/models.py文件并加入如下类:



class SharedBookmark(models.Model):


bookmark = models.ForeignKey(Bookmark,unique=True)

date=models.DateTimeField(auto_now_add=True)

votes=models.IntegerField(default=1)

users_voted=models.ManyToManyField(User)

def __str__(self):


return '%s,%s' %
self.bookmark,self.votes

这个模型中使用了我们以前没接触过得功能,现在我来一一解释:


  • bookmark字段对应被共享的书签。因为我们不希望同一个书签被共享多次,所以这里我们把它设置为unique=True。
  • date
    字段的类型为models.DateTimeField,就像名字映射的那样,你可以在这个字段中存储日期/时间格式的内容。参数auto_now_add设置为True是告诉Django在第一次创建一条记录的时候给这个字段赋值为当前系统日期/时间。

  • votes的类型是models.IntegerField,这个字段存储整型数据,default=1是告诉Django在第一次创建一条记录的时候给它赋值为1。

  • users_voted定义了这个类与User对象之间的多对多关系,它会保存给这个书签投票的一个列表。

创建了这个模型类之后,执行下面的命令将数据模型同步到数据库中:


  • $ python manage.py syncdb

这样我们就可以将共享书签数据保存到数据库中,接下来我们实现在主页上共享书签的功能。



修改书签保存表单


我们将通过在书签保存表单页面上增加一个复选框的方式来提供书签共享功能。如果用户选择了这个复选框书签就会被共享到主页上。为了实现这个功能我们首先需要修改显示显示保存表单的类,打开bookmarks/forms.py文件修改BookmarkSaveForm类如下:



class BookmarkSaveForm(forms.Form):


url=forms.URLField(

label='URL',

widget=forms.TextInput(attrs={'size':64})

)

title=forms.CharField(

label='Title',

widget=forms.TextInput({attrs={'size':64}})

)

tags=forms.CharField(

label='Tags',

required=False,

widget=forms.TextInput({attrs={'size':64}})

)

share=forms.BooleanField(

label='Share on the main page',

required=False

)

我们在BookmarkSaveForm中使用了新的字段类型forms.BooleanField,这个字段的值可以是Ture或者False,它在页面中显示为复选框。


接下来我们来修改一下保存书签的方法,让它可以出来新增的复选框的行为,打开bookmarks/views.py文件在_save_bookmark方法中加入以下黑体字部分的代码:



def _bookmark_save(request,form):


# Create or get link

link,dummy=Link.objects.get_or_create(

url=form.cleaned_data['url']

)

# Create or get bookmark

bookmark,created=Bookmark.objects.get_or_create(

user=request.user,

link=link

)

# Update bookmark title

bookmark.title=form.cleaned_data['title']

# If bookmark is being updated,clean old tag list.

if not created:


bookmark.tag_set.clear()

# Create new tag list

tag_names=form.cleaned_data['tags'].split()

for tag_name in tag_names:


tag,dummy=Tag.objects.get_or_create(name=tag_name)

bookmark.tag_set.add(tag)

# Share on the main page if requested

if form.cleaned_data['share']:


shared_bookmark,created=SharedBookmark.objects.get_or_create(bookmark=bookmark)

if created:


shared_bookmark.users_voted.add(request.user)

shared_bookmark.save()

# Save bookmark to database and return it

bookmark.save()

return bookmark

这段代码的原理是这样的,如果“共享”复选框被选中了我们通过get_or_create方法来校验数据库中是否已经存在一个SharedBookmark对象,如果没有就创建一个。如果通过create_or_get方法创建了一个SharedBookmark对象,我们就把当前的用户加入到给这书签投票的用户列表中,然后保存这个SharedBookmark对象。如果这个复选框没有选中或者SharedBookmark对象已经存在,我们什么都不做。


这就是我们为了实现在主页上共享书签要编写的代码。也就是说,当用户在提交书签数据时,如果选择了共享复选框相应的SharedBookmark就会被创建并保存到数据库中,所以下一节我们要实现的功能是,将最近共享的书签显示在主页上并让用户可以对其投票。



浏览并对共享的书签进行投票


现在我们已经有了一个保存共享书签的数据模型。这样我们就可以方便的将最近共享的书签找出来并显示在主页上。首先修改bookmarks/views.py中的main_page函数,我们在这个函数中取出共享的书签并把它作为参数传给主页模板:



def main_page(request):


shared_bookmarks=SharedBookmark.objects.order_by('-date')[:10]

variables=RequestContext(request,{'shared_bookmarks',shared_bookmarks})

return
render_to_response('main_page.html',varibales)

新增的代码简洁明了,我们通过SharedBookmark.objects的order_by方法获得按日期降序排列的共享书签列表(注意其中的-date负号标记),然后通过Python的数组切片功能取出前十条记录。最后我们把得到的共享书签列表放入RequestContext中并把它作为参数传递给main_page.html模板。


接下来我们修改一下主页模板让它显示共享的书签列表。我们通常使用bookmark_list.html模板显示书签列表,不过我们现在要显示的是SharedBookmark对象而不是Bookmark对象。因此我们需要单独创建一个模板用于显示共享的书签列表。这个模板与bookmark_list.html稍有不同,比如页面中每个书签后会显示对这个书签的投票数。在模板文件夹下创建一个名为shared_bookmark_list.html的文件并输入下面的代码:



{% if shared_bookmarks %}

<ul class="bookmarks">


{% for shared_bookmark in shared_bookmarks%}

<li>

<a href="{{shared_bookmark.bookmark.link.url}}"
class="title">


{{shared_bookmark.bookmark.title|escape}}</a>

<br/>

Posted By:

<a href="/user/{{shared_bookmark.bookmark.user.username}}"
class="username">


{{shared_bookmark.bookmark.user.username}}</a>|

<span class="vote-count">Vote:


{{shared_bookmark.votes}}</span>

</li>

{%endfor%}

</ul>

{%else%}

<p>No bookmarks found</p>

{%endif%

这个模板和bookmark_list.html很类似,所以并不难理解。首先校验共享书签列表是否为空,如果不为空就迭代这个列表并在页面上输出每个书签的链接和其它信息,比如谁共享的这个书签,用户对书签的投票数。


创建了shared_bookmark_list.html文件后,我们需要把它包含在主页模板中。打开main_page.html模板并插入黑体字部分的代码:



{% extends "base.html" %}

{% block title %}Welcome to Django Bookmarks{% endblock %}

{% block head %}Welcome to Django Bookmarks{% endblock %}

{% block content %}

{% if user.username %}

<p>Welcome {{ user.username }}!

Here you can store and share bookmarks!</p>

{% else %}

<p>Welcome anonymous user!

You need to <a href="/login/">login</a>

before you can store and share bookmarks.</p>

{% endif %}

<h2>Bookmarks Shared by Users</h2>

{% include 'shared_bookmark_list.html' %}

{% endblock %}

现在启动开发服务器,通过书签表单共享一些书签,然后打开http://127.0.0.1:8000/链接,页面显示应该类似下面图示:

 


images/shared_bookmark.jpg

现在差不多了,主页面上已经可以显示被共享的书签了,但是书签的投票数总是显示为1,那是因为我们还没办法给一个书签投票。下面我们就开始实现这个功能。


现在我们创建一个视图函数来接收对共享书签的投票请求,并记录投票数量。你一定记得前面我们将创建数据模型的时候,Django会自动给数据模型加上一个ID属性。这个属性是一个唯一的整数,它用于唯一标识一个对象。这里我们会利用这个书签来标识投票数。


首先我们需要给投票视图函数加上一个URL入口,打开urls.py文件,并加入下面黑体字部分:


urlpatterns = patterns('', # Account management (r'^save/$',
bookmark_save_page), (r'^vote/$', bookmark_vote_page), )


现在你应该很容易就理解这个URL的含义,我们给链接^vote/$映射一个视图函数名为
bookmark_vote_page,接下来我们来实现这个函数。打开文件bookmarks/views.py并输入下面代码:



@login_required

def bookmark_vote_page(request):


if request.GET.has_key('id'):


try:


id=request.GET['id']

shared_bookmark=SharedBookmark.objects.get(id=id)

user_voted=shared_book.users_voted.filter(username=request.username)

if not user_voted:


shared_bookmark.votes+=1

shared_bookmark.users_voted.add(request.user)

shared_bookmark.save()

except ObjectDoesNotExist:


raise Http404('Bookmark not found')

if request.META.has_key('HTTP_REFERER'):


return
HttpResponseRedreict(request.META['HTTP_REFERER'])

return HttpResponseRedirect('/')

让我们一起来看看代码的执行逻辑:



@login_required

def bookmark_vote_page(request):


@login_required

def bookmark_vote_page(request):

我们通过login_required来修饰这个函数,因为只有登录用户可以对书签进行投票。



if request.GET.has_key('id'):


try:


id=request.GET['id']

shared_bookmark=SharedBookmark.objects.get(id=id)

然后代码会校验请求中是否包含'id'变量,如果有就通过它获得一个SharedBookmark对象



user_voted=shared_book.users_voted.filter(username=request.username)

接下来函数会校验当前用户是否已经给书签投票了,可以通过给shared_bookmark.users_voted的filter方法传递一个username参数获得。如果这个返回结果是空:



if not user_voted:


shared_bookmark.votes+=1

shared_bookmark.users_voted.add(request.user)

shared_bookmark.save()

如果这是用户第一次给这个书签投票我们就给shared_bookmark.votes加一。并在shared_bookmark.users_voted加入当前的用户对象并保存这个shared_bookmark对象。


如果无法通过id找到共享的书签对象我们就抛出一个Http404异常,并输出一个404未找到页面。



if request.META.has_key('HTTP_REFERER'):


    return
HttpResponseRedreict(request.META['HTTP_REFERER'])

return HttpResponseRedirect('/')
 最后,如果所有逻辑都正常执行,我们就将页面重定向到之前的位置。我们可以通过HTTP头中的HTTP_REFERER来实现。当你点击页面上的一个链接的时候你的浏览器会将包含这个链接的当前页面的URL发送给服务器,所以我们可以利用这个特性将用户从投票页面从定向到他最初的页面。这对我们后面将要实现的功能是非常有用的。
HTTP头信息存在于Django的视图 request.META中,因为某些浏览器并不发送 HTTP_REFERER给服务器,所以我们首先要确定它是否存在,如果不存在我们就重定向到主页面上。
现在投票页面已经完成了,我们只需要在主页面上加上它的链接就可以了。下面打开 shared_bookmark_list.html文件并加入下面代码中黑体字部分:
{% if shared_bookmarks %}
  <ul class="bookmarks">
    {% for shared_bookmark in shared_bookmarks %}
      <li>
        <a href="/vote/?id={{ shared_bookmark.id }}"
           class="vote">[+]</a>

        <a href="{{ shared_bookmark.bookmark.link.url }}"
           class="title">
          {{ shared_bookmark.bookmark.title|escape }}</a>
        <br />
        Posted By:
        <a href="/user/{{ shared_bookmark.bookmark.user.username }}/"
           class="username">
          {{ shared_bookmark.bookmark.user.username }}</a> |
        <span class="vote-count">Votes:  
              {{ shared_bookmark.votes }}</span>
      </li>
    {% endfor %}
  </ul>
{% else %}
  <p>No bookmarks found.</p>
{% endif %}
黑体字部分将投票链接加入到主页中并用一个[+]符号表示。这个链接的URL是/vote/?id=再加上书签的id。现在我们完成了书签投票功能,接下来刷新一下你的主页,你应该看到类似下面的页面:
现在如果你点一下旁边的投票链接,投票数可能会增加,当然如果你是这个书签的创建者,投票数是不会增加的。记住,如果你共享了一个书签默认会给这个书签投一票,所以不妨试试注册多个帐号然后分别给这些书签投票测试一下。
目前,主页上显示了最近被共享的十个书签,但是如果我们想根据投票数看看最受欢迎的书签呢,下一节将创建一个页面来满足这个需求。

最受欢迎书签页面

我们可以非常方便的实现类似主页面的最受欢迎书签页面。我们只要把过滤条件从日期改为投票数量就可以了。不过,为了显示最新的最受欢迎书签我们需要显示最近一天被投票最多的书签。
实现这个功能的第一步是创建一个视图。所以请打开bookmarks/views.py文件加入以下方法:
from datetime import datetime, timedelta
def popular_page(request):
  today = datetime.today()
  yesterday = today - timedelta(1)
  shared_bookmarks = SharedBookmark.objects.filter(
    date__gt=yesterday
  )
  shared_bookmarks = shared_bookmarks.order_by(
    '-votes'
  )[:10]
  variables = RequestContext(request, {
    'shared_bookmarks': shared_bookmarks
  })
  return render_to_response('popular_page.html', variables)
这个函数比 main_page函数要稍微复杂一点,需要注意的是代码中获得昨天时间并根据它查找书签列表的部分,让我们逐行分析这段代码:
from datetime import datetime, timedelta
def popular_page(request):
  today = datetime.today()
  yesterday = today - timedelta(1)
首先,从datatime模块中导入datetime和timedalta类,datetime模块是一个标准Python模块,它提供了大量操作时间和日期的对象,其中datetime对象用户维护日期和时间,timedelta对象用于处理两个时间之间的持续时长或者不同点。
在popular_page函数中我们使用datatime.today()方法来获得当天的时间,然后我们通过timedelta对象创建一个长度为1天的对象,再用它与当前时间相减得到昨天的日期:
shared_bookmarks = SharedBookmark.objects.filter(
    date__gt=yesterday
  )
  shared_bookmarks = shared_bookmarks.order_by(
    '-votes'
  )[:10]


在上面的代码中我们通过 SharedBookmark.objects的filter获得昨天到现在所有的贡献书签,我们通过给filter传递一个 date__gt=yesterday参数实现,其中__gt代表“大于”,这样我们就能够获得共享日期大于昨天的所有书签。

接下来我们调用书签列表的order_by方法获得按照投票数量逆序排列的列表。我们使用Python的数组分片技术获得列表的前十个记录:

  variables = RequestContext(request, {
    'shared_bookmarks': shared_bookmarks
  })
  return render_to_response('popular_page.html', variables)
 最后我们把列表对象shared_bookmarks传给模板popular_page.html来显示结果。
现在我们开始创建显示最受欢迎书签的页面模板popular_page.html,创建并打开这个文件输入下面的代码:
{% extends "base.html" %}
{% block title %}Popular Bookmarks{% endblock %}
{% block head %}Popular Bookmarks{% endblock %}
{% block content %}
  {% include 'shared_bookmark_list.html' %}
{% endblock %}
这个模板页面非常简单,它集成自base.html模板并重装其中的标题等信息,然后将hared_bookmark_list.html包含进来。
最后一步我们需要给这个新的视图定义URL,所以请打开 urls.py文件并输入下面黑体字部分:
urlpatterns = patterns('',
  # Browsing
  (r'^$', main_page),
  (r'^popular/$', popular_page),
  (r'^user/(\w+)/$', user_page),
  (r'^tag/([^\s]+)/$', tag_page),
  (r'^tag/$', tag_cloud_page),
  (r'^search/$', search_page),
)
好了现在我们完成了,打开浏览器输入地址 http://127.0.0.1:8000/popular/ 你会看到这个新增的页面,注意这里页面中是按照投票数量来排序的。如果你尝试给一个书签投票,之后你会返回这个页面。
现在我们可以把这个新增的功能加到主页面菜单上了,打开templates/base.html 文件并加入下面黑体字部分的代码:
[...]
  <div id="nav">
    <a href="/">home</a> |
    <a href="/popular/">popular</a> |
    {% if user.is_authenticated %}
      <a href="/save/">submit</a> |
      <a href="/search/">search</a> |
      <a href="/user/{{ user.username }}/">
        {{ user.username }}</a> |
      <a href="/logout/">logout</a>
    {% else %}
      <a href="/login/">login</a> |
      <a href="/register/">register</a>
    {% endif %}
  </div>
[...]
增加这个功能并不是很困难对吗?我们确实花了些时间实现它不过并不麻烦。现在我们站点的用户可以共享并对书签进行投票,而且他们可以浏览最新的最受欢迎的书签。下一节我们将增加更有意思的功能,让用户可以对书签进行评论。

给书签加上评论

给书签投票是用户表达他们对书签的看法的一种方式。如果能让用户直接对一个书签进行评论那就更好了,这是一个很好的方式,用户可以针对书签交流看法并结识新的朋友。这一节我们就实现这个功能。

实现给书签增加评论功能分以下几个步骤:

  • 激活评论应用程序功能并在数据库中创建它的数据模型。
  • 用一系列评论应用程序中提供的模板标签来显示评论表单和已增加的评论内容。
  • 创建增加评论的表达模板和增加评论成功后的显示页面模板。
Django实现这一功能是非常简单的,你一会儿就会看到。

激活评论应用程序

 

Django的评论应用程序位于 django.contrib.comments中,和打开其他Django中的应用程序一样,我们首先需要编辑 settings.py文件,然后把 'django.contrib.comments'加入到INSTALLED_APPS 变量中:
INSTALLED_APPS = (
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.sites',
  'django.contrib.comments',
  'django_bookmarks.bookmarks'
)

接下来执行下面的命令将评论应用程序的数据模型同步到数据库中:
$ python manage.py syncdb
接下来我们需要把评论应用程序的URL入口加入到url.py中,由于Django的评论应用程序包含很多函数,所以一个个的增加这些函数的入口显然是一种重复功能。Django为此提供了一个快捷方式。Django将评论应用程序的所有函数URL放在了一个单独的模块中 django.contrib.comments.urls.comments,我们可以通过使用include函数将它包含进来。打开 urls.py文件并加入下面黑体字部分:
urlpatterns = patterns('',
  # Comments
  (r'^comments/', include('django.contrib.comments.urls.comments')),
)
这和我们之前的用法有点不同,我们告诉Django所有的URL入口都在模块django.contrib.comments.urls.comments 中,现在把它包含进来,并且所有这些URL都映射到^comment/下面。这样做可以提高重用性,其他项目想使用评论应用程序的时候可以直接使用这个模块。
现在我们完成了要做的事,评论应用程序可以使用了。

为评论功能创建视图









由于我们准备让用户可以对共享的书签进行评论,我们需要一个单独的页面来显示对共享书签的评论。为此我们将创建一个新的视图函数,这个视图函数将通过URL获得共享书签的ID,并显示这个共享的书签和它的评论已经一个用于添加评论的表单。


我们从定义这个视图函数的URL入口开始,打开urls.py
文件并加入下面黑体字部分:


urlpatterns = patterns('',


# Browsing


(r'^$', main_page),


(r'^popular/$',
popular_page),


(r'^user/(\w+)/$',
user_page),


(r'^tag/([^\s]+)/$',
tag_page),









(r'^tag/$',
tag_cloud_page),


(r'^search/$', search_page),


(r'^bookmark/(\d+)/$',
bookmark_page),


)


这个新的URL看起来和用户页面的URL很类似,但是这里给bookmark_page函数传入的是\d而不是\w参数,如果你还记得前面章节的内容,你应该知道\w代表任意字符,所以你一定猜到了这里的\d代表任意的数字。这是因为bookmark_page函数需要一个书签的ID值,而ID值是一个数字型的字段。你也一定记得给一个正则表达式加上括号对于视图函数来说是一个附加的字符串参数。


现在让我们来编写bookmark_page函数,打开bookmarks/views.py加入下面的方法:


def bookmark_page(request,
bookmark_id):


shared_bookmark =
get_object_or_404(


SharedBookmark,


id=bookmark_id


)


variables =
RequestContext(request, {


'shared_bookmark':
shared_bookmark


})


return
render_to_response('bookmark_page.html', variables)




这个函数非常简单,它利用get_object_or_404方法来通过ID获得一个SharedBookmark对象。之后把这个对象传给模板bookmark_page.html。最后我们来创建bookmark_page函数的模板。在模板目录下创建一个bookmark_page.html文件并加入下面的代码:


{% extends "base.html"
%}


{% block title %}Bookmark:


{{
shared_bookmark.bookmark.title|escape }}{% endblock %}


{% block head %}


<a href="/vote/?id={{
shared_bookmark.id }}"


class="vote">[+]</a>


<a href="{{
shared_bookmark.bookmark.link.url }}"


class="title">


{{
shared_bookmark.bookmark.title|escape }}</a>


{% endblock %}


{% block content %}


Posted By:









<a
href="/user/{{ shared_bookmark.bookmark.user.username }}/"


class="username">


{{
shared_bookmark.bookmark.user.username }}</a> |


<span
class="vote-count">Votes: {{ shared_bookmark.votes
}}</span>


{% endblock %}


这断代码没什么特别之处,我们在页面的上部显示书签和投票连接,以及有关这个书签信息的内容放在也没的中部。


创建bookmark_page函数很简单,不过下一节会是一个很激动人心的部分,我们将在页面上加入一个书签的评论的列表和一个增加评论的表单。


显示评论信息和评论表单


你会吃惊的发现利用Django的评论模块,你可以非常简单给应用程序增加评论功能。基本上评论程序为你提供了3个模板标签,你可以将它们应用到你自己的模板中:


  • get_comment_count
    :返回当前页面的评论个数。


  • get_comment_list :
    返回当前页面评论的列表。


  • comment_form :
    显示一个用于添加评论的表单。



缺省情况下这些标签并不在模板中,为了使用它们你需要在模板的开头加入下面的语句:


{% load comments %}


load方法通常用于加载模板中附加的选项,这些选项不是缺省存在的。


我们上面提到的这些标签都接受下面的参数:


  • 评论内容的类型,你可以使用下这样的参数格式:application.model


  • 评论对象的ID



所以如果 你想获得一个共享书签的评论个数,将下面的代码加入bookmark_page.html中:


{% get_comment_count for
bookmarks.sharedbookmark


shared_bookmark.id as
comment_count %}


现在模板变量comment_count中保存的是当前共享书签的评论个数。


类似的你可以在bookmark_page.html中加入下面的代码来获得一个共享书签的评论列表:


{% get_comment_list for
bookmarks.sharedbookmark


shared_bookmark.id as
comment_list %}


现在 comment_list变量中保存的了当前共享书签的评论列表。这个列表中的每个评论对象包含以下属性:


  • user:这个user对象代表添加这个评论的用户。


  • submit_date:提交评论的日期。


  • Comment:评论信息的文本内容。


  • ip_address:添加这个评论的ip地址。



最后,如果你想在页面上增加一个用于提交评论的表单,在bookmark_page.html中输入下面的代码:


{% comment_form for
bookmarks.sharedbookmark shared_bookmark.id %}


现在是时候把它们组织到一起了,打开templates/bookmark_page.html并加入下面黑体字部分的内容:


{%
extends "base.html" %}


{%
load comments %}


{%
block title %}Bookmark:


{{
shared_bookmark.bookmark.title|escape }}{% endblock %}


{%
block head %}


<a
href="/vote/?id={{ shared_bookmark.id }}"


class="vote">[+]</a>


<a
href="{{ shared_bookmark.bookmark.link.url }}"
class="title">


{{
shared_bookmark.bookmark.title|escape }}</a>


{%
endblock %}


{%
block content %}


Posted
By:


<a
href="/user/{{ shared_bookmark.bookmark.user.username }}/"


class="username">


{{
shared_bookmark.bookmark.user.username }}</a> |


<span
class="vote-count">Votes: {{ shared_bookmark.votes
}}</span>


<h2>Comments</h2>


{% get_comment_count for
bookmarks.sharedbookmark


shared_bookmark.id as
comment_count %}


{% get_comment_list for
bookmarks.sharedbookmark


shared_bookmark.id as
comment_list %}


{% for comment in
comment_list %}


<div class="comment">


<p><b>{{
comment.user.username }}</b> said:</p>


{{
comment.comment|escape|urlizetrunc:40|linebreaks }}


</div>


{% endfor %}


<p>Number of
comments: {{ comment_count }}</p>


{% comment_form for
bookmarks.sharedbookmark


shared_bookmark.id %}


{%
endblock %}


上面的代码中利用刚才讲过的标签给共享书签增加了显示评论列表的功能和添加评论的表单。结合我们前面将的内容代码应该很好理解。除了下面这行需要额外解释一下:


{{
comment.comment|escape|urlizetrunc:40|linebreaks }}


你一定还记得这是用于模板过滤器的语法结构,这里我们使用了三个过滤器:


  • escape:我们使用这个过滤器来转换评论内容中的html代码,避免人们在输入了HTML代码后出现异常。


  • Urlizetrunc:这个过滤器将评论内容中的URL转换为可以点击的链接。如果URL的字符超过40个那么可显示的链接只显示40个。


  • Linebreaks:这个过滤器将评论中的换行标志转换为<p><br>标记。



我们差不多完成了评论功能,剩下的工作就是给评论表单定义模板,以及提交评论后显示的页面。我们还将作一些小的修改来改进评论的显示效果。


创建评论模板


评论功能需要增加两个模板,一个用于显示评论的表单另一个用于显示提交表单后的页面。这些模板被放在templates下的comments目录中,所以现在现创建这个目录。


我们从创建显示评论表单的模板开始,在templates/comments/下创建一个form.html文件,并加入下面的代码:


{% if user.is_authenticated %}


<form
action="/comments/post/" method="post">


<p><label>Post
a comment:</label><br />


<textarea name="comment"
rows="10"


cols="60"></textarea></p>


<input type="hidden"
name="options"


value="{{ options
}}" />


<input type="hidden"
name="target" value="{{ target }}" />


<input type="hidden"
name="gonzo" value="{{ hash }}" />


<input type="submit"
name="post" value="submit comment" />


</form>


{% else %}


<p>Please <a
href="/login/">log in</a> to post comments.</p>


{% endif %}


如果用户登录系统模板就显示一个提交评论的HTML表单,表单的action和其他字段的内容值的取决于Django
评论程序的定义,不要在意。


接下来我模创建一个成功提交评论后显示的页面模板。模板中有一个变量名为object,这个对象代表了刚刚提交的评论对象(在这里这个对象是SharedBookmark)。在这个页面上显示一个返回共享书签页是个好主意,所以我们在templates/comments/下创建一个posted.html文件,并加入下面的代码:


{% extends "base.html"
%}


{% block title %}Comment Posted
Successfully{% endblock %}


{% block head %}Comment Posted
Successfully{% endblock %}


{% block content %}


<p>Thank you for
contributing.</p>


{% if object %}


<p><a
href="/bookmark/{{ object.id }}/">


View your comment</a></p>


{% endif %}


{% endblock %}


现在我们完成了评论功能,在我们测试这个功能之前还需要给它加个链接,打开templates/shared_bookmark_list.html,修改并加入下面黑体字部分的代码:


{% if shared_bookmarks %}


<ul class="bookmarks">


{% for shared_bookmark in
shared_bookmarks %}


<li>


<a
href="/vote/?id={{ shared_bookmark.id }}"


class="vote">[+]</a>


<a href="{{
shared_bookmark.bookmark.link.url }}"


class="title">


{{
shared_bookmark.bookmark.title|escape }}</a>


<br />


Posted By:


<a href="/user/{{
shared_bookmark.bookmark.user.username }}/"


class="username">


{{
shared_bookmark.bookmark.user.username }}</a> |


<span
class="vote-count">Votes:


{{
shared_bookmark.votes }}</span> |


<a
href="/bookmark/{{ shared_bookmark.id}}/">Comments</a>


</li>


{% endfor %}


</ul>


{% else %}


<p>No bookmarks
found.</p>


{% endif %}


我们给评论功能也没加上一些修饰,打开site_media/style.css并加入下面的内容:


.comment {


margin: 1em;


padding: 5px;


border: 1px solid #000;


}


现在终于大功告成了,打开http://127.0.0.1:8000/测试一下,在共享书签后点击评论链接,你会看到类似下面的页面:










如果你试着提交评论你会看到一个提示成功提交的页面,看起来像下面这样:










点击"View your
comment"
你会看到你刚才提交的评论:










神奇的是实现这些功能之用了很少的代码,我们没费多大功夫就完成了评论功能。更重要的是你给书签应用程序增加了书签评论功能。


总结


本章我们为应用程序增加了两个重要的功能。首先是可以让人们对感兴趣的书签进行投票并浏览最受欢迎的书签。第二个功能是允许用户对书签进行评论。这意味着用户可以查找他们感兴趣的书签并和其他用户进行沟通,从而为我们的应用程序提供社交功能。本章我们学习了几个新的Django
功能和Django中的评论模块。


下一章我们将讨论一个新的话题。我们需要为应用程序提供一个管理控制台来维护你的数据模型。幸运的是Django为此提供了一套功能完善的接口。我们将在下一章学习有关知识。