BBS登录与注册功能的总结

一、表设计:表名 外键字段

表名 models.py

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.jpg',verbose_name='用户头像')

register_time = models.DateTimeField(verbose_name='注册时间',auto_now_add=True)

site = models.OneToOneField(to='Site',on_delete=models.CASCADE,null=True)

class Site(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=32,null=True)

class Article(models.Model):

"""文章表"""

title = models.CharField(verbose_name='文章标题',max_length=32)

desc = models.CharField(verbose_name='文章简介',max_length=255)

content = models.TextField(verbose_name='文章内容')

create_time = models.DateTimeField(verbose_name='创建时间',auto_now_add=True)

# 三个优化字段

comment_num = models.IntegerField(verbose_name='评论数',default=0)

up_num = models.IntegerField(verbose_name='点赞数',default=0)

down_num = models.IntegerField(verbose_name='点踩数',default=0)

# 外键表

site = models.ForeignKey(to='Site',on_delete=models.CASCADE,null=True)

category = models.ForeignKey(to='Category',on_delete=models.CASCADE,null=True)

tags = models.ManyToManyField(to='Tag',through='Article2Tag',through_fields=('article', 'tag'),

null=True)

class Category(models.Model):

"""文章分类表"""

name = models.CharField(verbose_name='分类名称',max_length=32)

site = models.ForeignKey(to='Site', on_delete=models.CASCADE, null=True)

class Tag(models.Model):

"""文章标签表"""

name = models.CharField(verbose_name='标签名称',max_length=32)

site = models.ForeignKey(to='Site', on_delete=models.CASCADE, null=True)

class Article2Tag(models.Model):

"""多对多外键表"""

article = models.ForeignKey(to='Article',on_delete=models.CASCADE,null=True)

tag = models.ForeignKey(to='Tag',on_delete=models.CASCADE,null=True)

class UpAndDown(models.Model):

"""文章点赞点踩表"""

user = models.ForeignKey(to='UserInfo',on_delete=models.CASCADE,null=True)

article = models.ForeignKey(to='Article',on_delete=models.CASCADE,null=True)

is_up = models.BooleanField(verbose_name='点赞点踩数')

class Comment(models.Model):

"""文章评论表"""

user = models.ForeignKey(to='UserInfo',on_delete=models.CASCADE,null=True)

article = models.ForeignKey(to='Article',on_delete=models.CASCADE,null=True)

content = models.TextField(verbose_name='评论内容')

comment_time = models.DateTimeField(auto_now_add=True,verbose_name='评论时间')

parent = models.ForeignKey(to='self',on_delete=models.CASCADE,null=True) # 自关联字段

url.py

from django.contrib import admin
from django.urls import path
from app import views

urlpatterns = [

path('admin/', admin.site.urls),

path('register/',views.register_func,name='register_view'),

# 用户登录功能

path('login/',views.login_func,name='login_view'),

# 图片验证码

path('get_code/',views.get_code_func)

]

views.py

from django.shortcuts import render,HttpResponse,redirect
from app import myforms
from app import models
from django.http import JsonResponse
from django.contrib import auth

def register_func(request):

# 前后端ajax交互,通常采用字段作为交互对象

back_dict = {'code':10000,'msg':''}

# 1.先产生一个空的form_obj

form_obj = myforms.RegisterForm()

if request.method == 'POST':

form_obj = myforms.RegisterForm(request.POST)

if form_obj.is_valid():

clean_data = form_obj.cleaned_data # 存储符合校验的数据

# 将confirm_password键值对移除

clean_data.pop('confirm_password')

# 获取用户上传的头像文件

avatar_obj = request.FILES.get('avatar') # 用户有可能没有上传

if avatar_obj:

clean_data['avatar'] = avatar_obj

# 创建用户数据

models.UserInfo.objects.create_user(**clean_data)

back_dict['msg'] = '注册成功'

back_dict['url'] = '/login/'

else:

back_dict['code'] = 10001

back_dict['msg'] = form_obj.errors

return JsonResponse(back_dict)

return render(request,'registerPage.html',locals())

def login_func(request):

back_dict = {'code': 10000, 'msg': ''}

if request.method == 'POST':

username = request.POST.get('username')

password = request.POST.get('password')

code = request.POST.get('code')

if code.upper() == request.session.get('code').upper():

user_obj = auth.authenticate(request, username=username, password=password)

if user_obj:

