简单实现BBS注册与登陆

一. 数据库的表设计css

数据库表设计
    用户表(利用auth_user, 额外扩张几个字段,不用添加auth_user原表里的字段)
    phone  
    avatar
    create_time
 
     blog   # 一对一我的站点表     用户表与我的站点表
    
    我的站点表
    site_name  # 站点名称
    site_title   # 每一个人站点的名言警句,随便写的
    site_theme  # 站点的样式,  存css的路径
    # 我的站点表常常不会出现外接字段
    标签表   # 存到底有几个标签,名字是谁呢
     name
     blog   # 与我的站点表是一对多的关系,每一个站点看似有多个标签,每一个标签看似在每一个站点都有,实则不是,标签虽然名字同样,可是是不一样的人建立的
    分类表
     name
     blog   # 一对多我的站点
    文章表
     title
     desc  # 文章摘要,独白
     content   # 文章内容
     create_time   # 发布时间
     blog   # 文章和我的站点一对多
     tag   # 多对多
     category   #  文章分类, 一对多的关系
若是想统计某个文章的点赞点踩数, 到我的站点有好多文章,若是咱们要跨表查询的话,无疑是给数据库增长压力,那咱们能够在文章表里建几个普通字段
     # 数据库设计优化
     comment_num      # 普通字段
     up_num     # 普通字段
     down_num   # 普通字段
创建这几个普通字段,咱们能够和点赞点踩表,评论表开个事务,以后在想看评论数的话直接点comment_num就能够拿到评论数,再也不须要跨表查

    点赞点踩表
     user       # 一对多用户表
     article     # 一对多文章表
     is_up
     针对点赞来讲,赞能够有多我的来点,赞对人来讲是一对多的关系
    评论表
    user  #  一对多用户表
    article  # 一对多文章表
    comment  # 评论的内容
    create_time   
    parent     #     一对多评论表 ,本身跟本身关联      根评论,子评论    这个是根评论的id   若是有值说明是子评论, 若是没值就是根评论 

 

数据库同步html

  models里面的配置前端

 1 from django.db import models
 2 from django.contrib.auth.models import AbstractUser
 3 # Create your models here.
 4 class UserInfo(AbstractUser):
 5     phone = models.BigIntegerField(null=True)
 6     # avatar存的是用户头像文件路径 用户上传的头像会自动保存到avatar文件夹下
 7     avatar = models.FileField(upload_to='avatar/',default='avatar/default.jpg')
 8     create_time = models.DateField(auto_now_add=True)
 9 
10     blog = models.OneToOneField(to='Blog',null=True)   # 用户建立出来能够不绑定主页
11 
12 
13 class Blog(models.Model):
14     site_title = models.CharField(max_length=32)
15     site_name = models.CharField(max_length=32)
16     site_theme = models.CharField(max_length=255)
17 
18 
19 class Category(models.Model):
20     name = models.CharField(max_length=32)
21     blog = models.ForeignKey(to='Blog')
22 
23 
24 class Tag(models.Model):
25     name = models.CharField(max_length=32)
26     blog = models.ForeignKey(to='Blog')
27 
28 
29 class Article(models.Model):    # 多对多的时候建议用第三个方法也就是半自动化建立第三张表
30     title = models.CharField(max_length=255)
31     desc = models.CharField(max_length=255)
32     content = models.TextField()  # 存大段文本
33     create_time = models.DateField(auto_now_add=True)
34 
35     # 数据库优化字段
36     comment_num = models.IntegerField(default=0)
37     up_num = models.IntegerField(default=0)
38     down_num = models.IntegerField(default=0)
39 
40     # 外键字段
41     blog = models.ForeignKey(to='Blog',null=True)
42     category = models.ForeignKey(to='Category',null=True)
43     tag = models.ManyToManyField(to='Tag',through='Article2Tag',through_fields=('article','tag'))
44 
45 class Article2Tag(models.Model):
46     article = models.ForeignKey(to='Article')
47     tag = models.ForeignKey(to='Tag')
48 
49 
50 class UpAndDown(models.Model):
51     user = models.ForeignKey(to='UserInfo')
52     article = models.ForeignKey(to='Article')
53     is_up = models.BooleanField()  # 传布尔值  存0/1
54 
55 
56 class Comment(models.Model):
57     user = models.ForeignKey(to='UserInfo')
58     article = models.ForeignKey(to='Article')
59     content = models.CharField(max_length=255)
60     create_time = models.DateField(auto_now_add=True)
61     parent = models.ForeignKey(to='self',null=True)
模型层代码

 

