BBS(仿博客園系統)項目01(項目分析、表結構設計、註冊功能實現)

摘要:css

  • 需求分析
  • 表結構設計
  • 註冊功能實現

1、需求分析:

  • 項目需求(產品經理、架構師、開發組組長與客戶談該項目相關要求)
  • 項目設計 (架構師須要思考:框架選擇,數據庫選擇,主要功能模塊,報價:包括工期、開發人員工資...)
  • 任務分發(開發組長開會,拆分項目各個任務,分發到各組)
  • 測試(本身測試/本地測試,測試員測試,白盒測試--開發人員、黑盒測試--測試人員)
  • 交付上線(運維配合上線)

2、項目分析:

表設計:

  1. 用戶表(UserInfo)
    首先咱們使用Django Web框架,因此用戶表繼承Django的auth_user表的結構,咱們自定義建立UserInfo表,在原Django自動建立的auth_user表基礎上

    補充添加一些字段:
    用戶電話(phone)BigIntegerField類型
    用戶頭像(avatar)FileField類型(指定上傳路徑upload_to=‘’,默認頭像文件default='avatar/xxx.jpg')
    用戶建立時間(create_time) DateField類型(設置時間爲新增記錄時候自動設置爲當前時間auto_now_add=True)
    一對一關係的blog字段(blog)OneToOneField(to='Blog', null=True)
    須要知道:用戶user會有點贊點踩(UpAndDown)、評論(Comment)、站點(Blog)html

  2. 我的站點表(Blog)
    站點名稱(blog_name) CharField類型,建議長度32
    站點標題(blog_title)CharField類型,建議長度64
    站點樣式主題(blog_theme) CharField類型,存儲css文件路徑,建議長度64
    須要知道:站點blog上會有標籤(Tag)、分類(Category)、文章(Article)
  3. 文章標籤表(Tag)
    標籤名稱(name)CharField類型,建議長度32
    一對多關係:Blog(一)>>>Tag(多):
    blog外鍵字段 ForeignKey(to='Blog',null=True)
  4. 文章分類表(Category)
    分類名稱(name)CharField類型,建議長度32
    一對多關係:Blog(一)>>>Category(多):
    blog外鍵字段 ForeignKey(to='Blog',null=True)
  5. 文章表(Article)
    文章標題(title) CharField類型 建議長度64
    文章摘要(desc)CharField類型 建議長度255
    文章內容(content)TextField類型
    文章發佈時間(create_time) DateField類型(設置時間爲新增記錄時候自動設置爲當前時間auto_now_add=True)
    # 優化查詢建立的字段:
    評論數(comment_num)IntegerField類型
    點贊數(up_num)IntegerField類型
    踩數(down_num)IntegerField類型
    # Article表與我的站點Blog、標籤Tag、分類Category都有關聯:
    一對多關係:
    Blog(一)>>>Article(多):blog外鍵字段 ForeignKey(to='Blog',null=True)
    Category(一)>>>Article(多):category外鍵字段 ForeignKey(to='Category',null=True)
    多對多關係:(這裏咱們手動建立第三張多對多關聯表Article2Tag)
    Tag >>> Article :tag多對多外鍵字段 :ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag'))
  6. 點贊點踩表(UpAndDown)
    是否點贊(is_up)BooleanField類型,0表明點踩,1表明點贊
    點贊點踩會與用戶表UserInfo、文章表Article關聯:
    一對多關係:
    UserInfo(一)>>>UpAndDown(多):user外鍵字段 ForeignKey(to='UserInfo')  一個用戶能夠點多個贊和踩,一個踩或者贊只多是一個用戶點的
    Article(一)>>>UpAndDown(多):user外鍵字段 ForeignKey(to='Article')  一篇文章能夠被點多個贊和踩,一個踩或者贊只可能對應在一片文章上
  7. 評論表(Comment)
    評論內容(content)CharField類型 建議長度255
    建立時間(create_time) DateField類型(設置時間爲新增記錄時候自動設置爲當前時間auto_now_add=True)
    評論表會與用戶表UserInfo、文章表Article關聯:
    一對多關係:
    UserInfo(一)>>>Comment(多):user外鍵字段 ForeignKey(to='UserInfo')  一個用戶能夠發佈多個評論,一個評論只多是一個用戶發佈的
    Article(一)>>>Comment(多):user外鍵字段 ForeignKey(to='Article')  一篇文章能夠有多個評論,一個評論只可能對應在一片文章上
    父評論(parent)ForeignKey類型 ForeignKey(to='self') 這個特殊,跟本身關聯

    總結:BBS表直接的關係圖:

 註冊功能實現:

  1.  配置環境
    setting.py文件
    1、設置靜態文件 2、告訴Django,自定義建立用戶表 3、使用MySQL數據庫,配置數據庫參數 STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), os.path.join(BASE_DIR, 'app01/static') ] AUTH_USER_MODEL = 'app01.UserInfo' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'bbs01', 'HOST': '127.0.0.1', 'PORT': 3306, 'USER': 'root', 'PASSWORD': '123' } } 
    # 注意在init文件中寫入:

     

      import pymysql
      pymysql.install_as_MySQLdb()前端

     

  2. 配置Django的form表單相關數據:
    app01文件夾下新建文件夾myform,接着在此文件下新建myform.py文件,此py文件中:
    from django import forms from app01 import models # 建立Django的form表單
    class MyForm(forms.Form): username = forms.CharField( max_length=8, min_length=3, label='用戶名:', error_messages={ 'required': '用戶名不能爲空', 'max_length': '用戶名最大爲8位', 'min_length': '用戶名最小3位', }, widget=forms.widgets.TextInput(attrs={'class': 'form-control'}) ) password = forms.CharField( max_length=8, min_length=3, label='密碼:', error_messages={ 'required': '密碼不能爲空', 'max_length': '密碼最大8位', 'min_length': '密碼最小3位', }, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}) ) confirm_password = forms.CharField( max_length=8, min_length=3, label='確認密碼:', error_messages={ 'required': '確認密碼不能爲空', 'max_length': '確認密碼最大8位', 'min_length': '確認密碼最小3位', }, widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}) ) email = forms.EmailField( label='郵箱:', error_messages={ 'required': '郵箱不能爲空', 'invalid': '郵箱格式錯誤' }, widget=forms.widgets.EmailInput(attrs={'class': 'form-control'}) ) # 使用局部鉤子和全局鉤子對用戶名和密碼進行二次校驗:
        # 全局鉤子校驗密碼輸入是否一致:
        def clean(self): password = self.cleaned_data.get('password') confirm_password = self.cleaned_data.get('confirm_password') if password != confirm_password: self.add_error('confirm_password', '輸入兩次密碼不一致') return self.cleaned_data  # 記得返回
    
        # 局部鉤子校驗用戶名是否存在:
        def clean_username(self): username = self.cleaned_data.get('username') user_obj = models.UserInfo.objects.filter(username=username).first() if user_obj: self.add_error('username', '用戶名已存在') return username   # 記得返回
  3. 項目app01中models.py文件中建立Django的orm映射表關係模型數據:
    models.py中,建立表(前提是須要先建立一個數據庫(bbs01))
    from django.db import models from django.contrib.auth.models import AbstractUser # Create your models here.
    class UserInfo(AbstractUser): phone = models.BigIntegerField(null=True) create_time = models.DateField(auto_now_add=True) blog = models.OneToOneField(to='Blog', null=True) avatar = models.FileField(upload_to='avatar/', default='avatar/default_avatar.jpg') class Blog(models.Model): blog_name = models.CharField(max_length=32) blog_title = models.CharField(max_length=64) blog_theme = models.CharField(max_length=64) class Article(models.Model): title = models.CharField(max_length=64) content = models.TextField() desc = models.CharField(max_length=255) create_time = models.DateField(auto_now_add=True) blog = models.ForeignKey(to='Blog', null=True) category = models.ForeignKey(to='Category', null=True) tag = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag')) # 優化查詢
        comment_num = models.IntegerField() up_num = models.IntegerField() down_num = models.IntegerField() class Category(models.Model): name = models.CharField(max_length=32) blog = models.ForeignKey(to='Blog', null=True) class Article2Tag(models.Model): article = models.ForeignKey(to='Article') tag = models.ForeignKey(to='Tag') class Tag(models.Model): name = models.CharField(max_length=32) blog = models.ForeignKey(to='Blog', null=True) class UpAndDown(models.Model): is_up = models.BooleanField() user = models.ForeignKey(to='UserInfo') article = models.ForeignKey(to='Article') class Comment(models.Model): content = models.CharField(max_length=255) create_time = models.DateField(auto_now_add=True) user = models.ForeignKey(to='UserInfo') article = models.ForeignKey(to='Article') parent = models.ForeignKey(to='self', null=True)

    注意:記得運行數據庫遷移命令makemigrations>>>migrater 使建立的表生效
  4. 配置路由,視圖函數、前端register.html建立
    ## urls.py中:
    from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^register/', views.register) ]
    ## register.html文件建立:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title> {# <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>#} <script src="/static/jQuery-3.4.1.js"></script>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
        <link rel="stylesheet" href="/static/reg.css">
        <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
    </head>
    <body>
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h2 class="text-center">註冊頁面</h2>
                <hr> {# 注意:這裏使用form表單的目的在於咱們須要經過form表單批量處理表單內輸入的數據對象#} <form id="myform"> {% csrf_token %} {% for form in form_obj %} {# 經過在input框外套個div,設置div的class包含form-group,#} {# 就能夠經過bootstrap的樣式來調整input框之間的間距#} <div class="form-group">
                            <label for="{{ form.auto_id }}">{{ form.label }}</label> {{ form }} <span class="has-error pull-right"></span>
                        </div> {% endfor %} </form>
                    <div class="form-group">
                        <label for="id_myfile">
                            <img id="id_avatar" src="/static/avatar/default_avatar.jpg" width="70" class="img-thumbnail">
                        </label> 點擊圖片上傳頭像 <input type="file" id="id_myfile" name="myfile" class="hide">
                    </div>
                    <button class="btn btn-primary pull-right" id="id_submit">提交註冊</button>
            </div>
        </div>
    </div>
    
    <script>
        // 利用文件閱讀器動態展現用戶上傳的圖像
     $('#id_myfile').on('change',function () { // 獲取上傳文件對象
     let file_obj = this.files[0]; // 生成一個文件閱讀器內置對象
     let fileReader = new FileReader(); // 把文件對象傳給文件閱讀器對象
     fileReader.readAsDataURL(file_obj); // 將讀取出的文件對象替換到img標籤
            // 由於渲染圖片的速度遠比文件閱讀器讀取文件的速度
            // 因此,這裏須要用onload方法等待文件閱讀器讀取完畢以後在渲染圖片,圖片纔會顯示
     fileReader.onload = function () { $('#id_avatar').attr('src', fileReader.result) // img標籤src屬性可放:文件路徑、文件二進制數據、url
     } }); // 經過ajax發送請求,提交數據
     $('#id_submit').on('click',function () { // ajax沒法傳本身傳文件,須要藉助內置對象FormData傳文件
            // 聲明一個formData對象,formData對象既能傳文件又能夠傳普通鍵值,經過append的方式添加
     let formData = new FormData(); // jQuery對象方法each方法:
            // 將經過$('#myform').serializeArray()方法獲得的json格式的對象數組遍歷它每一個鍵值對
            // 把遍歷出來的每一個鍵值對經過函數處理,function()中的index是遍歷出來的鍵值對加的索引,
            // obj就是遍歷出來的鍵值對(也就是這裏form表單裏面input框的name和填寫的value)
     $.each( // 經過serializeArray() 方法序列化form表單值來建立對象數組(名稱和值),該方法返回的是個json對象
                // 返回的 JSON 對象是由一個對象數組組成的,其中每一個對象包含鍵值對 name和value
     $('#myform').serializeArray(), function (index, obj) {formData.append(obj.name,obj.value);} // 1 {name: "username", value: "sgt"} 對應的index 和 obj
     ); // function函數內將遍歷出來的json數據經過點name和點value獲得對應鍵值添加進formData中
    
            // 普通鍵值(input框填入的鍵值)添加完畢,接下來添加文件數據到formData中
     formData.append('myfile', $('#id_myfile')[0].files[0]); $.ajax({ url: '', // 不寫默認當前頁面路由提交
     type: 'post', // post提交方式
     data: formData, // 傳數據和文件就得藉助內置對象formData發送請求
     processData: false, // 告訴瀏覽器不對數據作任何處理
     contentType: false, // 不進行任何編碼,formData數據對象Django後端可以識別
                // 接下來
     success:function (data) { // 註冊成功,跳轉到後端傳來的指定頁面
                    if (data.code==100) {location.replace(data.url)} // 註冊失敗,將後端傳來的校驗不成功的提示信息進行處理渲染到前端
                    // 這裏須要注意一點:Django的form表單在前端渲染的時候會將每一個input框的id名按規律
                    // 定義名字,好比像這樣:id_username、id_password
                    else { $.each( data.msg, function (index, obj) { // 注意:index obj 分別是:username ["用戶名最小3位"]
                                // 和上面的方法不同,這個是將字典使用each方法,上面是將數組使用each方法
     let targetId = '#id_'+index; // 拼接出input框的id名
                                // 遍歷出來的每一個字段名字,經過上面拼接的對應input框對應的id名,經過這個
                                // id名字就能找到它,它下面(經過next()方法)就是咱們須要處理的span標籤
                                // 將它添加html文本(就是錯誤提示信息,注意obj是個列表),同時繼續鏈式操做
                                // 讓錯誤的input框標紅框,警告提示,經過parent()方法找到父標籤div,將其
                                // class加入一個has-error便可達到目的
     $(targetId).next().html(obj[0]).parent().addClass('has-error') } ) } } }) }); // 上面經過ajax發送post請求進行註冊過程基本所有完成,最後還實現了錯誤信息的渲染,此時還需進行完善一下
        // 用戶若是註冊一次提示錯誤,繼續進行註冊的話,就須要再次清空錯誤提示,因此:
     $('input').on('focus',function () { $(this).next().html('').parent().removeClass('has-error') // 方法同上面加入錯誤信息相似,也是找到input框下面的span標籤,將她的html置空,就去掉了紅色提示
            // 同時繼續找到其父標籤div去掉class裏面的has-error,紅框提示取消
     }) </script>
    </body>
    </html>
    ## views.py視圖函數
    from django.shortcuts import render,HttpResponse,redirect from app01.myform.myform import MyForm from app01 import models from django.http import JsonResponse # Create your views here.
    def register(request): form_obj = MyForm() # 先定義一個響應字典,後面註冊請求來了返回時候要使用
        back_dic = {'code': 100, 'msg': ''} if request.method == 'POST': # 將register頁面提交的普通數據獲取到丟給MyForm(),實例化一個form_obj
            form_obj = MyForm(request.POST) # 經過form_obj獲得Django自動校驗提交表單處理結果
            if form_obj.is_valid(): # 校驗經過,獲取到經過的全部鍵值數據字典
                data = form_obj.cleaned_data # 這裏須要注意,字典裏面有個confirm_password的鍵值,這個鍵值在校驗經過後是不須要的
                # 因此須要去掉:
                data.pop('confirm_password') # 獲取用戶上傳的頭像文件對象
                file_obj = request.FILES.get('myfile') # 這裏須要加一層判斷,看看用戶在前端是否上傳了頭像文件,仍是用的默認頭像
                # 傳了就添加進data,沒傳就直接新增數據
                if file_obj: # 用戶上傳了頭像文件,往data裏添加頭像文件的鍵值
                    data['avatar'] = file_obj # 注意要用create_user才能正常建立用戶數據
                    # data是字典形式的鍵值對,直接打散傳入,perfect!
                models.UserInfo.objects.create_user(**data) back_dic['msg'] = '註冊成功'
                # 在相應數據字典裏添加註冊成功後跳轉的頁面路由
                back_dic['urs'] = '/login/'
            # 校驗不經過,註冊不成功
            else: back_dic['code'] = 101  # 用101表明註冊失敗
                # 將校驗失敗的信息字典傳進去,等待前端渲染提示用戶註冊失敗
                back_dic['msg'] = form_obj.errors return JsonResponse(back_dic) return render(request, 'register.html', locals())

     

相關文章
相關標籤/搜索