# 保存用户登录状态

auth.login(request, user_obj) # 执行之后就可以使用request.user获取登录用户对象

back_dict['msg'] = '登录成功'

back_dict['url'] = '/home/'

else:

back_dict['code'] = 10001

back_dict['msg'] = '用户名或密码'

else:

back_dict['code'] = 10002

back_dict['msg'] = '验证码错误'

return JsonResponse(back_dict)

return render(request, 'loginPage.html')

from PIL import Image,ImageFont,ImageDraw

from io import BytesIO,StringIO

"""

BytesIO 在内存中临时存储 读取的时候以bytes格式为准

StringIO 在内存中临时存储 读取的时候以字符串格式为准

"""

import random

def get_random():

return random.randint(0,255),random.randint(0,255),random.randint(0,255)

def get_code_func(request):

# 产生图片对象

img_obj = Image.new('RGB',(350,35),get_random())

# 将图片交给画笔对象

draw_obj = ImageDraw.Draw(img_obj)

# 确定字体的样式

font_obj = ImageFont.truetype('static/font/111.ttf',35)

# 产生随机验证码

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(1,9))

# 三选一

temp_choice = random.choice([random_upper,random_lower,random_int])

# 写到图片上

draw_obj.text((i * 60 + 45,0),temp_choice,font=font_obj)

code += temp_choice

# 后端保存验证码

request.session['code'] = code

io_obj = BytesIO()

img_obj.save(io_obj,'png')

return HttpResponse(io_obj.getvalue())

loginPage.html

Title

{% load static %}

用户登录

{% csrf_token %}

用户名

密码

验证码

{% load static %}

用户注册

{% csrf_token %}
{% for form in form_obj %}

{{ form.label }}
{{ form }}

{% endfor %}

头像

            </div>
<input type="button" id="subBtn" class="btn btn-primary btn-block" value="注册">
</form>
</div>
</div>
myforms.py

from django import forms
from app import models

class RegisterForm(forms.Form):

"""用户注册form类"""

username = forms.CharField(min_length=3,max_length=8,label='用户名',

error_messages={

'min_length':'用户名最短三位',

'max_length':'用户名最长八位',

'required':'用户名不能为空',

},

widget=forms.widgets.TextInput(attrs={'class':'form-control'})

)

password = forms.CharField(min_length=3, max_length=8, label='密码',

error_messages={

'min_length': '密码最短三位',

'max_length': '密码最长八位',

'required': '密码不能为空',

},

widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})

)

confirm_password = forms.CharField(min_length=3, max_length=8, label='确认密码',

error_messages={

'min_length': '密码最短三位',

'max_length': '密码最长八位',

'required': '密码不能为空',

},

widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})

)

email = forms.EmailField(label='邮箱',

error_messages={

'required': '邮箱不能为空',

'invalid': '邮箱格式不正确'

},

widget=forms.widgets.EmailInput(attrs={'class': 'form-control'})

)

# 局部钩子校验用户名是否已经存在
def clean_username(self):
username = self.cleaned_data.get('username')
res = models.UserInfo.objects.filter(username=username)
if res:
self.add_error('username','用户名已存在')
return username # 全局钩子校验两次密码是否一致
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not password == confirm_password:
self.add_error('confirm_password','两次密码不一致')
return self.cleaned_data

重点代码的记忆

 # 局部钩子校验用户名是否已经存在
def clean_username(self):
username = self.cleaned_data.get('username')
res = models.UserInfo.objects.filter(username=username)
if res:
self.add_error('username','用户名已存在')
return username # 全局钩子校验两次密码是否一致
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not password == confirm_password:
self.add_error('confirm_password','两次密码不一致')
return self.cleaned_data
def register_func(request):
# 前后端ajax交互 通常采用字段作为交互对象
back_dict = {'code': 10000, 'msg': ''}
# 1.先产生一个空的form_obj
form_obj = myforms.RegisterForm()
if request.method == "POST":
form_obj = myforms.RegisterForm(request.POST) # username password confirm_password email csrfmiddlewaretoken
if form_obj.is_valid():
clean_data = form_obj.cleaned_data # 存储符合校验的数据 {username password confirm_password email}
# 将confirm_password键值对移除
clean_data.pop('confirm_password') # {username password email}
# 获取用户上传的头像文件
avatar_obj = request.FILES.get('avatar') # 用户有可能没有上传
if avatar_obj:
clean_data['avatar'] = avatar_obj # {username password email avatar }
# 创建用户数据
models.UserInfo.objects.create_user(**clean_data) # 上述处理字典的目的就是为了创建数据省事
back_dict['msg'] = '注册成功'
back_dict['url'] = '/login/'
else:
back_dict['code'] = 10001
back_dict['msg'] = form_obj.errors
return JsonResponse(back_dict)
return render(request, 'registerPage.html', locals())