注册功能python

 1 from django import forms
 2 from django.forms import widgets
 3 from app01 import models
 4 
 5 
 6 class MyRegForm(forms.Form):
 7     username = forms.CharField(max_length=8, min_length=3, label='用户名',
 8                                error_messages={
 9                                    'max_length': '用户名最大八位',
10                                    'min_length': '用户名最小三位',
11                                    'required': '用户名不能为空'
12                                }, widget=widgets.TextInput(attrs={'class': 'form-control'})
13                                )
14     password = forms.CharField(max_length=8, min_length=3, label='密码',
15                                error_messages={
16                                    'max_length': '密码最大八位',
17                                    'min_length': '密码最小三位',
18                                    'required': '密码不能为空'
19                                }, widget=widgets.PasswordInput(attrs={'class': 'form-control'})
20                                )
21     confirm_password = forms.CharField(max_length=8, min_length=3, label='确认密码',
22                                        error_messages={
23                                            'max_length': '确认密码最大八位',
24                                            'min_length': '确认密码最小三位',
25                                            'required': '确认密码不能为空'
26                                        }, widget=widgets.PasswordInput(attrs={'class': 'form-control'})
27                                        )
28     email = forms.EmailField(label='邮箱', error_messages={
29         'required': "邮箱不能为空",
30         'invalid': "邮箱格式错误"
31     }, widget=widgets.EmailInput(attrs={'class': 'form-control'}))
32 
33     # 局部钩子 校验用户名是否已存在
34     def clean_username(self):
35         username = self.cleaned_data.get('username')
36         is_user = models.UserInfo.objects.filter(username=username)
37         if is_user:
38             self.add_error('username', '用户名已存在')
39         return username
40 
41     # 全局钩子 校验密码是否一致
42     def clean(self):
43         password = self.cleaned_data.get('password')
44         confirm_password = self.cleaned_data.get('confirm_password')
45         if not password == confirm_password:
46             self.add_error('confirm_password', '两次密码不一致')
47         return self.cleaned_data
form组件代码

