表设计
表分析
先确认表的数量 再确认表的基础字段 最后确认表的外键字段
1.用户表(基于auth模块设计扩展,手机号,头像,注册时间)
from django.contrib.auth.models import AbstractUser
class UserInfo(AbstractUser):
phone = models.BinaryField(null=True, verbose_name='手机号')
avatar=models.FileField(upload_to='avatar/',
default='avatar/default.jpg', verbose_name='用户头像')
register_time = models.DateTimeField
(auto_now_add=True, verbose_name='注册时间')
site = models.OneToOneField(to='Site', on_delete=models.CASCADE, null=True)
# 外键字段 关联个人站点 一对一关系
setting文件中配置:AUTH_USER_MODEL = 'app01.UserInfo'
2.个人站点表(每个用户都有单独的博客站点)
from django.db import models
class Site(models.Model):
name = models.CharField(max_length=32)
# 站点名称
title = models.CharField(max_length=32)
# 站点标题
theme = models.CharField(max_length=32, null=True)
# 模拟站点的css文件
3.文章表(重点)
title = models.CharField(max_length=32)
# 文章标题
desc = models.CharField(max_length=255)
# 文章简介
content = models.TextField
# 文章内容
create_time = models.DateTimeField(auto_now_add=True)
# 发布时间
"""优化字段"""
comment_num = models.IntegerField(verbose_name='评论数', default=0)
# 文章评论数,在用户评论时 在这里字段也对应加1 这样就不用跨表查询提高效率
up_num = models.IntegerField(verbose_name='点赞数', default=0)
# 文章评论数,在用户评论时 在这里字段也对应加1 这样就不用跨表查询提高效率
down_num = models.IntegerField(verbose_name='反对数', default=0)
# 文章评论数,在用户评论时 在这里字段也对应加1 这样就不用跨表查询提高效率
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='ArticleAndTag',
through_fields=('article', 'tag'), null=True)
# 外键字段 文章标签表 一个文章可以有多个标签 一个标签也可以有多个文章
# 这里选择的是半自动创建 指定了关联的表和表字段
'''
数据库字段优化设计:我们想统计文章的评论数 点赞数
通过文章数据跨表查询到文章评论表中对应的数据统计即可
但是文章需要频繁的展示 每次都跨表查询的话效率极低
所以我们在文章表中再创建三个普通字段
之后只需要确保每次操作评论表或者点赞点踩表时同步修改上述三个普通字段即可
减少了跨表查询
'''
4.文章分类表
class Category(models.Model):
name = models.CharField(max_length=22)
# 设置分类的名称
site = models.ForeignKey(to='Site',on_delete=models.CASCADE,null=True)
# 分类名称 对应生效的个人站点
文章 和 标签的多对多表
class ArticleAndTag(models.Model):
article = models.ForeignKey(to='Article', on_delete=models.CASCADE, null=True)
# 文章外键
tag = models.ForeignKey(to='Tag', on_delete=models.CASCADE, null=True)
# 标签外键
5.文章标签表
class Tag(models.Model):
name = models.CharField(max_length=32)
site = models.ForeignKey(to='Site',on_delete=models.CASCADE,null=True)
# 标签也是对应生效的个人站点 因为每个人的标签都不一样
6.文章点赞点踩表
class Up_and_Down(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='1是点赞还是0是反对')
# 记录用户对这篇文章的操作
7.文章评论表
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.CharField(max_length=255)
# 评论的内容
create_time = models.DateTimeField(auto_now_add=True)
# 评论的时间
parent = models.ForeignKey(to='self',on_delete=models.CASCADE,null=True)
"""to=self 自关联 """
# 如果有子评论 需要记录 例如 评论了id为1 的评论
"""
id user_id article_id content parent_id
1 1 1 哈哈哈 null
2 2 1 哈你妹 1
3 3 1 讲文明 2
"""
# 哈你妹就是回复的 id为1的评论
注册功能
1.创建一个forms组件 因为是前后端一体的项目,在django中推荐使用
创建一个forms的py文件 用来存储编写的forms类
from django import forms
from app01 import models
class Register(forms.Form):
username = forms.CharField(min_length=5, max_length=18, label='用户名',
error_messages={'min_length': '用户名不能低于5位',
'max_length': '用户名不能高于18位',
'required': '用户名不能为空'},
widget=forms.widgets.TextInput(attrs={'class':'form-control'}))
# 给forms标签添加样式
password = forms.CharField(min_length=5, max_length=18, label='密码',
error_messages={ 'min_length': '密码不能低于5位',
'max_length': '密码不能高于18位',
'required': '密码不能为空'},
widget=forms.widgets.PasswordInput(attrs={'class':'form-control'}))
password1 = forms.CharField(min_length=5, max_length=18, label='确认密码',
error_messages={
'min_length': '密码不能低于5位',
'max_length': '密码不能高于18位',
'required': '密码不能为空'},
widget=forms.widgets.PasswordInput(attrs={'class':'form-control'}))
email = forms.EmailField(error_messages={ 'required': '邮箱不能为空'},
widget=forms.TextInput(attrs={'class':'form-control'}),
# 给forms标签添加样式
label='邮箱')
def clean(self):
username = self.cleaned_data.get('username')
user_obj = models.UserInfo.objects.filter(username=username)
if user_obj:
self.add_error('username', '用户名已存在')
if not self.cleaned_data.get('password') == self.cleaned_data.get('password1'):
self.add_error('password1', '两次密码不一致')
return self.cleaned_data
# 设置一个全局钩子函数,判断用户名是否存在,判断两次密码是否输入一致
2.导入forms类到视图函数 传递forms类至html文件渲染标签
from app01.myforms import Register
def register_func(request):
back_dict = {'code':10000,'msg':''}
# 设置一个空字典,用于返回给前端 前端用来展示数据
register_obj = Register()
# 生成一个空的forms组件对象 传入前端渲染标签
if request.method == 'POST':
register_obj = Register(request.POST)
if register_obj.is_valid():
# 判断数据是否全部符合forms类的规则
clean_data = register_obj.cleaned_data
# 储存已通过校验的数据 这是一个字典 里面包含了所有forms类字段的数据
clean_data.pop('password1')
# 移除创建账户时不需要的数据
avatar_obj = request.FILES.get('avatar')
# 获取用户上传头像的文件
if avatar_obj:
# 判断用户是否有上传头像,因为上传头像选填
clean_data['avatar'] = avatar_obj
# 如果用户有上传,就把用户上传头像的文件添加入刚创建的forms数据中 以便稍等储存
# 如果用户没有上传 则不添加头像数据 数据库也有默认的头像
UserInfo.objects.create_user(**clean_data)
# 创建用户对象,利用**打散字段 成为 username = xxxx,password = xxx的形式
# UserInfo表中录入数据
back_dict['msg'] = '注册成功'
# 给前端返回的字典添加数据,
back_dict['url'] = '/login/'
# 给前端返回的字典添加数据,
else:
back_dict['msg'] = register_obj.errors
# 给前端返回的字典添加数据,这里是不通过时 返回的错误信息
back_dict['code'] = 10001
# 错误时的id号 前端可以通过此id号判断正常还是异常
return JsonResponse(back_dict)
# 把字典返回给前端
return render(request, 'registerPage.html', locals())
3.前端页面接收数据反馈数据信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
<!--设置页面小标题-->
<meta name='keywords' content="查询关键字,可以填写多个">
<meta name="description" content="网页简介">
{% load static %}
<!--动态加载配置文件-->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
<link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.css' %}">
<!--动态加载配置文件-->
</head>
<body>
<div class="row">
<div class="col-md-4 col-md-offset-4" style="margin-top: 100px">
<!--设定一块区域,距离顶部100px-->
<h2 class="text-center">注册</h2>
<form id="form">
{% csrf_token %}
<!--在form标签内添加 csrf_token 验证-->
{% for foo in register_obj %}
<!--对于后端返回的forms类for循环展示渲染标签-->
<div class="form-group">
<label for="{{ foo.auto_id }}">{{ foo.label }}</label>
<!--绑定标签id,展示标签别名-->
{{ foo }}
<!--渲染输入标签-->
<span style="color: #f15050;font-size: 13px"></span>
<!--错误提示标签-->
</div>
{% endfor %}
<div class="form-group">
<p><label for="myfile">头像</label></p>
<label for="myfile">
<img src="/static/img/001.png" alt="" width="100" id="myimg">
<!--设置一个待用户上传头像图标,并且绑定选择区域 绑定ID为myfile的上传
文件标签,-->
</label>
<p style="margin-top: 10px"><span style="color: #999999;font-size: 12px">
点击头像上传</span></p>
<input type="file" id="myfile" style="display: none">
<!--设置一个接收文件标签,用来接收用户上传的头像文件,并把这个标签隐藏,
因为头像图标继承了他,所以点击头像图标也是触发这个标签-->
</div>
<input type="button" id="subBtn" class="btn btn-success btn-block" value="注册">
<!--设置一个空的标签,后面会通过绑定ajax事件传递数据-->
</form>
</div>
</div>
</body>
</html>
<script>
<!--给头像图标绑定一个变化事件,只要头像图标有变化就会执行,上传头像实时展示-->
$('#myfile').change(function () {
let myFileReaderobj = new FileReader();
<!--1.产生一个文件阅读器对象-->
let fileObj = this.files[0];
<!--获取用户上传的头像文件-->
myFileReaderobj.readAsDataURL(fileObj);
<!--将头像文件交给文件阅读器对象读取-->
myFileReaderobj.onload = function () {
<!--.onload 是等待文件阅读器对象读取完成后在进行的意思-->
$('#myimg').attr('src', myFileReaderobj.result)
<!--给头像图标标签更换图片,修改图片标签的src属性-->
}})
<!--这样就完成了一个头像实时展示的功能-->
<!--给按钮标签绑定单击事件,发送ajax请求,并携带文件数据-->
$('#subBtn').click(function () {
let myFormData = new FormData();
<!--1.先产生一个内置对象,空的数据对象-->
$.each($('#form').serializeArray(), function (index, data) {
<!--2.for循环获取#form标签内的所有普通字段数据-->
myFormData.append(data.name, data.value)})
<!--3.for循环添加所有普通字段数据 到 数据对象中-->
myFormData.append('avatar', $('#myfile')[0].files[0])
<!--4.最后获取form标签内文件数据,也添加到数据对象中-->
$.ajax({
<!--5.发送ajax请求-->
url: '',
type: 'post',
data: myFormData,
<!--6.把刚刚携带所有数据的数据对象发送出去-->
contentType: false,
<!--固定格式,携带文件数据都需要-->
processData: false,
<!--固定格式,携带文件数据都需要-->
success: function (args) {
<!--接收后端返回数据-->
<!--ajax请求后端返回一个字典,这个字典就是args接收了-->
if (args.code === 10000) {
<!--通过后端返回的id号码判断是否注册成功-->
alert('注册成功')
window.location.href = args.url
} else {
let data_obj = args.msg;
<!--接收后端字典返回的错误信息-->
$.each(data_obj, function (k, v) {
<!--for循环 拿到错误信息对于的标签名k,和错误信息内容v-->
let eleId = '#id_' + k
<!--生成具体标签id 因为前端forms渲染标签id都是id_字段名-->
$(eleId).next().text(v[0]).parent().addClass('has-error')
<!--找到具体标签,然后.next()找到标签下我们提前设置好的span标签,然后给span标签添加文本错误信息,然后.parent()顺便更改输入框的边框颜色.addClass('has-error') -->
})
}
}
})
})
<!--给所有输入框绑定事件,当聚焦时-->
$('input').focus(function () {
$(this).next().text('').parent().removeClass('has-error')
<!--清除输入框的子span标签内的错误信息,并移除输入框的边框颜色-->
})
</script>
注册功能完成
标签:models,True,博客,django,forms,length,文章,null,BBS From: https://www.cnblogs.com/moongodnnn/p/17020597.html