BBS總結

表設計

from django.db import models
from django.contrib.auth.models import AbstractUser


# Create your models here.
class UserInfo(AbstractUser):
    nid=models.AutoField(primary_key=True)
    # blank=True admin中改字段能夠不填,null=True是數據庫層面能夠爲空
    telephone = models.BigIntegerField(null=True,blank=True)
    # auto_now_add 建立時自動添加當前時間
    create_date = models.DateField(auto_now_add=True)
    # upload_to須要傳一個路徑
    # default 默認頭像的路徑
    avatar = models.FileField(upload_to='avatar/', default='avatar/default.png')
    # 跟Blog表一對一
    blog = models.OneToOneField(to='Blog', to_field='nid',null=True)
    class Meta:
        verbose_name='用戶表'
        verbose_name_plural = verbose_name
# 我的站點表
class Blog(models.Model):
    nid = models.AutoField(primary_key=True)
    site_name = models.CharField(max_length=32)
    site_title = models.CharField(max_length=64)
    # 存css文件的路徑
    theme = models.CharField(max_length=32)
    def __str__(self):
        return self.site_name


class Category(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    blog = models.ForeignKey(to='Blog', to_field='nid')


class Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    blog = models.ForeignKey(to='Blog', to_field='nid')
    def __str__(self):
        return self.name


class Article(models.Model):
    nid = models.AutoField(primary_key=True)
    title = models.CharField(max_length=64,verbose_name='文章標題')
    desc = models.CharField(max_length=255)
    # 存大文本
    content = models.TextField()
    create_time = models.DateTimeField(auto_now_add=True)
    # 跟站點表一對多
    blog = models.ForeignKey(to='Blog', to_field='nid',null=True)
    # 跟分類一對多
    category = models.ForeignKey(to='Category', to_field='nid',null=True)
    # 跟標籤多對多,手動建立第三張表
    tag = models.ManyToManyField(to='Tag', through='Article2Tag', through_fields=('article', 'tag'))

    #     後來想到的
    # 評論數,點贊,點踩數
    comment_num=models.IntegerField(default=0)
    up_num=models.IntegerField(default=0)
    down_num=models.IntegerField(default=0)
    def __str__(self):
        return self.title


class Article2Tag(models.Model):
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(to='Article', to_field='nid')
    tag = models.ForeignKey(to='Tag', to_field='nid')

#誰對哪篇文章,點贊仍是點踩
class UpAndDown(models.Model):
    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey(to='UserInfo')
    article = models.ForeignKey(to='Article', to_field='nid')
    is_up = models.BooleanField()

#評論對評論自關聯,
#誰,何時,對哪篇文章,評論了什麼內容,父評論是誰
class Comment(models.Model):
    nid = models.AutoField(primary_key=True)
    user = models.ForeignKey(to='UserInfo')
    article = models.ForeignKey(to='Article', to_field='nid')
    content = models.CharField(max_length=255)
    # 評論時間
    create_time=models.DateTimeField(auto_now_add=True)
    # parent =models.ForeignKey(to='Comment',to_field='nid')
    # 自關聯,存父評論id
    parent = models.ForeignKey(to='self', to_field='nid',null=True)
    # parent =models.IntegerField()
View Code

1 登錄功能:

-圖形驗證碼css

-ajax提交
-認證用的是auth
-認證經過,loginhtml

    1 forms組件
        1 定義
            from django import forms
            from django.forms import widgets
            from django.core.exceptions import ValidationError
            # 2 寫一個類
            class RegForm(forms.Form):
                # 3 寫屬性
                name=forms.CharField(max_length=8,min_length=3,label='用戶名',error_messages={'max_length':'超長了'},
                                     widget=widgets.TextInput(attrs={'class':'form-control'})
                                     )
                
                # 4 局部鉤子函數
                def clean_name(self):
                    name=self.cleaned_data.get('name')
                    if name.startswith('sb'):
                        raise ValidationError('不能以sb開頭')
                    else:
                        # 切記,若是正確,必定要返回name
                        return name
                    
                #     5 全局鉤子函數
                def clean(self):
                    #一系列邏輯判斷
                    #若是校驗經過:返回cleaned_data
                    #若是校驗不經過:raise ValidationError('兩次密碼不一致'),錯誤放到__all__
                    pass
        2 views中使用:
            def test(request):
                if request.method=='GET':
                    regform=RegForm()
                else:
                    regform=RegForm(request.POST)
                    if regform.is_valid():
                        #通常狀況須要存數據庫了
                        pass
                    else:
                        error_all=regform.errors.get('__all__')
                        # error_all=regform.errors['__all__']
                return render(request,'register.html',locals())
        3 模板中使用
            <form action="">

            {% for foo in regform %}
                {{ foo.label }}:{{ foo }} <span>{{ foo.errors.0 }}</span>
            {% endfor %}
            <input type="submit"> <span>{{ error_all }}</span>

            </form>
            
    2 cookie和session
        1 cookie:由服務器產生,存放在客戶端瀏覽器上的鍵值對
        2 django中使用cookie:
            -設置值:
                obj=HttpResponse('ok')
                obj.set_cookie('key','value',max_age=10)
            -取值:
                request.COOKIES.get('key')
                request.COOKIES['key']
            -刪除值:
                obj=HttpResponse('ok')
                obj.delete_cookie('key')
                
        3 session:保存在服務器上的鍵值對
            -設置值:
                request.session['key']='value'
                request.session['key1']='value1'
                
                     1 生成一個隨機字符串:dasfasdf
                     2 在django_session表中存入dasfasdf   {'key':'value','key1':value1}  超時時間
                     3 把sessionid:dasfasdf寫入到cookie
                
            -取值:
                request.session.get('key')
            -刪除值:
                request.session.flush():全刪除
                request.session.delete():只刪除數據庫
            -其它配置參數:
                瞭解
                
    3 Auth模塊
        1 Django自帶的用戶認證模塊,能夠快速的實現登陸,註銷,修改密碼...
        2 擴展auth表,須要繼承AbstractUser
        3 必定不要忘記在setting中配置:AUTH_USER_MODEL = "app名.UserInfo"
        4 它提供的功能
            -from django.contrib.auth import authenticate,login,logout
            -用戶認證:user=authenticate(username=lqz,password=123)
            -用戶一旦認證經過,調用login(request,user),之後從request.user中就能取出當前登陸人對象
            -退出:logout(request),request.user就是匿名用戶
            -校驗是否經過認證(是否登陸):request.user.is_authenticated()
            -建立普通用戶
                -models.UserInfo.objects.create_user(username=lqz)
            -建立超級用戶
                -models.UserInfo.objects.create_superuser(username=lqz)
            -修改密碼
                -用user對象.set_password(新密碼)
                -必定要記住save
            -校驗密碼
                -check_password(password)
            -登陸認證裝飾器(沒有登錄的時候跳轉)
                -login_required(login_url='/login/')
                -全局配置(在setting中配置):
                    LOGIN_URL = '/login/' 
            is_staff: 用戶是否擁有網站的管理權限:create_superuser:is_staff是1
            is_active: 是否容許用戶登陸, 設置爲 False,能夠在不刪除用戶的前提下禁止用戶登陸。
            
            
今日內容:
    1 中間件
        -是什麼?中間件顧名思義,是介於request與response處理之間的一道處理過程,相對比較輕量級,而且在全局上改變django的輸入與輸出。由於改變的是全局,因此須要謹慎實用,用很差會影響到性能
        -怎麼用:
        -自定義中間件:
            1 寫一個類,繼承MiddlewareMixin,
            2 在類中寫方法:
                process_request
            3 在settings中配置
        
        -5個方法(process_request,process_response)
            ******
            process_request(self,request)
                -執行順序,settings中中間件自上而下執行
                -請求來的時候會執行它
                -request對象,就是本次請求的request對象,對它處理後,視圖函數拿到的就是處理後的request對象
                
            process_view(self, request, callback, callback_args, callback_kwargs)
                -callback是視圖函數,callback_args, callback_kwargs是視圖函數的參數
                -能夠調用callback方法
            
            process_template_response(self,request,response)(忘掉)
                -只有視圖函數返回的對象中有render方法的時候,纔會執行
            process_exception(self, request, exception)
                -視圖函數出錯,會執行它
            *****
            process_response(self, request, response)
                -執行順序,settings中中間件自下而上執行
                -響應走的時候,會執行它
                -request對象,就是本次請求的request對象,response是響應對象(HttpResponse的對象)
            
            
        -若是process_request方法返回HttpResponse的對象,請求直接返回,按中間件方法執行順序往回走
        
    2 csrf
        xss攻擊/csrf或xsrf跨站請求僞造
        使用:中間件不註釋,form表單中寫{% csrf_token %}
    
    3 bbs表設計
        -一個項目從無到有
            1 需求分析
                -登陸ajax,圖形驗證碼
                -註冊forms和ajax,上傳頭像,頭像預覽
                -博客首頁
                -我的站點
                -點贊,點踩
                -評論
                    -根評論
                    -子評論
                -後臺展現
                -添加文章
                    -防xss攻擊
            2 設計程序以及程序的架構
                -Django
                -數據庫設計
                
                
            3 分任務開發程序
            
            4 測試
            5 上線運行
            
        -數據庫設計
            -用戶表:UserInfo---auth模塊
                ...
                -telephone:手機號
                -create_date:註冊時間
                -avatar:用戶頭像
                -blog:跟Blog表一對一
            -我的站點表:Blog
                -site_name:站點名稱
                -site_title:站點標題
                -theme:站點主題樣式
            -分類表:Category
                -nid
                -name:分類名稱
                -blog:屬於哪一個站點            一對多
            -標籤表:Tag
                -nid
                -name:標籤的名稱
                -blog:屬於哪一個站點            一對多
            -文章表:Article
                -nid
                -title:文章標題
                -desc:文章摘要
                -content:文章內容
                -create_time:文章發佈時間
                -blog:文章屬於哪一個站點,      一對多
                -category:文章分類           一對多
                -tag:文章標籤                多對多
                
            -Article2Tag:文章跟標籤的中間表
                -nid
                -article_id:文章id
                -tag_id:標籤id
            -點贊點踩表:UpAndDown
                -nid
                -user:誰                一對多            
                -article:給那篇文章     一對多
                -is_up:點贊或點踩
            -評論表:Comment
                -nid
                -user:誰                 一對多
                -article:給那篇文章      一對多
                -content:評論了什麼內容
                -parent_id:父評論的id    自關聯
                
        nid     用戶id  文章id   內容        parent_id(父評論的id)
        1        1     1       你好          null
        2        2     1       寫的真好      null
        3       3     1       你傻麼         1
            
做業:
    1 csrf中間件不註釋,用ajax提交post請求
    2 用中間件實現只有登陸了之後,才能訪問order,userinfo這些路徑,若是沒有登陸,重定向到登陸頁面
    
            
            
View Code

2 註冊功能

-forms組件
-ajax提交
-錯誤信息渲染前端

    1 註冊:
        -forms組件渲染頁面
        -頭像預覽
        -點擊img觸發頭像上傳
        -$("#myform").serializeArray()的使用
        -jq的循環 $.each(循環的對象,匿名函數(兩個參數)):
            循環對象若是是個列表,匿名函數的兩個參數,一個是索引,一個是索引對應的值
            循環對象若是是個字典,匿名函數的兩個參數,一個是key,一個是value
        -上傳文件:
            processData: false,
            contentType: false,
        -錯誤信息渲染
        -定時器
        
        -reg_form.is_valid()走了它以後,cleaned_data中才有值
    -2 登錄
        -生成驗證碼
            -Pillow
        -生成圖片
        -在圖片上寫字
        -指定寫字的字體
        -內存管理器BytesIO
        -驗證碼保存在session中
        
    -驗證碼刷新:
    $("#id_imgcode")[0].src += '?'
    
    127.0.0.1:8000/getcode/?random=隨機數
View Code

3 首頁

    admin中添加數據要將用戶與一個用戶表進行關聯
     media的配置,設置用戶上傳頭像路徑和默認頭像
     開口:es6

      url(r'^media/(?P<path>.*)', serve,{'document_root':settings.MEDIA_ROOT}),ajax

-所有文章取出來(分頁)for循環渲染數據庫

        -首頁設計:
            -用戶是否登錄
                {% if request.user.is_authenticated %}
                    <li><a href="#">{{ request.user.username }}</a></li>
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
                           aria-haspopup="true" aria-expanded="false">我的中心 <span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li><a href="#">修改密碼</a></li>
                            <li><a href="#">修改頭像</a></li>
                            <li role="separator" class="divider"></li>
                            <li><a href="/logout/">退出</a></li>
                        </ul>
                    </li>
                {% else %}
                    <li><a href="/login/">登錄</a></li>
                    <li><a href="/register/">註冊</a></li>
                {% endif %}
            -for循環顯示全部文章
            -文章做者顯示:
                -{{ article.blog.userinfo.username }}:經過文章,正向查詢站點(blog),經過站點反向查詢用戶,經過用戶取出姓名
            -文章評論和點贊數顯示:
                -<span>評論({{ article.comment_set.count }})</span>
                -<span>點贊({{ article.upanddown_set.count}})</span>
                -經過文章反向查詢(表名小寫_set)全部評論,計算評論條數
                比較複雜,因此用了在文章表中加入三個字段
                    comment_num=models.IntegerField(default=0)
                    up_num=models.IntegerField(default=0)
                    down_num=models.IntegerField(default=0)
        -admin的使用(快速錄入數據):
            -註冊表,才能在admin後臺看到
                admin.site.register(models.UserInfo)
                admin.site.register(models.Blog)
                admin.site.register(models.Tag)
                admin.site.register(models.Category)
                admin.site.register(models.Article)
                admin.site.register(models.UpAndDown)
                admin.site.register(models.Comment)
            -表名的中文顯示:
                class Meta:
                    verbose_name='用戶表'
                    verbose_name_plural = verbose_name
            -字段的中文顯示(verbose_name):
                title = models.CharField(max_length=64,verbose_name='文章標題')
            -admin表單提交,是否必填(blank),注意區分null=True
                -telephone = models.BigIntegerField(null=True,blank=True)
            
        -mediaroot配置
            -media文件:用戶上傳的靜態文件
            -static文件:網站所用的靜態文件
            -在settings中配置:MEDIA_ROOT = os.path.join(BASE_DIR, 'media'),用戶上傳的文件放到裏面
            -在路由中寫:  url(r'^media/(?P<path>.*)', serve,{'document_root':settings.MEDIA_ROOT}),
View Code

4 我的站點

-文章展現(當前站點的全部文章)
-左側標籤顯示
-三個分組查詢,TruncMonthdjango


-抽取成inclusion_tag
-左側過濾後端

-我的站點:
            -路由:url(r'^(?P<username>\w+)',views.site),
            -視圖函數:
                def site(request,username):
                    #經過名字取數據庫查詢此人是否存在,若是存在,返回此人我的站點,若是不存在,返回404
                    user=models.UserInfo.objects.filter(username=username).first()
                    if not user:
                        return render(request,'error.html')
                    # 取到此人我的站點
                    blog=user.blog
                    # 取出該站點下全部文章(從blog取article,反向查詢,一對多,按表名小寫_set.all())
                    article_list=blog.article_set.all()
                    return render(request,'site.html',locals())
            -頁面樣式顯示:(動態顯示)
                <link rel="stylesheet" href="/static/css/{{ blog.theme }}">
            
            
        -補充:
            若是想django不自動加斜槓,須要配置APPEND_SLASH=False
            -防盜鏈:
                -就是根據refer信息

    -自定義session(在中間件中處理)
    -本身的圖片防盜鏈(頭三次,能夠訪問)
    -訪問頻率控制(一分鐘只能,同一個ip地址只能訪問3次)
        -設置一個全局變量,記錄60sip 訪問次數
    
    
View Code
-我的站點左側顯示
        -截斷表分析
            id   時間                           文章內容        month
            1   2019-01-25 03:04:07.844138          111           2019-01
            2   2018-12-01 03:04:54.000000          222           2018-12
            3   2018-12-01 03:05:17.000000          333           2018-12
            4   2018-11-01 03:05:38.000000          444           2018-11
        -官方提供
            from django.db.models.functions import TruncMonth
            Sales.objects
            .annotate(month=TruncMonth('timestamp'))  # Truncate to month and add to select list
            .values('month')  # Group By month
            .annotate(c=Count('id'))  # Select the count of the grouping
            .values('month', 'c')  # (might be redundant, haven't tested) select month and count

        -重點總結:
            -查詢當前站點分類下的文章數
                annotate 方法不侷限於用於本文提到的統計分類下的文章數,你也能夠觸類旁通,只要是兩個 model 類經過 ForeignKey 或者 ManyToMany 關聯起來,那麼就能夠使用 annotate 方法來統計數量。
                category_ret = models.Category.objects.filter(blog=blog).annotate(c=Count('article')).values_list('name', 'c')
            -查詢當前站點標籤下的文章數
                tag_ret=models.Tag.objects.filter(blog=blog).annotate(c=Count('article')).values_list('name','c')
            -查詢當前站點下每月份下的文章數
                -month_ret=models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values('month').annotate(c=Count('pk')).values_list('month','c')
            -前端顯示:
                {% for category in category_ret %}
                    <p><a href="">{{ category.0 }}({{ category.1 }})</a></p>
                {% endfor %}
    -我的站點過濾
        -抽取成inclusion_tag
        -路由設計:
            <p><a href="/{{ username }}/category/{{ category.2 }}">{{ category.0 }}({{ category.1 }})</a></p>
左邊欄

5 文章詳情

-繼承了母版
-marksafe展現html瀏覽器

6 點贊點踩

-事務服務器

    -點贊點踩
        -前端:
            -樣式:從博客園扣過來的
            -ajax提交數據
                -誰對哪篇文章點贊或點贊
                -只寫一個ajax,取出當前點擊div內的span,後續直接在span上加一
        -後端:
            -先判斷是否登陸
            -再判斷是否已經點過
            -去article表中修改點贊或點踩數
            -去點贊點踩表中插入一條數據
View Code

7 評論

-根評論
-根評論提交
-根評論render顯示
-根評論ajax顯示
-子評論
-子評論提交
-子評論render顯示
-子評論ajax顯示

-根評論
        -提交
            -跟點贊點踩相似
        -render顯示
            -後端取出全部評論
            -模板中渲染: <ul class="list-group">
            -日期過濾:comment.create_time|date:'Y-m-d H:i:s'
            
        -ajax顯示:
            -es6的字符串替換語法:`asdfasfd ${變量名}`,變量須要先定義
            -$(".list-group").append(ss) 拼完追加到後面
        
        -es6字符串替換
            'you is %s'%'big'
            var user_name='lqz'
             ss=`
                 <li class="list-group-item">
                 <p>
                 <span>${ user_name }</span>
                    <span>${ time }</span>
                </p>
                ${content}
                </li>
                `
View Code
    1 子評論提交
        -點擊回覆按鈕,1 獲取parent_id 2在文本框中輸入:@人名 回車
        -提交的時候:若是是子評論,須要切掉頭部
            var index=content.indexOf('\n')+1
            content=content.slice(index)
        -提交的時候:須要把parent_id提交到後臺
    2 子評論render顯示
        -判斷是否有父評論,若是有,顯示父評論的人名
            -@{{ comment.parent.user.username }}
    3 子評論的ajax顯示
        -根據parent_id是否有值,判斷要拼接的html樣式
        -評論提交成功,parent_id的值要置爲空
        -後臺:若是是子評論格式,須要返回父評論評論人的名字
子評論

8 後臺文章展現

-table的展現

9 新增文章

-富文本編輯器使用
-富文本編輯器上傳圖片
-處理xss攻擊(bs4)

    5 文章添加
        -富文本編輯器
            -從官網下載,放到static文件夾下
            -window.editor = K.create('#id_content')
            -其它參數,具體看文檔
            -上傳圖片,攜帶csrf
                uploadJson:'/add_img/',
                extraFileUploadParams : {
                        csrfmiddlewaretoken : '{{ csrf_token }}',
                }
        -xss攻擊(bs4)
            -經過bs4模塊,取出script標籤,刪除decompose()
            -取出html中150個字符:soup.text[0:150]
        beautifulsoup4  模塊
            -解析html頁面的
            -爬蟲中用的多
        
    -局部禁用csrf,局部使用
        from django.views.decorators.csrf import csrf_protect,csrf_exempt
        @csrf_exempt 局部禁用,前提是csrf中間件使用着
        @csrf_protect 局部使用,前提是csrf中間件沒有使用
    -CBV加裝飾器
        1 能夠加在方法上
            @method_decorator(auth_login)
        2 能夠加在類上
            -@method_decorator(auth_login,name='dispatch'):所有使用
            -@method_decorator(auth_login,name='get'):只在get上使用
        3 csrf的裝飾器,只能加在類上
            @method_decorator(csrf_exempt,name='dispatch')
View Code
相關文章
相關標籤/搜索