簡單實現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())
後端代碼