N多年前,曾经用PHP为公司工会写了一个《工会换届选举投票系统》。那时候因为个人爱好,在自学PHP编程。有一天工会主席找我,希望使用网络投票方式选出新一届工会委员。我硬着头皮接下了任务,花了一个星期才完成。
3年前,EE委员会的老潘找我,希望我能帮忙做一个《三八节摄影作品》评比投票系统。因为工作忙的原因,就找到百度免费的《问卷调研》这个在线工具,总算是应付过去。
昨天,老潘又提起《摄影作品》在线投票评比的事,还是希望我能帮忙,本想这一次还是用百度的《问卷调研》这个工具,可是已经不能免费使用了,了解到至少要支付RMB 1000元,因为经费紧张,所以另想办法。
今天,放假,因为疫情,只能待在家里,于是决定自己写一个《摄影作品》投票系统给老潘。花了一个白天,构思、设计后台数据库,编写代码,测试。总算ok。
系统使用了django2.1.5, mysql5.7,
一、models.py
from django.db import models
# Create your models here.
class qtype(models.Model):
name=models.CharField(max_length=20)
def __str__(self):
return self.name
class question(models.Model):
qtext=models.CharField(max_length=200)
qtype=models.ForeignKey('qtype',to_field='id',on_delete=False)
largevote=models.IntegerField(default=5,verbose_name='最多可选')
def __str__(self):
return self.qtext
class choiceitem(models.Model):
ctext=models.CharField(max_length=40)
question=models.ForeignKey('question',to_field='id',on_delete=False)
image=models.ImageField(upload_to='vote',verbose_name='相片')
def __str__(self):
return self.ctext
class voterecord(models.Model):
email=models.EmailField(max_length=50)
choiceitem=models.ForeignKey('choiceitem',to_field='id', on_delete=False)
二、views.py
from django.shortcuts import render
from django.http import HttpResponse,HttpResponseRedirect
from vote.models import question,qtype,choiceitem,voterecord
from django.views.decorators.csrf import csrf_exempt
from random import shuffle
from django.contrib import messages
from django.utils.safestring import mark_safe
# Create your views here.
@csrf_exempt
def voteindex(request):
if request.method=='GET':
return render(request,'voteindex.html')
if request.method=='POST':
if len(request.POST.get('email'))<13:
messages.info(request,'邮件地址不正确!')
return HttpResponse("<br><br><h2><p align=center class=text-primary>邮件地址不正确,<a href='javascript:history.back(-1);'>返回上一页</a></p></h2>")
request.session['email']=request.POST.get('email')
print(request.session['email'])
return HttpResponseRedirect('./showquestion')
@csrf_exempt
def showquestion(request):
#判断是否投过票? session值判断
voted = request.session.get('voted')
if voted == 'voted':
return HttpResponse('<br><br><h2><p align=center class=text-primary>你已经投过票了!请勿重复投票!</p></h2>')
email = request.session.get('email',None)
if email==None or len(email)<13:
messages.info(request,'邮件地址不正确!')
return HttpResponseRedirect('/vote/')
if request.method=='GET':
lists=choiceitem.objects.filter(question_id=1).values('id','ctext','question__qtext','question__largevote','image')
ll=list(lists)
shuffle(ll)
return render(request,'showquestion.html',locals())
if request.method=='POST':
vote=request.POST.getlist('vote')
if len(vote)==0:
return HttpResponse('<br><br><h2><p align=center class=text-primary>投票不成功!勾选的作品数:' + str(
len(vote)) +"!请积极参与投票,<a href='javascript:history.back(-1);'>返回上一页</a></p></h2>")
largevote=request.POST.get('largevote')
email=request.session.get('email')
print(largevote)
print(vote)
#判断勾选的数量是否大与容许选择的数量
if len(vote) > int(largevote):
return HttpResponse('<br><br><h2><p align=center class=text-primary>投票不成功!勾选的作品数:'+str(len(vote))+',已经超过最大可选数:'+largevote+"!<a href='javascript:history.back(-1);'>返回上一页</a></p></h2>")
else:
#投票记录voterecord里是否有相同的邮件地址?
result=voterecord.objects.filter(email=email)
if result:
#有相同的邮件地址,提示已经投过票
return HttpResponse('<br><br><h2><p align=center class=text-primary>你已经投过票了!请勿重复投票!</p></h2>')
for l in vote:
voterecord.objects.create(email=email,choiceitem_id=int(l))
request.session['voted']='voted'
return HttpResponse('<br><br><h2><p align=center class=text-primary>投票成功!投票结果稍后公布。</a></p></h2>"')
三、模板
{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- 引入 Bootstrap -->
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
<!-- HTML5 Shiv 和 Respond.js 用于让 IE8 支持 HTML5元素和媒体查询 -->
<!-- 注意: 如果通过 file:// 引入 Respond.js 文件,则该文件无法起效果 -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
<![endif]-->
</head>
<body background="/static/media/vote/background.jpg" style="backgrounp-size:cover">
<script src="/static/jquery-2.1.4.js"></script>
<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<div class="page-header">
<h1>
<p class="text-primary b">优秀摄影作品评比投票 <small>罗湖办公室EE委员会</small></p>
</h1>
</div>
<div ><h4>{{ ll.0.question__qtext }}(多项选择,最多可以勾选{{ ll.0.question__largevote }}个作品!) </h4></div>
<form name="votefor" action="#" method="post">
{% csrf_token %}
<table class="table table-bordered">
<tbody>
{% if ll %}
<input type="text" name="largevote" value="{{ ll.0.question__largevote }}" hidden>
<tr >
{% for l in ll %}
<td nid="{{ l.id }}" align="center" style="vertical-align: bottom;">
<span style="vertical-align: middle">
<img src="{% static '/media/' %}{{ l.image}}" alt="picture" width="350" >
<p></p>
<ol class="list-unstyled">
<li>
</li>
<li>
<font color="blue"> {{ forloop.counter }}: [{{ l.ctext }}]</font>
</li>
<li>
<a class="btn primary" onclick="testajax(this);" href="#">查看大图</a>
<!--
<a onclick="testajax(this);" href="#" >放入购物车</a>
-->
</li>
<li>
投一票 : <input type="checkbox" name="vote" value="{{ l.id }}">
</li>
</ol>
</span>
</td>
{% if forloop.counter|divisibleby:"3"%}
</tr>
<tr>
{% endif %}
{% endfor %}
</tr>
{% endif %}
</tbody>
</table>
<input type="submit" value="提交"> <input type="reset" value="重置">
</form>
</div>
</div>
<br>
<p></p>
<hr/>
<div> <p align="center" class="text-primary">---本投票系统由xxx提供技术支持,欢迎使用--- </p></div>
</div>
</body>
</html>
四、以下是效果图
五、特点
图片的排序是随机的,杜绝重复投票--用session标志和识别是否重复投票,多项选择,勾选个数不能大于规定的数量。在后台设置标题和图片上传,后台设置可选数量。