一. 數據庫的表設計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
前端代碼: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())