一、BBS项目
路由
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^register/', views.register, name='reg'),
url(r'^login/', views.login, name='login'),
url(r'^get_code/', views.get_code, name='gc'),
]
表结构设计准备
from django.db import models
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
phone = models.BigIntegerField(verbose_name='手机号', null=True)
avatar = models.FileField(upload_to='avatar', default='avatar/default.png', verbose_name='用户头像')
'''
给avatar字段文件对象,该文件自动存储到avatar文件下,然后该字段只会保存在
'''
create_time = models.DateField(auto_now_add=True)
blog = models.OneToOneField(to='Blog', null=True)
class Blog(models.Model):
site_name = models.CharField(verbose_name='站点名称', max_length=32)
site_title = models.CharField(verbose_name='站点标题', max_length=32)
site_theme = models.CharField(verbose_name='站点样式', max_length=64)
class Category(models.Model):
name = models.CharField(validators='文章分类', max_length=32)
blog = models.ForeignKey(to='Blog', null=True)
class Tag(models.Model):
name = models.CharField(verbose_name='文章标签', max_length=32)
blog = models.ForeignKey(to='Blog', null=True)
class Article(models.Model):
title = models.CharField(verbose_name='文章标题', max_length=64)
desc = models.CharField(verbose_name='文章简介', max_length=255)
content = models.TextField(verbose_name='文章内容')
create_time = models.DateField(auto_now_add=True)
up_num = models.BigIntegerField(verbose_name='点赞数', default=0)
down_num = models.BigIntegerField(verbose_name='点踩数', default=0)
comment_num = models.BigIntegerField(verbose_name='评论数', default=0)
blog = models.ForeignKey(to='Blog', null=True)
category = models.ForeignKey(to='Category', null=True)
tags = models.ManyToManyField(to='Tag',
through='Article2Tag',
through_fields=('article', 'tag')
)
class Article2Tag(models.Model):
article = models.ForeignKey(to='Article')
tag = models.ForeignKey(to='Tag')
class UpAndDown(models.Model):
user = models.ForeignKey(to='UserInfo')
article = models.ForeignKey(to='Article')
is_Up = models.BooleanField()
class Comment(models.Model):
user = models.ForeignKey(to='UserInfo')
article = models.ForeignKey(to='Article')
content = models.CharField(verbose_name='评论内容', max_length=255)
comment_time = models.DateTimeField(auto_now_add=True)
parent = models.ForeignKey(to='self', null=True)
二、注册功能
1.前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<script src="{% static 'js/jquery.min.js' %}"></script>
<link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet">
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
<script src="{% static 'layer/layer.js' %}"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">注册</h1>
<!-- 不用form表单提交,只是单纯的用一下而已 -->
<form id="myform">
{% csrf_token %}
{% for form in form_obj %}
<div class="form-group">
<label for="{{ form.auto_id }}">{{ form.label }}</label>
{{ form }}
<span style="color:red;" class="pull-right" ></span>
</div>
{% endfor %}
<div class="form-group">
<label for="myfile">头像
{% load static %}
<img src="{% static 'img/default.png' %}" id="myimg" width="80" alt=""
style="margin-left: 10px;">
</label>
<input type="file" id="myfile" name="avatar" style="display: none">
</div>
<input type="button" value="注册" id="id_commit" class="btn btn-primary pull-right">
</form>
</div>
</div>
</div>
<script>
$("#myfile").change(function () {
let myFileReaderObj = new FileReader();
let fileObj = $(this)[0].files[0];
myFileReaderObj.readAsDataURL(fileObj)
myFileReaderObj.onload = function () {
$("#myimg").attr('src', myFileReaderObj.result)
}
});
$("#id_commit").click(function () {
let formData = new FormData();
{#console.log($("#myform").serializeArray())
$.each($("#myform").serializeArray(), function (index, obj) {
{#console.log(index, obj)
formData.append(obj.name, obj.value);
});
formData.append('avatar', $("#myfile")[0].files[0]);
$.ajax({
url: '',
type: 'post',
data: formData,
contentType: false,
processData: false,
success: function (res) {
if (res.code === 200) {
window.location.href = res.url;
} else {
$.each(res.msg, function (index, obj) {
console.log(index, obj);
let targetId = '#id_' + index;
$(targetId).next().text(obj[0]).parent().addClass('has-error');
});
}
}
});
});
$("input").focus(function () {
$(this).next().text('').parent().removeClass('has-error');
});
</script>
</body>
</html>
2.后端
def register(request):
form_obj = MyRegForm()
if request.method == 'POST':
form_obj = MyRegForm(request.POST)
back_dict = {'code': 200, 'msg': '注册成功,3秒后自动跳转页面'}
if form_obj.is_valid():
print(form_obj.cleaned_data)
clean_data = form_obj.cleaned_data
clean_data.pop('confirm_password')
file_obj = request.FILES.get('avatar')
'''针对用户头像一定要判断是否传值,不能直接添加到字典中去'''
if file_obj:
clean_data['avatar'] = file_obj
models.UserInfo.objects.create_user(**clean_data)
back_dict['url'] = '/login/'
else:
back_dict['code'] = 2000
back_dict['msg'] = form_obj.errors
return JsonResponse(back_dict)
return render(request, 'register.html', locals())
三、登录功能之图片验证码推导操作
1.以登录–前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<script src="{% static 'js/jquery.min.js' %}"></script>
<link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet">
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
<script src="{% static 'layer/layer.js' %}"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">登录</h1>
<div class="form-group">
<label for="username">用户名</label>
<input type="text" name="username" id="username" class="form-control">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" name="password" id="password" class="form-control">
</div>
<div class="form-group">
<label for="username">验证码</label>
<div class="row">
<div class="col-md-6">
<input type="text" name="code" id="id_code" class="form-control">
</div>
<div class="col-md-6">
<img src="/get_code/" id="id_img" alt="" width="535" height="35">
</div>
</div>
</div>
<input type="button" value="登录" class="btn btn-success btn-block">
</div>
</div>
</div>
</body>
</html>
<script>
$("#id_img").click(function () {
let oldVal = $(this).attr('src');
$(this).attr('src', oldVal += '?')
});
</script>
2.python推导图片生成嘛
'''
图片相关模块
pip install pillow
Image: 生成图片
ImageDraw:能够在图片上乱涂乱画
ImageFont:控制字体样式
BytesIO:临时存储数据,返回的时候是二进制
StringIO:临时存储数据,返回的时候是字符串
'''
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO, StringIO
def get_random():
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
def get_code(request):
'''
图片的src格式:
图片的路径
url
二进制数据
:param request:
:return:
'''
with open(r'E:\python26\day66_BBS\avatar\7.jpg', 'rb') as f:
data = f.read()
return HttpResponse(data)
new(mode, size, color=0)
img_obj = Image.new('RGB', (535, 35), 'green')
img_obj = Image.new('RGB', (535, 35), get_random())
with open('xxx.png', 'wb') as wf:
img_obj.save(wf, 'png')
with open('xxx.png', 'rb') as rf:
data = rf.read()
return HttpResponse(data)
img_obj = Image.new('RGB', (535, 35), get_random())
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue())
img_obj = Image.new('RGB', (535, 35), get_random())
img_draw = ImageDraw.Draw(img_obj)
img_font = ImageFont.truetype('static/font/yun.ttf', 30)
code = ''
for i in range(5):
random_upper = chr(random.randint(65, 90))
random_lower = chr(random.randint(97, 122))
random_int = str(random.randint(0, 9))
tmp = random.choice([random_upper, random_lower, random_int])
'''
为什么一个个写而不是生成好了之后再写?
因为一个个写能够控制每个字体的间隙 而生成好之后在写的话,没法控制间隙
'''
img_draw.text((i * 45 + 60, 2), tmp, get_random(), img_font)
code += tmp
print('验证码:', code)
request.session['code'] = code
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue())
3.登录功能
def login(request):
if request.method == 'POST':
back_dict = {'code': 200, 'msg': '登录成功,3秒后自动跳转页面'}
username = request.POST.get('username')
password = request.POST.get('password')
code = request.POST.get('code')
if request.session.get('code').upper() == code.upper():
user_obj = auth.authenticate(request, username=username, password=password)
if user_obj:
auth.login(request, user_obj)
back_dict['url'] = '/home/'
else:
back_dict['code'] = 2000
back_dict['msg'] = '用户名或密码错误'
else:
back_dict['code'] = 3000
back_dict['msg'] = '验证码错误'
return JsonResponse(back_dict)
return render(request, 'login.html', locals())