BBS第二天

表关系创建

模型层代码

注意点:

  • 用户表我们是在django默认的user表上继承的,创建用户模型层代码时需要继承AbstractUser
  • 评论数 点赞数 点踩数 字段优化 避免频繁跨表浪费资源。这里我们在article表中定义三个普通字段记录
  • 文章和标签表是多对多关系,第三章关系表我们这里自定义即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.


class Userinfo(AbstractUser):
'''用户表'''
phone = models.BigIntegerField('手机号',null=True)
# 头像 存储头像路径 图片数据单独存放 upload_to指定文件存放路径
avatar = models.FileField('头像', upload_to='avatar/', default='avatar/default.jpg')
# 日期
create_time = models.DateField('注册时间', auto_now_add=True)
# 一对一
blog = models.OneToOneField(to='Site', null=True)


class Site(models.Model):
'''个人站点'''
site_title = models.CharField('站点标题', max_length=32)
site_name = models.CharField('站点名称', max_length=32)
site_theme = models.CharField('站点样式', max_length=32)


class Article(models.Model):
'''文章表'''
title = models.CharField('文章标题', max_length=32)
desc = models.CharField('文章简介', max_length=32)
content = models.TextField('文章内容') # 存储大段文本
create_time = models.DateField('创建日期',auto_now_add=True)

# 评论数 点赞数 点踩数 字段优化 避免频繁跨表浪费资源
# 定义三个普通字段记录
comment_num = models.IntegerField('评论数', default=0)
up_num = models.IntegerField('点赞数', default=0)
down_num = models.IntegerField('点踩数', default=0)
# 当评论表或者点赞点踩表有记录的时候 顺带修改上述三个普通字段即可

# 个人站点
blog = models.ForeignKey(to='Site', null=True)
# 分类
category = models.ForeignKey(to='Category', null=True)
# 标签
tag = models.ManyToManyField(to='Tag', through='ArticleToTag', through_fields=('article', 'tag'))


class Tag(models.Model):
'''标签表'''
name = models.CharField('文章标签', max_length=32)
blog = models.ForeignKey(to='Site', null=True)


class ArticleToTag(models.Model):
article = models.ForeignKey(to='Article')
tag = models.ForeignKey(to='Tag')


class Category(models.Model):
'''分类表'''
name = models.CharField('文章分类', max_length=32)
blog = models.ForeignKey(to='Site', null=True)


class UpAndDown(models.Model):
'''点赞点踩'''
user = models.ForeignKey(to='Userinfo')
article = models.ForeignKey(to='Article')
is_up = models.BooleanField('点赞点踩') # True/False 1/0


class Comment(models.Model):
'''评论表'''
user = models.ForeignKey(to='Userinfo')
article = models.ForeignKey(to='Article')
content = models.CharField('评论内容', max_length=255)
comment_time = models.DateTimeField('评论日期',auto_now_add=True)
# 自关联
parent = models.ForeignKey(to='self', null=True)

"""
1 1 写的真棒 2021
2 1 你放屁 2021 1
3 1 好好说话 2021 2
"""

forms组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
from django import forms
from app01 import models


# 注册forms组件wrs
class MyRegister(forms.Form):
# 用户名
username = forms.CharField(label='用户名',
max_length=8,
min_length=3,
error_messages={
'required': '用户名不能为空',
'min_length': '用户名最少三位',
'max_length': '用户名最多八位'
},
widget=forms.widgets.TextInput(attrs={'class': 'form-control'})
)
# 密码
password = forms.CharField(label='密码',
max_length=8,
min_length=3,
error_messages={
'required': '密码不能为空',
'min_length': '密码最少三位',
'max_length': '密码最多八位'
},
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
)
# 确认密码
confirm_password = forms.CharField(label='确认密码',
max_length=8,
min_length=3,
error_messages={
'required': '确认密码不能为空',
'min_length': '确认密码最少三位',
'max_length': '确认密码最多八位'
},
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
)
# 邮箱
email = forms.EmailField(label='邮箱',
error_messages={
'invalid': "邮箱格式错误",
'required': '邮箱不能为空'
},
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).first()
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

注册后端逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def register(request):
# 生成一个forms对象
form_obj = MyRegister()
if request.method == 'POST':
back_dic = {'code':10000,'msg':''}
# 校验普通键值对数据
form_obj = MyRegister(request.POST)
# 判断数据是否合法
if form_obj.is_valid():
# form_obj.cleaned_data # 字典 存放的合法的数据 {'username' 'password' 'confirm_password' 'email'}
# 将cleaned_data里面的confirm_password键值对删除
clean_data = form_obj.cleaned_data
clean_data.pop('confirm_password') # {'username' 'password' 'email'}
# 获取头像数据
file_obj = request.FILES.get('avatar')
if file_obj:
clean_data['avatar'] = file_obj # {'username' 'password' 'email' 'avatar'}
models.Userinfo.objects.create_user(**clean_data)
back_dic['msg'] = '注册成功'
back_dic['url'] = '/login/'
else:
back_dic['code'] = 10001
back_dic['msg'] = form_obj.errors
return JsonResponse(back_dic)
return render(request,'register.html',locals())

注册前端逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
用户头像实时展示
需要使用js自带的内置对象FileReader()文件阅读器
批量获取用户输入的数据
serializeArray()

$('#myfile').change(function (){
var fileReader = new FileReader();
var myFile = $(this)[0].files[0];
fileReader.readAsDataURL(myFile);
fileReader.onload = function (){
$('#id_img').attr('src',fileReader.result)
}
})
// 绑定点击事件 触发提交动作
$('#id_submit').click(function (){
var formData = new FormData();
$.each($('#myform').serializeArray(),function (index,obj){
formData.append(obj.name,obj.value)
});
// 手动添加文件对象
formData.append('myfile',$('#myfile')[0].files[0]);
// 发送ajax请求
$.ajax({
url: '',
type: 'post',
data: formData,
processData: false,
contentType: false,

success:function (data) {
if (data.code==100){
location.href = data.url
}else {
// 找到对应的input框对应错误信息
$.each(data.msg,function (index,obj){
var targetId = '#id_' + index;
$(targetId).next().html(obj[0]).parent().add('has-error')
})
}
}
})
});

$('input').focus(function (){
$(this).next().html('').parent().removeClass('has-error')
})

settings相关配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
django内部支持多个国家的语言环境
默认是英文 可以通过配置文件指定切换
from django.conf import global_settings

LANGUAGE_CODE = 'zh-hans'

# 静态文件目录配置
STATICFILES_DIRS = [
os.path.join(BASE_DIR,'bootstrap&jquery'),
]

# 用户上传的静态文件位置
MEDIA_ROOT = os.path.join(BASE_DIR,'media')

# 自定义django的用户管理模型表,设置为我们自定义的Userinfo表
AUTH_USER_MODEL = 'app01.Userinfo'

# #login_required全局配置
LOGIN_URL = '/login/'