登录注册关键代码比较
# 登录框的编写
<div class="container">
<div class="col-md-8 col-md-offset-2">
<h2 class="text-center">用户登录</h2>
{% csrf_token %}
<div class="form-group">
<label for="name">用户名</label>
<input type="text" id="name" class="form-control" name="username">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" id="password" class="form-control" name="password">
</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" name="code">
</div>
<div class="col-md-6">
<img src="/get_code/" alt="" width="350" height="35" id="d1">
</div>
</div>
</div>
<input type="button" class="btn btn-success btn-block" value="登录" id="loginBtn">
</div>
</div>
# 登录按钮发送ajax请求
$('#loginBtn').click(function () {
// 可以再次使用form标签序列化功能 也可以自己挨个获取
$.ajax({
url:'',
type:'post',
data:{'username':$('#name').val(),'password':$('#password').val(), 'code':$('#code').val(),'csrfmiddlewaretoken':'{{ csrf_token }}'},
success:function (args) {
if (args.code === 10000){
window.location.href = args.url
}else {
swal(args.msg,'Here have a error')
} }
})
})
# 注册框的编写
<div class="container">
<div class="col-md-8 col-md-offset-2">
<h2 class="text-center">用户注册</h2>
<form id="form">
{% csrf_token %}
{% for form in form_obj %}
<div class="form-group">
<label for="{{ form.auto_id }}">{{ form.label }}</label> <!--form.auto_id自动获取渲染的标签id值-->
{{ form }}
<span style="color: darkred" class="pull-right"></span>
</div>
{% endfor %}
<!--用户头像相关-->
<div class="form-group">
<label for="myfile">头像
<img src="/static/img/default.jpg" alt="" width="120" id="myimg">
</label>
<input type="file" id="myfile" style="display: none"> </div>
<input type="button" id="subBtn" class="btn btn-primary btn-block" value="注册">
</form>
</div>
</div>
# 1.用户头像的实时展示
$('#myfile').change(function () {
//1.产生一个文件阅读器
let myFileReaderObj = new FileReader();
//2.获取用户上传的头像文件
let fileObj = this.files[0];
// 3.将文件对象交给阅读器对象读取
myFileReaderObj.readAsDataURL(fileObj);
// 等待文件阅读器对象加载完毕之后再修改src
myFileReaderObj.onload = function () {
// 4.修改img标签的src属性展示图片
$('#myimg').attr('src', myFileReaderObj.result)
}
})
#  2.给注册的按钮绑定点击事件
$('#subBtn').click(function () {
//1.先产生一个内置对象
let myFormDataObj = new FormData();
//2.添加普通数据
$.each($('#form').serializeArray(),function (index,dataObj) { // 对结果for循环 然后交给后面的函数处理
myFormDataObj.append(dataObj.name,dataObj.value)
})
//3.添加文件数据
myFormDataObj.append('avatar',$('#myfile')[0].files[0])
//4.发送ajax请求
$.ajax({
url:'',
type:'post',
data:myFormDataObj,
contentType:false,
processData: false,
success:function (args) {
if (args.code === 10000){
window.location.href = args.url
}else {
let dataObj = args.msg;
// 针对性的渲染提示
$.each(dataObj,function (k,msgArray) {
//拼接标签的id值
let eleId = '#id_' + k
// 根据id查找标签 修改下面span标签的内容 并给父标签添加错误样式
$(eleId).next().text(msgArray[0]).parent().addClass('has-error')
})
}
}
})
})
# 3.给所有的input标签绑定获取焦点事件 移除错误样式
$('input').focus(function () {
$(this).next().text('').parent().removeClass('has-error') })

效果图



