Django项目之个人网站
Github地址:https://github.com/liangdongchang/MyWeb.git
感兴趣的可以fork或star一下
功能模块一:登录/注册
一、说明
功能:用户名、密码、验证码输入、头像上传
技术:文件上传、验证码、密码加密、会话技术
二、界面
1、登录
2、注册
三、代码
1、前端(T)
1.1 base.html
{# 父模板base.html#}
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{# 响应式web设计,自适应浏览器大小#}
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="save" content="history">
{% block title %}
<title>首页</title>
{% endblock %}
{% block link %}
{% endblock %}
<link href="{% static 'SitesApp/css/reset.css' %}" rel="stylesheet">
<link href="{% static 'SitesApp/css/sitesAppCss.css' %}" rel="stylesheet">
{# <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">#}
{# <script src="https://cdn.bootcss.com/jquery/1.12.0/jquery.min.js"></script>#}
{# <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>#}
<link href="/static/SitesApp/css/bootstrap.min.css" rel="stylesheet">
{% block style %}
{% endblock %}
<script src="/static/SitesApp/js/jquery.min.js"></script>
<script src="/static/SitesApp/js/bootstrap.min.js"></script>
{% block script %}
<script type="text/javascript"></script>
{% endblock %}
</head>
<body style="background-color: #E6E6FA;">
<a href="{% url 'sitesApp:vote' 1 %}">hhhhh</a>
<div class="box">
<div class="header">
<ul class="nav nav-pills navbar faq-tabbable">
<li role="presentation" class="active"><a href="{% url 'sitesApp:home' %}">首页</a></li>
<li role="presentation"><a href="{% url 'sitesApp:vote' 1 %}">投票</a></li>
<li role="presentation"><a href="{% url 'sitesApp:grade' %}">打分</a></li>
<li role="presentation"><a href="{% url 'sitesApp:review' %}">回顾</a></li>
<li role="presentation"><a href="{% url 'sitesApp:blog' %}">博客</a></li>
<li role="presentation"><a href="{% url 'sitesApp:dataBank' %}">资料</a></li>
<li role="presentation"><a href="{% url 'sitesApp:forum' %}">论坛</a></li>
<li role="presentation"><a href="{% url 'sitesApp:mine' %}">我的</a></li>
<li role="presentation"><a href="{% url 'sitesApp:login' %}">登录</a></li>
<li role="presentation"><a href="{% url 'sitesApp:register' %}">注册</a></li>
</ul>
</div>
<div class="time" >
<span id="mytime"></span>
</div>
<div class="content" style="position: relative;">
{% block content %}
这家伙很懒,还没开始开发...~_~
{% endblock %}
</div>
<div class="footer">
{% block footer %}
开发者 LDC
{% endblock %}
</div>
</div>
<script type="text/javascript">
$(function ($) {
{# 导航栏按钮渲染#}
$(".faq-tabbable").find("li").each(function () {
var a = $(this).find("a:first")[0];
if ($(a).attr("href") === location.pathname) {
$(this).addClass("active");
} else {
$(this).removeClass("active");
}
});
});
{#实时显示时间#}
function showTime(){
nowtime=new Date();
year=nowtime.getFullYear();
month=nowtime.getMonth()+1;
date=nowtime.getDate();
document.getElementById("mytime").innerText=year+"年"+month+"月"+date+" "+nowtime.toLocaleTimeString();
}
<!--定时刷新时间-->
setInterval("showTime()",1000);
</script>
</body>
</html>
1.2 login.html
{% extends 'SitesApp/base.html' %}
{% block title %}
<title>登录</title>
{% endblock %}
{% block content %}
{# 文件上传、验证码、密码加密、会话技术#}
<form id="formLogin" method="post" action="{% url 'sitesApp:login' %}"
onkeydown="if(event.keyCode==13) return focusNextInput(this);">
{% csrf_token %}
<div class="login">
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">用户名</span>
<input type="text" class="form-control" placeholder="Username" aria-describedby="basic-addon1"
name="uname" onkeyup="if(event.keyCode==13) focusNextInput(this);">
</div>
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">密 码</span>
<input type="password" class="form-control" placeholder="Password" aria-describedby="basic-addon1"
name="upwd" onkeyup="if(event.keyCode==13) focusNextInput(this);">
</div>
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">验证码</span>
<input type="text" class="form-control" placeholder="Auth code" aria-describedby="basic-addon1"
name="vcode" onkeyup="if(event.keyCode==13) focusNextInput(this);">
</div>
<div class="vcode">
<img src="/app/getvcode/" id="vcode">
</div>
<input id="submit" type="submit" class="loginBtn" value="登 录">
</div>
</form>
{% endblock %}
{% block script %}
<script src="/static/SitesApp/js/jquery-form.js"></script>
<script type="text/javascript">
$(function () {
{# 验证码点击时生成随机的路由请求#}
$('#vcode').click(function () {
$(this).attr('src', "/app/getvcode" + Math.random())
})
});
{# 表单提交后,处理服务器返回的数据#}
$(document).ready(function () {
$("#formLogin").ajaxForm(function (data) {
{# alert("post success." + data);#}
data = $.parseJSON(data);
if (data['status'] == '1') {
{# alert('登录成功');#}
{# 跳转到我的主页 #}
window.location.href = "{% url 'sitesApp:mine' %}";
} else {
alert(data['ret']);
}
});
});
//jQuery实现在一个输入框按回车键后光标跳到下一个输入框
function focusNextInput(thisInput) {
var inputs = document.getElementsByTagName("input");
for (var i = 0; i < inputs.length; i++) {
// 如果是最后一个,则焦点回到第一个
if (i == (inputs.length - 1)) {
inputs[0].focus();
break;
} else if (thisInput == inputs[i]) {
inputs[i + 1].focus();
break;
}
}
return false;
}
</script>
{% endblock %}
1.3 register.html
{% extends 'SitesApp/base.html' %}
{% block title %}
<title>注册</title>
{% endblock %}
{% block content %}
{# 文件上传、验证码、密码加密、会话技术#}
{# enctype="multipart/form-data" 上传支持 #}
<form id="formLogin" method="post" action="{% url 'sitesApp:register' %}" enctype="multipart/form-data">
{% csrf_token %}
<div class="login" style="height: 380px">
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">用户名</span>
<input type="text" class="form-control" placeholder="Username" aria-describedby="basic-addon1"
id="uname" name="uname" >
</div>
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">昵 称</span>
<input type="text" class="form-control" placeholder="Nickname" aria-describedby="basic-addon1"
id="unick" name="unick" >
</div>
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">密 码</span>
<input type="password" class="form-control" placeholder="Password" aria-describedby="basic-addon1"
id="upwd" name="upwd" >
</div>
<div class="input-group">
{# 用于上传头像的表单控件 #}
<span class="input-group-addon" id="basic-addon1">头 像</span>
<input type="file" class="form-control" aria-describedby="basic-addon1" style="height: 37px;"
id="uicon" name="uicon" onchange="check()">
</div>
<div class="input-group">
<span class="input-group-addon" id="basic-addon1">验证码</span>
<input type="text" class="form-control" placeholder="Auth code" aria-describedby="basic-addon1"
id="vcod" name="vcode" onchange="check()">
</div>
<div class="vcode" style="margin: 0;height: 65px;">
<img src="/app/getvcode/" id="vcode">
</div>
<input type="submit" class="loginBtn" value="注 册">
</div>
</form>
{% endblock %}
{% block script %}
<script src="/static/SitesApp/js/jquery-form.js"></script>
<script type="text/javascript">
{# 验证码点击事件 #}
$(function () {
$('#vcode').click(function () {
$(this).attr('src', "/app/getvcode" + Math.random())
});
});
{# 表单数据提交后对服务器返回的数据进行处理#}
$(document).ready(function () {
$("#formLogin").ajaxForm(function (data) {
{# alert("post success." + data['status']);#}
if (data['status'] == '1') {
alert('注册成功');
window.location.href = "{% url 'sitesApp:login' %}";
} else {
alert("注册失败,请检查输入信息!!!");
}
});
});
{# 检查上传的文件是否为图片#}
function check() {
var icon = document.getElementById("icon").value.toLowerCase().split('.');//以“.”分隔上传文件字符串
if (icon[icon.length - 1] == 'gif' || icon[icon.length - 1] == 'jpg' || icon[icon.length - 1] == 'bmp'
|| icon[icon.length - 1] == 'png' || icon[icon.length - 1] == 'jpeg')//判断图片格式
{
var imagSize = document.getElementById("icon").files[0].size;
{# alert("图片大小:" + imagSize + "B");#}
if (imagSize < 1024 * 1024 * 3) {
return true;
}
alert("图片大小在3M以内,您选中的图片大小为:" + (imagSize / (1024 * 1024)).toFixed(2) + "M");
}
else {
alert('请选择格式为*.jpg、*.gif、*.bmp、*.png、*.jpeg 的图片');
}
{# 文件选择错就把原文件清空#}
var obj = document.getElementById('icon');
obj.outerHTML = obj.outerHTML;
}
</script>
{% endblock %}
2 路由处理(V)
2.1 项目下的总路由
urlpatterns = [
url('^app/',include('SitesApp.urls',namespace='sitesApp'))
]
2.2 子应用下的路由
# 登录
url(r'^login/', views.login, name='login'),
# 注册
url(r'^register/', views.register, name='register'),
3、视图函数处理(Views)
3.1 登录
# 登录
def login(request):
if request.method == 'GET':
return render(request, 'SitesApp/login.html')
else:
# 预定义一个最终返回的Response对象(可以动态地为其配置内容,要想勒令客户端做事情必须要有一个Response对象)
resp = HttpResponse()
respData = {'status': '0', 'ret': '登录失败,输入信息有误!!!'}
# 获取用户输入的用户名、密码、验证码
uname = request.POST.get('uname', None)
upwd = request.POST.get('upwd', None)
vcode = request.POST.get('vcode', None)
# 校验验证码
# 从session中获取正确的验证码
sessVcode = request.session.get('vcode', None)
# 比较用户输入的验证码与正确的验证码是否匹配
# 事先全部转换为小写形式,这样用户可以忽略大小写
if vcode and sessVcode and vcode.lower() == sessVcode.lower():
# 对密码做消息摘要
upwd = useMd5(upwd)
# 查询名称为uname的用户
user = User.uManager.filter(uName=uname).first()
if not user:
respData = {'status': '0', 'ret': '用户不存在!!!'}
# 检查密码、验证码是否匹配
if user and upwd == user.uPwd :
# # 勒令客户端(通过cookie)自己将状态保存起来,过期时间为60秒
# resp.set_cookie('uname',uname,max_age=60*1)
# # 让服务端通过session保存用户状态
# 向客户端端要session其实是要存储在cookie中的sessionid
# request.session的言下之意是"request.getSessionBySessionid"
# request.session['uname'] = uname
# request.session['upwd'] = upwd
'''
token相当于手动实现的session
session将用户状态保存在django_session的表中
token将用户状态保存在何处完全取决于程序媛自己,例如:User表
但务必使保存用户状态的这张表中有用于作为[id/key/信物]的字段(该字段必须唯一),例如:utoken
和session一样,必须在客户端的cookie中存一个相同的[id/key/信物],例如:utoken
如何获取存储的用户状态:先从cookie中拿出utoken,进而查询User表中utoken为xxx的记录,就可以拿到uname了
'''
# 将用户状态保存在token中,让客户端持有一个token,将该token保存在某个表中
# 生成令牌/信物
token = str(uuid.uuid4())
# 将该令牌/信物存储在客户端的cookie中,过期时间一天
resp.set_cookie('utoken', token,expires=60*60*24)
# 将同样的信物存一份在服务端的表中
user.uToken = token
try:
user.save()
respData = {'status': '1', 'ret': 'login success!'}
except BaseException as e:
print(e)
respData = {'status': '0', 'ret': '登录失败,输入信息有误!!!'}
pass
resp.content = json.dumps(respData)
return resp
3.2 注册
# 注册
def register(request):
if request.method == 'GET':
return render(request, 'SitesApp/register.html')
else:
# 获取用户输入的用户名、昵称、密码、验证码、上传的头像
uname = request.POST.get('uname', None)
unick = request.POST.get('unick', None)
upwd = request.POST.get('upwd', None)
vcode = request.POST.get('vcode', None)
uip = getUserIP(request)
# 拿到用户上传的文件数据,类型是框架类InMemoryUploadedFile
uiconFile = request.FILES.get('uicon', None)
# <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
print(uname,unick, upwd, vcode, uiconFile, type(uiconFile))
# 手动存储上传的文件
# 自定义文件位置
# if uiconFile:
# fp = os.path.join(MEDIA_ROOT, 'x-' + uiconFile.name)
# # 写入文件
# with open(fp, 'wb') as file:
# # 逐"桶"读取上传的文件数据,并写入本地文件
# for buffer in uiconFile.chunks():
# file.write(buffer)
# 校验验证码
# 从session中获取正确的验证码
sessVcode = request.session.get('vcode', None)
# 比较用户输入的验证码与正确的验证码是否匹配
# 事先全部转换为小写形式,这样用户可以忽略大小写
if vcode and sessVcode and vcode.lower() == sessVcode.lower():
user = User()
user.uName = uname
user.uNickName = unick
user.uIP = uip
# 对密码做消息摘要(目的是避免明文存储)
user.uPwd = useMd5(upwd)
# 将上传过来的文件直接赋值给用户的ImageField字段uicon
# 框架会自动将图片存储在MEDIA_ROOT中
if uiconFile:
user.uIcon = uiconFile
# 把数据写进数据库
try:
user.save()
return JsonResponse({'status': 1, 'ret': 'register success!'})
except BaseException as e:
print(e)
return JsonResponse({'status':0,'ret':'输入信息有误!'})