1、概述
当我们在浏览网站时,经常会碰到如对一篇文章进行投票:喜欢、不喜欢还是弃票。投票也用表单提交实现,但与通常表单不同的是,投票提交的表单不需要进行相关的错误验证。
2、models.py层投票的数据结构
在之前篇章功能的基础上(即models层已有数据Video和用户UserProfile)如下:
class Video(models.Model):
title = models.CharField(null=True, blank=True, max_length=300)
content = models.TextField(null=True, blank=True)
url_image = models.URLField(null=True, blank=True)
cover = models.FileField(upload_to='cover_image', null=True)
editors_choice = models.BooleanField(default=False)
def __str__(self):
return self.title
class UserProfile(models.Model):
belong_to = models.OneToOneField(to=User, related_name='profile')
profile_image = models.FileField(upload_to='profile_image')
解析:以上数据项是实现网页内容和网页登录用户注册设定的。
因投票功能需要将票关联到用户和将票关联到投票对象,这这张票是谁投的,投给那个对象的。故在model层设计票数据项:
class Ticket(models.Model):
voter = models.ForeignKey(to=UserProfile, related_name='voter_ticket')
video = models.ForeignKey(to=Video, related_name='video_ticket')
VOTER_CHICES = (
('like','like'),
('dislike', 'dislike'),
('normal', 'normal'),
)
choice = models.CharField(choices=VOTER_CHICES, max_length=10)
def __str__(self):
return str(self.id)
解析:
a、字段voter是针对用户的外键,因用户和票是一对多关系,一个用户可以投票多个多项;
b、字段video是这对Video对象的外键,因一个对象可以投多张票,是一对多关系;
c、字段choice是用户的投票选择:喜欢like、不喜欢dislike和未投票normal。
3、投票的网页显示
1)在视图层views.py实现投票显示视图
def detail(request, id):
context = {}
vid_info = Video.objects.get(id=id)
voter_id = request.user.profile.id
like_counts = Ticket.objects.filter(choice='like',video_id=id).count()
try:
user_ticket_for_this_video = Ticket.objects.get(voter_id=voter_id, video_id=id)
context['user_ticket'] = user_ticket_for_this_video
except :
pass
context['vid_info'] = vid_info
return render(request, 'detail.html', context)
解析:通过request.user.profile.id来获取当前请求的用户,然后与当前请求对象id结合来获取得到当前的票user_ticket_for_this_video;
2)通过模板来加载变量
<div class="ui basic segment container">
<h1 class="ui header">{{ vid_info.title }}</h1>
<i class="icon grey unhide"></i>
<span style="color:#bbbbbb">10K</span>
<span class="" style="color:rgb(226, 226, 226)">|</span>
<i class="icon grey checkmark"></i>
<span style="color:#bbbbbb">{{ like_counts }} people got it</span> //#01
<p>
{{ vid_info.content }}
</p>
<div class="ui divider"></div>
<form class="ui form" action="" method="post">
{% csrf_token %}
{% if user_ticket.choice == 'like' %} //#02
<button class="ui red tiny button" type="submit" name="vote" value="normal">
<i class="icon checkmark"></i>
Get it!
</button>
<button class="ui tiny button" type="submit" name="vote" value="dislike">
<i class="icon bomb"></i>
Hmmm...
</button>
{% elif user_ticket.choice == 'dislike' %}
<button class="ui tiny button" type="submit" name="vote" value="like">
<i class="icon checkmark"></i>
Get it!
</button>
<button class="ui red tiny button" type="submit" name="vote" value="normal">
<i class="icon bomb"></i>
Hmmm...
</button>
{% else %}
<button class="ui tiny button" type="submit" name="vote" value="like">
<i class="icon checkmark"></i>
Get it!
</button>
<button class="ui tiny button" type="submit" name="vote" value="dislike">
<i class="icon bomb"></i>
Hmmm...
</button>
<button class="ui secondary circular tiny right floated pin icon button">
<i class="pin icon"></i>
Saved
</button>
{% endif %}
</form>
</div>
解析:
a、#01通过对Ticket数据进行过滤计算获取对当前对象的投票总数;
b、#02通过if判断当前登录用户对登录对象的状态判断,来显示投票状态,网页显示如下:
3、投票的结果存储功能
如上只是显示了在后台对Ticket进行操作后,网页中的投票状态的显示结果。下面将是直接在网页中进行投票,如用户点击投票则结果保存至数据库状态。
1)在views.py层添加投票视图
from django.core.exceptions import ObjectDoesNotExist
def detail_vote(request, id):
voter_id = request.user.profile.id
try:
user_ticket_for_this_video = Ticket.objects.get(voter_id=voter_id, video_id=id)
user_ticket_for_this_video.choice = request.POST['vote']
user_ticket_for_this_video.save()
except ObjectDoesNotExist:
new_ticket = Ticket(voter_id=voter_id, video_id=id, choice=request.POST['vote'])
new_ticket.save()
return redirect(to='detail', id=id)
解析:视图的逻辑是如果当前用户票已存在,则点击提交的状态进行修改保存;如果用户的票不存在,则根据提交结果新创建一张用户票。
2)在urls.py层增加投票视图
url(r'^detail/(?P<id>\d+)$', detail, name='detail'),
url(r'^detail/vote/(?P<id>\d+)$', detail_vote, name='vote'),
3)在模板层增加投票结果跳转
<form class="ui form" action="{% url 'vote' vid_info.id %}" method="post">
...
</form>
说明:action中内容即在点击投票结果的时候,会进行视图跳转。