前端代码:jquery

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>Title</title>
  6     <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
  7     {% load static %}
  8     <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
  9     <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
 10 </head>
 11 <body>
 12 <div class="container">
 13     <div class="row">
 14         <div class="col-md-8 col-md-offset-2">
 15             <h2 class="text-center">注册</h2>
 16 {#        novalidate是告诉前端不要让前端去校验#}
 17             <form id="myform" novalidate>
 18                 {% csrf_token %}
 19                 {% for foo in form_obj %}
 20                     <div class="form-group">
 21                         {#foo.auto_id获取foo渲染的input框的id值,效果就是在标签上点动就会在input框里有光标在晃动#}
 22                         <label for="{{ foo.auto_id }}">{{ foo.label }}</label>
 23                         {{ foo }}
 24                         <span class="errors pull-right" style="color: red;"></span>
 25                     </div>
 26                 {% endfor %}
 27 {#            form-group的效果就是让input框的距离稍远一点,不加的话就两个input框就会挨的近一点#}
 28                 <div class="form-group">
 29                     <label for="myfile">头像
 30 {#                        将头像的这个放在label里面就会出现点击头像图片的话就会弹出选择文件的页面#}
 31                     <img src="/static/img/default.jpg" alt="" height="80" style="margin-left: 20px" id="img">
 32                     </label>
 33 {#                    将选择文件的那几个字消失#}
 34                     <input type="file" name="avatar" id="myfile" style="display: none">
 35                 </div>
 36                 <input type="button" class="btn btn-primary pull-right" value="注册" id="id_submit">
 37             </form>
 38         </div>
 39     </div>
 40 </div>
 41 
 42 <script>
 43     将头像展现在前端
 44     $('#myfile').change(function () {
 45         // 获取用户上传的头像 而后替换到img标签中
 46         // 1 获取用户上传的文件对象
 47         var fileObj = $(this)[0].files[0];  拿到当前文件所存储的对象
 48         // 2.利用内置对象FileReader
 49         var fileReader = new FileReader();  //文件阅读器
 50         // 3.将文件对象交由文件阅读器读取 文件内容
 51         fileReader.readAsDataURL(fileObj);  // IO操做速度较慢,读取文件较慢,还没等到这条语句执行完就执行下调语句,
 52         // 会出现选中头像后什么都不显示的现象,因此在下条语句加onload等待语句,等待我读完再去执行下条语句
 53         // 4.找到img标签 修改src属性
 54         // 等待文件阅读器彻底读取完文件数据以后 才作下面的操做 onload
 55         fileReader.onload = function(){ $('#img').attr('src',fileReader.result)}
 56     });
 57 
 58     // 绑定点击事件
 59     $('#id_submit').click(function () {
 60         // 1. 产生内置对象formdata
 61         var formData = new FormData();
 62         // 2. 循环添加普通键值对
 63         {#console.log($('#myform').serializeArray())#}
 64         $.each($('#myform').serializeArray(),function (index,obj) {
 65             formData.append(obj.name,obj.value)
 66         });
 67         // 3. 手动添加文件
 68         formData.append('myfile',$('#myfile')[0].files[0]) ;
 69         // 4. 发送ajax请求
 70         $.ajax({
 71             url:'',
 72             type:'post',
 73             data:formData,
 74 
 75             // 传文件须要指定两个参数
 76             contentType:false,
 77             processData:false,
 78 
 79             success:function (data) {
 80                 if (data.code==100){
 81                     location.href = data.url
 82                 }else{
 83                     // 若是没有成功 说明用户输入的数据不合法 你须要展现错误信息
 84                     // console.log(data.msg)
 85                     // 可以将对应的错误信息准确无误的渲染到对应的input下面的span标签中
 86                     // 手动拼接input的id值
 87                     $.each(data.msg,function (index,obj) {
 88                         {#console.log(index,obj)#}
 89                         var targetId = '#id_' + index;
 90                         $(targetId).next().text(obj[0]).parent().addClass('has-error')
 91                     })
 92                 }
 93             }
 94 
 95 
 96         })
 97     });
 98     {#绑定焦点事件,当鼠标点进input框时,让input框不在飘红#}
 99     $('input').focus(function () {
100         $(this).next().text('').parent().removeClass('has-error')
101     })
102 </script>
103 </body>
104 </html>
前端代码

后端代码:ajax

 1 from django.shortcuts import render,HttpResponse
 2 from django.http import JsonResponse
 3 from app01 import myforms
 4 from app01 import models
 5 from django.contrib import auth
 6 # Create your views here.
 7 
 8 
 9 def register(request):
10     form_obj = myforms.MyRegForm()
11     if request.method == 'POST':
12         back_dic = {'code':100,'msg':''}
13         # 校验用户信息是否合法
14         form_obj = myforms.MyRegForm(request.POST)
15         if form_obj.is_valid():
16             clean_data = form_obj.cleaned_data  # clean_data = {'username':'','password':'','confirm_password':'','email':''}
17             clean_data.pop('confirm_password')  # clean_data = {'username':'','password':'','email':''}
18             # 手动获取用户头像
19             user_file = request.FILES.get('myfile')
20             if user_file:  # 必定要判断用户是否传头像了 若是传了才往字典里面添加  没传不用添加 由于有默认
21                 clean_data['avatar'] = user_file
22             # 建立数据
23             models.UserInfo.objects.create_user(**clean_data)
24             back_dic['msg'] = '注册成功'
25             back_dic['url'] = '/login/'
26         else:
27             back_dic['code'] = 101
28             back_dic['msg'] = form_obj.errors   # 数据不合法,错误数据全都在errors里面,将所有错误信息返回前端
29         return JsonResponse(back_dic)   # ajax一般返回的都是一个字典,先在上面定义一个字典
30 
31     return render(request,'register.html',locals())
后端代码
相关文章
相关标签/搜索