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標誌和識別是否重複投票,多項選擇,勾選個數不能大於規定的數量。在後臺設置標題和圖片上傳,後臺設置可選數量。