BBS登录与注册功能的总结的更多相关文章

  1. BBS登录与注册功能

    登录功能 视图函数 def my_login(request): if request.method == 'GET': return render(request, 'login.html') el ...

  2. AndroidStudio制作登录和注册功能的实现,界面的布局介绍

    前言 大家好,给大家带来AndroidStudio制作登录和注册功能的实现,界面的布局介绍的概述,希望你们喜欢 每日一句: Success is connecting with the world a ...

  3. VS连接SQL Server 2008,并实现登录和注册功能

    --------------------- 作者:Cambridge 来源:CSDN 原文:https://blog.csdn.net/cambridgeacm/article/details/797 ...

  4. 基于struts2和hibernate的登录和注册功能——完整实例

    1.该项目使用MySQL数据库,数据库名为test,表名info,如图所示: 2.配置web.xml(Struts2使用) <?xml version="1.0" encod ...

  5. 用java集合模拟登录和注册功能

    package com.linkage.login; import java.util.HashMap;import java.util.Iterator;import java.util.Map;i ...

  6. 用java数组模拟登录和注册功能

    package com.linkage.login; import java.util.Scanner; public class user { // 存储用户名和密码 public static S ...

  7. JavaWeb 实现简单登录、注册功能

    1.首先创建一个简单的动态Javaweb项目 2.然后手动建立文件目录: 项目创建好之后,在src下建几个包: controller:控制器,负责转发请求,对请求进行处理,主要存放servlet: d ...

  8. Unity uGUI 登录及注册功能

    上次我们已经完成了登录界面的模拟功能,今天咱们把上次没做完的继续完善下!那么废话少说直接开始吧! PS:本次完善的功能有: 1,增加对数据库的操作. 2,使用了MD5Key值加密 3,完善登录和组测功 ...

  9. 利用PHP实现登录与注册功能以及使用PHP读取mysql数据库——以表格形式显示数据

    登录界面 <body><form action="login1.php" method="post"><div>用户名:&l ...

随机推荐

  1. 沁恒CH32V003F4P6 开发板上手报告和Win10环境配置

    CH32V003 沁恒最近推出的低价CH32V003系列, 基于青稞RISC-V2A内核, 48MHz主频, 2KB SRAM, 16KB Flash, 工作电压兼容3.3V和5V. 主要参数如下 S ...

  2. .NET API 接口数据传输加密最佳实践

    .NET API 接口数据传输加密最佳实践 我们在做 Api 接口时,相信一定会有接触到要给传输的请求 body 的内容进行加密传输.其目的就是为了防止一些敏感的内容直接被 UI 层查看或篡改. 其实 ...

  3. 驱动开发:内核封装WSK网络通信接口

    本章LyShark将带大家学习如何在内核中使用标准的Socket套接字通信接口,我们都知道Windows应用层下可直接调用WinSocket来实现网络通信,但在内核模式下应用层API接口无法使用,内核 ...

  4. ES6 学习笔记(一)let、const与作用域

    一.let命令 1.1用法 1.1.1 let类似于var,但所声明的变量只在let命令所在的代码块有效. 如: { let a = 10 var b = 20 } console.log(b) co ...

  5. The Google File System 翻译和理解

    The Google File System 摘要 GFS 是一个可扩展的分布式文件系统,用于大型分布式数据密集型应用上.它可以运行在便宜的普通硬件上,提供了高性能和一定的容错性. 1. 分布式文件系 ...

  6. 编码工具使用(go语言)

    1.课程介绍 Git基础课程和实操 Goland介绍以及常用快捷键使用 Go delve 调试 你想要的linux 这里都有 2.版本控制工具介绍 原始的版本控制 修改文件,保存文件副本 版本控制的起 ...

  7. Referenced file contains errors (http://mybatis.org/dtd/mybatis-3-config.dtd). For more information, right click on the message in the Problems View and select "Show Details..."

    mybatis配置文件报错Referenced file contains errors mybatis的配置文件报错 The errors below were detected when vali ...

  8. vscode+springboot+gradle

    vscode+springboot+gradle 项目搭建 demo 目标:项目中抛弃所有xml格式文件 啰嗦: 一直在用maven作为项目的依赖包管理,最近看到基于Java17 的 Spring f ...

  9. 前端工程化与webpack的介绍

    前端工程化 概念:在企业级的前端项目开发中,把前端开发所需的工具.技术.流程.经验等进行规范化.标准化. 模块化 js的模块化,css的模块化,资源的模块化 组件化 复用现有的UI结构,样式,行为 规 ...

  10. 【每日一题】【遍历orSet】2022年2月1日-NC66 两个链表的第一个公共结点

    描述输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空.(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的) 输入描述:输入分为是3段,第 ...