• 简单实现BBS注册与登录


    一. 数据库的表设计

    数据库表设计
        用户表(利用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   如果有值说明是子评论, 如果没值就是根评论 

    数据库同步

      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)
    模型层代码

    注册功能

     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组件代码

    前端代码:

      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>
    前端代码

    后端代码:

     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())
    后端代码

      

    生前无需久睡,死后自会长眠,努力解决生活中遇到的各种问题,不畏将来,勇敢面对,加油,你是最胖的,哈哈哈
  • 相关阅读:
    工作一年感想
    launcher项目踩坑小结(1)
    滕王阁序
    PC端/移动端常见的兼容性问题总结
    Java中逻辑&和短路&&,逻辑|和短路||的区别
    Linux常用指令和系统管理命令总结
    Ajax学习笔记
    js放大镜特效
    《Python for Data Science》笔记之着手于数据
    Python2&3学习中遇到的坑
  • 原文地址:https://www.cnblogs.com/panshao51km-cn/p/11593317.html
Copyright © 2020-2023  润新知