表结构设计
from django.db import models
# Create your models here.
from django.contrib.auth.models import AbstractUser
'''
先写普通字段,再考虑外键字段
'''
# 用户表
class UserInfo(AbstractUser):
# 继承了Auth模块,下面是我们额外加的字段
phone = models.BigIntegerField(verbose_name='手机号', null=True)
"""
upload_to:指定图片上传的路径
default:默认图片
avatar:保存的默认图片文件夹
"""
avatar = models.FileField(upload_to='avatar/', default='avatar/default.png', verbose_name='用户头像')
# auto_now_add:自动添加当前时间
create_time = models.DateTimeField(auto_now_add=True, verbose_name='注册时间')
blog = models.OneToOneField(to='Blog', null=True, on_delete=models.CASCADE)
# 站点表
class Blog(models.Model):
site_name = models.CharField(verbose_name='站点名称', max_length=32)
site_title = models.CharField(verbose_name='站点标题', max_length=32)
# 存css/js的文件路径,简单模拟一下,认识样式内部原理的操作
site_theme = models.CharField(verbose_name='站点样式', max_length=64)
# 分类表
class Category(models.Model):
name = models.CharField(verbose_name='文章分类', max_length=64)
blog = models.ForeignKey(to='Blog', null=True, on_delete=models.CASCADE)
# 标签表
class Tag(models.Model):
name = models.CharField(verbose_name='文章标签', max_length=32)
blog = models.ForeignKey(to='Blog', null=True, on_delete=models.CASCADE)
# 文章表
class Article(models.Model):
title = models.CharField(verbose_name='文章标题', max_length=128)
desc = models.CharField(verbose_name='文章简介', max_length=255)
# 文章内容很多,一般情况下使用TextField
content = models.TextField(verbose_name='文章内容')
create_time = models.DateTimeField(verbose_name='创作时间', 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, on_delete='')
category = models.ForeignKey(to='Category', null=True, on_delete=models.CASCADE)
tags = models.ManyToManyField(
to='Tag',
through='Article2Tag',
through_fields=('article', 'tag')
)
# 文章标签表
class Article2Tag(models.Model):
article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
tag = models.ForeignKey(to='Tag', on_delete=models.CASCADE)
# 点赞点踩表
class UpAndDown(models.Model):
user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE)
article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
# 传布尔值 0或1
is_up = models.BooleanField()
# 评论表
class Comment(models.Model):
user = models.ForeignKey(to='UserInfo', on_delete=models.CASCADE)
article = models.ForeignKey(to='Article', on_delete=models.CASCADE)
content = models.CharField(verbose_name='评论内容', max_length=255)
comment_time = models.DateTimeField(verbose_name='评论时间', auto_now_add=True)
# 自关联
parent = models.ForeignKey(to='self', null=True, on_delete=models.CASCADE)
准备工作
# 新建Django项目,名字叫bbs1,项目名app01
# 创建在bbs1下创建static目录,同时把静态文件复制到改目录下
bootstrap #前端样式 https://v3.bootcss.com/
font # 该目录存放字体样式 文件名叫123.ttf,可以去ttf下载网址上随便找
img # 存放bbs注册用户时,默认的头像
default.png #手动添加一个给前端展示的默认头像图片
layer # 弹窗样式 https://layuiweb.com/index.htm
jquery.js
# 创建bbs1下avatar目录,存放用户注册上传的头像
default.png #手动添加一个数据库读取的默认头像图片
# Django版本使用的是2.x,修改下settings.py
TEMPLATES
'DIRS': [os.path.join(BASE_DIR,'templates')]
# 配置数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'bbs1',
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
'PASSWORD': '123456',
'CHARSET': 'utf-8',
}
}
# 配置静态文件目录
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
os.path.join(BASE_DIR, 'avatar')
]
# auto认证模块指定数据表
AUTH_USER_MODEL = 'app01.UserInfo'
# 创建数据库bbs1
# 将表结构的models执行数据库迁移命令
python3 manage.py makemigrations
python3 manage.py migrate
注册功能
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<script src="{% static 'jquery.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
<script src="{% static 'layer/layer.js' %}"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<h1 class="text-center">注册页面</h1>
<form action="">
<div class="form-group">
<label for="username">用户名:</label>
<input type="text" id="username" class="form-control">
</div>
<div class="form-group">
<label for="password">密码:</label>
<input type="password" id="password" class="form-control">
</div>
<div class="form-group">
<label for="re_password">确认密码:</label>
<input type="password" id="re_password" class="form-control">
</div>
<div class="form-group">
<label for="email">邮箱:</label>
<input type="text" id="email" class="form-control">
</div>
<div class="form-group">
<label for="myfile">上传头像:
<img src="{% static 'img/default.png' %}" id="myimg" alt="" width="100px">
</label>
<input type="file" id="myfile" style="display: none">
</div>
<input type="button" class="btn btn-block btn-primary commit" value="注册">
</form>
</div>
</div>
</div>
<script>
$("#myfile").change(function () {
// 使用js来实时显示头像图片
// 1.借助于文件阅读器
var myFileReadObj = new FileReader();
// 2.获取文件数据
var myfile = $(this)[0].files[0];
// 3.获取的文件交给文件阅读器
myFileReadObj.readAsDataURL(myfile); //注意:这里是异步提交
// 因为是异步提交,所以要执行onload,再给src重新设值
// 4.返回一个图片数据
myFileReadObj.onload = function () {
$("#myimg").attr('src', myFileReadObj.result);
}
});
$(".commit").click(function () {
// 获取前端输入的数据
var username = $("#username").val();
var password = $("#password").val();
var re_password = $("#re_password").val();
var email = $("#email").val();
var myfile = $("#myfile")[0].files[0];
// 参数的验证
if (!username) {
//提示
layer.msg('用户名必填');
return;
}
if (!password) {
//提示
layer.msg('密码必填');
return;
}
if (!re_password) {
//提示
layer.msg('确认密码');
return;
}
if (!email) {
//提示
layer.msg('邮箱必填');
return;
}
// 借助于formdata对象
var myFormDataObj = new FormData();
myFormDataObj.append('username', username);
myFormDataObj.append('password', password);
myFormDataObj.append('re_password', re_password);
myFormDataObj.append('email', email);
myFormDataObj.append('myfile', myfile);
myFormDataObj.append('csrfmiddlewaretoken', '{{ csrf_token }}');
// 发起Ajax请求,把前端输入的数据提交到后端
$.ajax({
url: '',
type: 'post',
data: myFormDataObj,
contentType: false,
processData: false,
success: function (res) {
if (res.code == 200) {
layer.msg(res.msg, {}, function () {
location.href = res.url;
});
} else {
layer.msg(res.msg);
}
}
})
});
</script>
</body>
</html>
urls.py
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
# 注册功能
path('register/', views.register, name='app01_register'),
# 登录功能
path('login/', views.login, name='app01_login'),
views.py
from django.shortcuts import render, reverse, HttpResponse
from django.http import JsonResponse
import hashlib
from django.conf import settings
from app01 import models
def get_md5_pwd(password):
m = hashlib.md5()
s = password + settings.SECRET_KEY
m.update(s.encode('utf-8'))
return m.hexdigest()
def register(request):
if request.method == 'POST':
# 1.先定义返回给前端的数据格式
back_dic = {'code': 200, 'msg': '注册成功'}
# 2.接收参数
username = request.POST.get('username')
password = request.POST.get('password')
re_password = request.POST.get('re_password')
email = request.POST.get('email')
myfile = request.FILES.get('myfile')
# 3.验证参数,后端必须验证,先验证错误,不合法的参数
if not username:
back_dic['code'] = 1001
back_dic['msg'] = '用户名必填'
return JsonResponse(back_dic)
if not password:
back_dic['code'] = 1002
back_dic['msg'] = '密码必填'
return JsonResponse(back_dic)
if re_password != password:
back_dic['code'] = 1003
back_dic['msg'] = '密码输入不一致'
return JsonResponse(back_dic)
if not email:
back_dic['code'] = 1004
back_dic['msg'] = '邮箱必填'
return JsonResponse(back_dic)
# 4.开始处理业务逻辑
# 密码加密
new_pwd = get_md5_pwd(password)
data_dic = {}
data_dic['username'] = username
data_dic['password'] = new_pwd
data_dic['email'] = email
# 判断是否上传头像
if myfile:
data_dic['avatar'] = myfile
models.UserInfo.objects.create(**data_dic)
# 5.返回前端数据
back_dic['url'] = reverse('app01_login')
return JsonResponse(back_dic)
return render(request, 'register.html')
验证注册
启动Django,浏览器输入 127.0.0.1:8000/register
注册成功,会自动跳转到login,如果遇到报错,自定义个登录函数即可
登录功能
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load static %}
<script src="{% static 'jquery.js' %}"></script>
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
<script src="{% static 'layer/layer.js' %}"></script>
</head>
<body>
<div class="container">
<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" id="username" class="form-control">
</div>
<div class="form-group">
<label for="password">密码:</label>
<input type="text" id="password" class="form-control">
</div>
<div class="form-group">
<label for="code">验证码:</label>
<div class="row">
<div class="col-md-6">
<input type="text" id="code" class="form-control">
</div>
<div class="col-md-6">
<img src="{% url 'app01_get_code' %}" alt="" id="img_code" style="width: 365px;height: 38px">
</div>
</div>
</div>
<input type="button" class="btn btn-success" value="登录">
</div>
</div>
</div>
<script>
$("#img_code").click(function () {
var old_src = $(this).attr('src');
$(this).attr('src', old_src += '?');
});
$(".btn").click(function () {
var username = $("#username").val();
var password = $("#password").val();
var code = $("#code").val();
// 2.参数验证
if (!username) {
layer.msg('用户名必须填')
}
if (!password) {
layer.msg('密码必须填')
}
if (!code) {
layer.msg('验证码必须填')
}
var obj = {username: username, password: password, code: code, csrfmiddlewaretoken: '{{ csrf_token }}'};
$.ajax({
url: '',
type: 'post',
data: obj,
success: function (res) {
if (res.code == 200) {
layer.msg(res.msg, {}, function () {
location.href = res.url;
})
} else {
layer.msg(res.msg)
}
}
})
})
</script>
</body>
</html>
urls.py
# 验证码
path('get_code/', views.get_code, name='app01_get_code'),
````# 首页
path('home/', views.home, name='app01_home'),
views.py
'''随机验证码'''
"""
图片相关模块
pip3 install pillow
"""
from PIL import Image, ImageDraw, ImageFont
"""
Image:生成图片
ImageDraw:能够在图片上乱涂乱画
ImageFont:控制字体样式
"""
from io import BytesIO, StringIO
"""
内存管理器模块
BytesIO:临时帮你存储数据,返回的时候数据是二进制
StringIO:临时帮你存储数据,返回的时候数据室字符串
"""
import random
def login(request):
if request.method == 'POST':
# 1.返回数据格式
back_dic = {'code': 200, 'msg': '登录成功'}
# 2.接收参数
username = request.POST.get('username')
password = request.POST.get('password')
code = request.POST.get('code')
# 3.验证参数
if not username:
back_dic['code'] = 1001
back_dic['msg'] = '用户名必填'
return JsonResponse(back_dic)
if not password:
back_dic['code'] = 1002
back_dic['msg'] = '密码必填'
return JsonResponse(back_dic)
if request.session.get('code').lower() != code.lower():
back_dic['code'] = 1005
back_dic['msg'] = '验证码不正确'
return JsonResponse(back_dic)
# 4.处理业务逻辑
new_pwd = get_md5_pwd(password)
user_obj = models.UserInfo.objects.filter(username=username, password=new_pwd).first()
if not user_obj:
back_dic['code'] = 1006
back_dic['msg'] = '用户名或密码错误'
return JsonResponse(back_dic)
# 登录成功,保存用户状态
request.session['username'] = user_obj.username
request.session['id'] = user_obj.pk
back_dic['url'] = reverse('app01_home')
return JsonResponse(back_dic)
return render(request, 'login.html')
def get_random():
return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)
def get_code(request):
# 最终步骤4:写图片验证码
img_obj = Image.new('RGB', (430, 35), get_random())
img_draw = ImageDraw.Draw(img_obj) # 产生一个画笔对象
img_font = ImageFont.truetype('static/font/123.ttf', 30) # 字体样式 大小
# 随机验证码 五位数的随机验证码 数字 小写字母 大写字母
code = ''
for i in range(6):
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_lower, random_upper, random_int])
# 将产生的随机字符串写入到图片上
"""
为什么一个个写而不是生成好了之后再写
因为一个个写能够控制每个字体的间隙 而生成好之后再写的话
间隙就没法控制了
"""
img_draw.text((i * 60 + 60, -2), tmp, get_random(), img_font)
# 拼接随机字符串
code += tmp
# 随机验证码在登陆的视图函数里面需要用到 要比对 所以要找地方存起来并且其他视图函数也能拿到
request.session['code'] = code
io_obj = BytesIO()
img_obj.save(io_obj, 'png')
return HttpResponse(io_obj.getvalue())
def home(request):
return HttpResponse('home页面')
验证登录
启动Django,浏览器输入 127.0.0.1:8000/login
注册成功,会自动跳转到,如果home首页,遇到报错,自定义个home函数即可
标签:code,登录,models,back,dic,注册,msg,password
From: https://www.cnblogs.com/ycmyay/p/17386198.html