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()
-圖形驗證碼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這些路徑,若是沒有登陸,重定向到登陸頁面
-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=隨機數
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}),
-文章展現(當前站點的全部文章)
-左側標籤顯示
-三個分組查詢,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 訪問次數
-我的站點左側顯示 -截斷表分析 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>
-繼承了母版
-marksafe展現html瀏覽器
-事務服務器
-點贊點踩 -前端: -樣式:從博客園扣過來的 -ajax提交數據 -誰對哪篇文章點贊或點贊 -只寫一個ajax,取出當前點擊div內的span,後續直接在span上加一 -後端: -先判斷是否登陸 -再判斷是否已經點過 -去article表中修改點贊或點踩數 -去點贊點踩表中插入一條數據
-根評論
-根評論提交
-根評論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> `
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的值要置爲空 -後臺:若是是子評論格式,須要返回父評論評論人的名字
-table的展現
-富文本編輯器使用
-富文本編輯器上傳圖片
-處理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')