1.模板內容複習css
2.FBV及CBV及上傳文件html
3.ORM複習前端
4.ORM拓展python
5.cookie和session數據庫
6.csrf詳情django
7.django分頁bootstrap
django預備知識:http://www.javashuo.com/article/p-gaxyavsw-bm.html後端
django基礎:http://www.javashuo.com/article/p-ozqsnhub-bv.html瀏覽器
1.模板內容複習cookie
(1)母版和繼承
1 何時用母版? 2 html頁面有重複的代碼,把它們提取出來放到一個單獨的html文件(好比:導航條和左側菜單) 3 4 子頁面如何使用母版? 5 {% extends 'base.html' %} --> 必需要放在子頁面的第一行 6 母版裏面定義block(塊),子頁面使用block(塊)去替換母版中同名的塊
(2)組件
1 何時用組件? 2 重複的代碼,包裝成一個獨立的小html文件。 3 4 如何使用? 5 {% include 'nav.html' %}
(3)Django模板語言中關於靜態文件路徑的靈活寫法
1 利用Django模板語言內置的static方法幫我拼接靜態文件的路徑: 2 {% load static %} 3 <link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet"> 4 5 利用內置的get_static_prefix獲取靜態文件路徑的別名,咱們自行拼接路徑: 6 {% load static %} 7 <link href="{% get_static_prefix %}bootstrap/css/bootstrap.min.css" rel=stylesheet>
(4)自定義simple_tag和自定義inclusion_tag
1 自定義的simple_tag: 2 比filter高級一點點,返回一段文本 3 它能夠接受的參數個數大於2 4 5 自定義的inclusion_tag: 6 用來返回一段html代碼(示例:返回ul標籤)
py文件(放在在app下面新建的templatetags 文件夾(包)):
HTML:
2.FBV及CBV及上傳文件
(1)什麼是FBV及CBV
視圖:接收請求返回響應那部分
FBV:function base view 基於函數的視圖
CBV:class base view 基於類的視圖
(2)CBV實例
views.py:
1 # CBV實例 - 添加新的出版社 2 class AddPublisher(View): 3 def get(self, request): 4 return redirect("/book/publisher_list/") 5 6 def post(self, request): 7 new_name = request.POST.get("publisher_name", None) 8 if new_name: 9 # 經過ORM去數據庫裏新建一條記錄 10 models.Publisher.objects.create(name=new_name) 11 return redirect("/book/publisher_list/")
urls.py:
1 url(r'^add_publisher/', views.AddPublisher.as_view()),
(3)上傳文件
上傳文件要使用到request的如下參數:
request.FILES: 包含全部上傳文件的類字典對象;FILES中的每個Key都是<input type="file" name="" />標籤中name屬性的值,FILES中的每個value同時也是一個標準的python字典對象,包含下面三個Keys:
前端HTML:
1 <form action="" method="post" enctype="multipart/form-data"> 2 <input type="file" name="upload-file"> 3 <input type="submit" value="上傳文件"> 4 </form> 5 6 注意: 7 上傳文件時表單中的enctype="multipart/form-data"必需要寫 8 input(file)必需要有name
views.py:
1 def upload(request): 2 if request.method == "POST": 3 filename = request.FILES["upload-file"].name 4 # 在項目目錄下新建一個文件 -> 項目根目錄 5 with open(filename, "wb") as f: 6 # 從上傳的文件對象中一點一點讀 7 for chunk in request.FILES["upload-file"].chunks(): 8 # 寫入本地文件 9 f.write(chunk) 10 return HttpResponse("上傳OK") 11 return render(request, "test/test_upload.html")
3.ORM複習
(1)django ORM增刪改查
1 DjangoORM基本增刪查改: 2 # 建立: 3 # (1) 4 # models.UserInfo.objects.create(username='root', pwd='666888999') 5 # (2) 6 # dict = {'username': 'alex', 'pwd': '333'} 7 # models.UserInfo.objects.create(**dict) 8 # (3) 9 # obj = models.UserInfo.objects.create(username='root', pwd='666888999') 10 # obj.save() 11 12 # 查: 13 # (1)所有: 14 # result = models.UserInfo.objects.all() 15 # (2)按條件查找: 16 # result = models.UserInfo.objects.filter(username='root') 17 # first = models.UserInfo.objects.filter(username='root').first() 18 # count = models.UserInfo.objects.filter(username='root').count() 19 # result = models.UserInfo.objects.filter(username='root', pwd='123456') 20 21 # 查找的結果的數據結構: 22 # result, QuerySet -> Django -> [] 23 # [obj(id, username, pwd),obj(id, username, pwd),obj(id, username, pwd)] 24 # 輸出查找的結果: 25 # for row in result: 26 # print(row.id, row.username, row.pwd) 27 28 # 刪: 29 # 刪除id爲4的數據 30 # models.UserInfo.objects.filter(id=4).delete() 31 # 刪除username爲alex的數據 32 # models.UserInfo.objects.filter(username="alex").delete() 33 34 # 更新: 35 # 所有更新: 36 # models.UserInfo.objects.all().update(pwd='666') 37 # 條件更新: 38 # models.UserInfo.objects.filter(id=3).update(pwd='69')
(2)ORM字段
經常使用字段:
經常使用的字段參數:
DateField和DateTimeField纔有的參數:
(3)關係字段
eg:
關於多對多:
1 # 多對多的方式: 2 # 1. ORM ManyToManyField()自動幫我建立第三張表 --> 關係表中沒有額外字段、ORM封裝了不少方法可使用: add() remove() set() clear() 3 4 # 2. 本身建立第三張表, 利用外鍵分別關聯做者和書 這種方法關聯查詢比較麻煩,由於沒辦法使用ORM提供的便利方法 5 6 # 3. 本身建立第三張表,用ORM的ManyToManyField()的through指定表名(自建的關係表) --> 可向關係表中添加額外字段, 使用此種方式沒有ORM封裝的方法可以使用 注: through_fields = (field1, field2) field1是關係表經過哪一個屬性能夠找到這張表 7 8 9 # 咱們應該用哪一種? 看狀況: 10 # 若是你第三張表沒有額外的字段,就用第一種 11 # 若是你第三張表有額外的字段,就用第三種或第一種 12 13 # 有額外字段的實際狀況: 14 """ 15 相親網站: 16 Boy 17 girl = ManyToManyField(to=「Girl") 18 19 Girl 20 21 約會記錄:多對多 22 id boy_id girl_id date 23 """
實例:
1 # 一對多: 2 class Publisher(models.Model): 3 id = models.AutoField(primary_key=True) 4 name = models.CharField(max_length=64, null=False, unique=True) 5 6 class Book(models.Model): 7 id = models.AutoField(primary_key=True) 8 title = models.CharField(max_length=64, null=False, unique=True) 9 # 和出版社關聯的外鍵字段: 10 publisher = models.ForeignKey(to="Publisher") 11 # 數據庫中沒有publisher這個字段 這有publisher_id這個字段 12 13 # 一對一: 14 class Author(models.Model): 15 name = models.CharField(max_length=32) 16 info = models.OneToOneField(to='AuthorInfo') 17 18 class AuthorInfo(models.Model): 19 phone = models.CharField(max_length=11) 20 email = models.EmailField() 21 22 # 多對多1(系統自動生成第三張表 or 本身建第張方表): 23 class Book(models.Model): 24 id = models.AutoField(primary_key=True) 25 title = models.CharField(max_length=64, null=False, unique=True) 26 27 class Author(models.Model): 28 id = models.AutoField(primary_key=True) 29 name = models.CharField(max_length=32, null=False, unique=True) 30 book = models.ManyToManyField(to="Book") # 告訴ORM Author和Book是多對多關係 系統自動生成第三張表 31 32 # 多對多2(本身建第三張表 利用外鍵關聯) 33 class Author2Book(models.Model): 34 id = models.AutoField(primary_key=True) 35 author = models.ForeignKey(to="Author") # 做者id 36 book = models.ForeignKey(to="Book") # 圖書id 37 # 本身建表還能夠新建字段 38 publish_date = models.DateField(auto_now_add=True)
多對多第三種方式:
(4)單表查詢的雙下劃線用法
1 models.Book.objects.filter(id__gt=1) 2 models.Book.objects.filter(id__in=[1,2,3]) 3 models.Book.objects.filter(id__range=[1,5]) 4 models.Book.objects.filter(title__contains="python") 5 models.Book.objects.filter(title__icontains="python") 6 models.Book.objects.filter(title__startswith="python") 7 models.Book.objects.filter(title__endswith="python") 8 models.Book.objects.filter(publish_date__year=2017) 9 models.Book.objects.filter(publish_date__month=2)
4.ORM拓展
ORM詳細內容:http://www.javashuo.com/article/p-emhmbenx-bp.html
(1)ORM查詢
返回QuerySet對象:
返回一個特殊的QuerySet對象:
返回一個具體對象:
返回布爾值:
exists(): 若是QuerySet包含數據,就返回True,不然返回False
返回數字:
count(): 返回數據庫中匹配查詢(QuerySet)的對象數量
多對多查詢拓展:
1 def select_related(self, *fields) 2 # 性能相關:表之間進行join連表操做,一次性獲取關聯的數據。 3 4 總結: 5 1. select_related主要針一對一和多對一關係進行優化。 6 2. select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。 7 8 def prefetch_related(self, *lookups) 9 # 性能相關:多表連表操做時速度會慢,使用其執行屢次SQL查詢在Python代碼中實現連表操做。 10 11 總結: 12 1. 對於多對多字段(ManyToManyField)和一對多字段,可使用prefetch_related()來進行優化。 13 2. prefetch_related()的優化方式是分別查詢每一個表,而後用Python處理他們之間的關係。
(2)外鍵的查詢操做
1 # 正向查詢: 2 # 查詢第一本書的出版社 3 book_obj = models.Book.objects.all().first() 4 ret = book_obj.publisher 5 res = book_obj.publisher.name 6 print(ret, res) 7 # 查詢id是7的書的出版社的名稱 8 # 利用雙下劃線 跨表查詢 雙下劃線就表示跨了一張表 9 ret = models.Book.objects.filter(id=7).values_list("publisher__name") 10 print(ret) 11 12 # 反向查詢: 13 # 1. 基於對象查詢 14 publisher_obj = models.Publisher.objects.get(id=1) # 獲得一個具體的對象 15 # ret = publisher_obj.book_set.all() 16 # 在外鍵字段中加上related_name="books",以後就要使用下面的方法查詢: 17 ret = publisher_obj.books.all() 18 print(ret) 19 # 2. 基於雙下劃線 20 ret = models.Publisher.objects.filter(id=1).values_list("books__title") 21 print(ret)
注意:
(3)多對多操做
查詢:
1 # 查詢第一個做者: 2 author_obj = models.Author.objects.first() 3 print(author_obj.name) 4 # 查詢寫過的書: 5 ret = author_obj.book.all() 6 print(author_obj.book, type(author_obj.book)) 7 print(ret)
增刪改查操做:
1 # 1. create 2 # 經過做者建立一本書,會自動保存 3 # 作了兩件事:1. 在book表裏面建立一本新書,2. 在做者和書的關係表中添加關聯記錄 4 author_obj = models.Author.objects.first() 5 author_obj.book.create(title="wyb自傳", publisher_id=1) 6 7 # 2. add 8 # 在wyb關聯的書裏面,再加一本id是8的書 9 book_obj = models.Book.objects.get(id=8) 10 author_obj.book.add(book_obj) 11 # 添加多個 12 book_objs = models.Book.objects.filter(id__gt=5) 13 author_obj.book.add(*book_objs) # 要把列表打散再傳進去 14 # 直接添加id 15 author_obj.book.add(9) 16 17 # 3.remove 18 book_obj = models.Book.objects.get(title="跟Alex學泡妞") 19 author_obj.book.remove(book_obj) 20 # 把 id是8的記錄 刪掉 21 author_obj.book.remove(8) 22 23 # 4.clear 24 # 清空 25 jing_obj = models.Author.objects.get(id=2) 26 jing_obj.book.clear()
注意:
對於ForeignKey對象,clear()和remove()方法僅在null=True時存在
(4)分組和聚合查詢
聚合查詢:
aggregate()是QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。
鍵的名稱是聚合值的標識符,值是計算出來的聚合值。鍵的名稱是按照字段和聚合函數的名稱自動生成出來的
用到的內置函數:
1 from django.db.models import Avg, Sum, Max, Min, Count
實例以下:
1 from django.db.models import Avg, Sum, Max, Min, Count 2 res = models.Book.objects.all().aggregate(price_avg=Avg("price"), price_max=Max("price"), price_min=Min("price")) 3 print(res) 4 print(res.get("price_avg"), res.get("price_max"), res.get("price_min")) 5 print(type(res.get("price_max"))) # <class 'decimal.Decimal'>
分組查詢:
1 # 查詢每一本書的做者個數 2 from django.db.models import Avg, Sum, Max, Min, Count 3 ret = models.Book.objects.all().annotate(author_num=Count("author")) 4 print(ret) 5 for book in ret: 6 print("書名:{},做者數量:{}".format(book.title, book.author_num)) 7 8 # 查詢做者數量大於1的書 9 ret = models.Book.objects.all().annotate(author_num=Count("author")).filter(author_num__gt=1) 10 print(ret) 11 12 # 查詢各個做者出的書的總價格13 ret = models.Author.objects.all().annotate(price_sum=Sum("book__price")) 14 print(ret) 15 for i in ret: 16 print(i, i.name, i.price_sum) 17 print(ret.values_list("id", "name", "price_sum"))
(5)F查詢和Q查詢
F查詢:
在上面全部的例子中,咱們構造的過濾器都只是將字段值與某個常量作比較。若是咱們要對兩個字段的值作比較,那該怎麼作呢?
Django 提供 F() 來作這樣的比較。F() 的實例能夠在查詢中引用字段,來比較同一個 model 實例中兩個不一樣字段的值
F查詢實例:
1 from django.db.models import F 2 3 # 查詢評論數大於收藏數的書籍 4 models.Book.objects.filter(comment_num__gt=F('keep_num')) 5 6 # 修改操做也可使用F函數,好比將每一本書的價格提升30元 7 models.Book.objects.all().update(price=F("price")+30) 8 9 # 修改字段: 10 from django.db.models.functions import Concat 11 from django.db.models import Value 12 models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("初版"), Value(")")))
Q查詢:
filter() 等方法中的關鍵字參數查詢都是一塊兒進行「AND」 的。 若是你須要執行更復雜的查詢(例如OR語句),你可使用Q對象
Q查詢實例:
1 from django.db.models import Q 2 # 查詢 賣出數大於1000,而且 價格小於100的全部書 3 ret = models.Book.objects.filter(maichu__gt=1000, price__lt=100) 4 print(ret) 5 6 # 查詢 賣出數大於1000,或者 價格小於100的全部書 7 ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100)) 8 print(ret) 9 10 # Q查詢和字段查詢同時存在時, 字段查詢要放在Q查詢的後面 11 ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100), title__contains="金老闆") 12 print(ret)
ORM拓展內容總結:
1 #分組和聚合 2 # 聚合: 3 from django.db.models import Avg, Sum, Max, Min, Count 4 models.Book.objects.all().aggregate(Avg("price")) 5 6 # 分組: 7 book_list = models.Book.objects.all().annotate(author_num=Count("author")) 8 9 # F和Q 10 # 當須要字段和字段做比較的時候用F查詢 11 # 當查詢條件是 或 的時候 用Q查詢,由於默認的filter參數都是且的關係
1 ################################################################## 2 # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET # 3 ################################################################## 4 5 def all(self) 6 # 獲取全部的數據對象 7 8 def filter(self, *args, **kwargs) 9 # 條件查詢 10 # 條件能夠是:參數,字典,Q 11 12 def exclude(self, *args, **kwargs) 13 # 條件查詢 14 # 條件能夠是:參數,字典,Q 15 16 def select_related(self, *fields) 17 性能相關:表之間進行join連表操做,一次性獲取關聯的數據。 18 19 總結: 20 1. select_related主要針一對一和多對一關係進行優化。 21 2. select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。 22 23 def prefetch_related(self, *lookups) 24 性能相關:多表連表操做時速度會慢,使用其執行屢次SQL查詢在Python代碼中實現連表操做。 25 26 總結: 27 1. 對於多對多字段(ManyToManyField)和一對多字段,可使用prefetch_related()來進行優化。 28 2. prefetch_related()的優化方式是分別查詢每一個表,而後用Python處理他們之間的關係。 29 30 def annotate(self, *args, **kwargs) 31 # 用於實現聚合group by查詢 32 33 from django.db.models import Count, Avg, Max, Min, Sum 34 35 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')) 36 # SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id 37 38 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1) 39 # SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 40 41 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1) 42 # SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 43 44 def distinct(self, *field_names) 45 # 用於distinct去重 46 models.UserInfo.objects.values('nid').distinct() 47 # select distinct nid from userinfo 48 49 注:只有在PostgreSQL中才能使用distinct進行去重 50 51 def order_by(self, *field_names) 52 # 用於排序 53 models.UserInfo.objects.all().order_by('-id','age') 54 55 def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None) 56 # 構造額外的查詢條件或者映射,如:子查詢 57 58 Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) 59 Entry.objects.extra(where=['headline=%s'], params=['Lennon']) 60 Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) 61 Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) 62 63 def reverse(self): 64 # 倒序 65 models.UserInfo.objects.all().order_by('-nid').reverse() 66 # 注:若是存在order_by,reverse則是倒序,若是多個排序則一一倒序 67 68 69 def defer(self, *fields): 70 models.UserInfo.objects.defer('username','id') 71 或 72 models.UserInfo.objects.filter(...).defer('username','id') 73 #映射中排除某列數據 74 75 def only(self, *fields): 76 #僅取某個表中的數據 77 models.UserInfo.objects.only('username','id') 78 或 79 models.UserInfo.objects.filter(...).only('username','id') 80 81 def using(self, alias): 82 指定使用的數據庫,參數爲別名(setting中的設置) 83 84 85 ################################################## 86 # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS # 87 ################################################## 88 89 def raw(self, raw_query, params=None, translations=None, using=None): 90 # 執行原生SQL 91 models.UserInfo.objects.raw('select * from userinfo') 92 93 # 若是SQL是其餘表時,必須將名字設置爲當前UserInfo對象的主鍵列名 94 models.UserInfo.objects.raw('select id as nid from 其餘表') 95 96 # 爲原生SQL設置參數 97 models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,]) 98 99 # 將獲取的到列名轉換爲指定列名 100 name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} 101 Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) 102 103 # 指定數據庫 104 models.UserInfo.objects.raw('select * from userinfo', using="default") 105 106 ################### 原生SQL ################### 107 from django.db import connection, connections 108 cursor = connection.cursor() # cursor = connections['default'].cursor() 109 cursor.execute("""SELECT * from auth_user where id = %s""", [1]) 110 row = cursor.fetchone() # fetchall()/fetchmany(..) 111 112 113 def values(self, *fields): 114 # 獲取每行數據爲字典格式 115 116 def values_list(self, *fields, **kwargs): 117 # 獲取每行數據爲元祖 118 119 def dates(self, field_name, kind, order='ASC'): 120 # 根據時間進行某一部分進行去重查找並截取指定內容 121 # kind只能是:"year"(年), "month"(年-月), "day"(年-月-日) 122 # order只能是:"ASC" "DESC" 123 # 並獲取轉換後的時間 124 - year : 年-01-01 125 - month: 年-月-01 126 - day : 年-月-日 127 128 models.DatePlus.objects.dates('ctime','day','DESC') 129 130 def datetimes(self, field_name, kind, order='ASC', tzinfo=None): 131 # 根據時間進行某一部分進行去重查找並截取指定內容,將時間轉換爲指定時區時間 132 # kind只能是 "year", "month", "day", "hour", "minute", "second" 133 # order只能是:"ASC" "DESC" 134 # tzinfo時區對象 135 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC) 136 models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai')) 137 138 """ 139 pip3 install pytz 140 import pytz 141 pytz.all_timezones 142 pytz.timezone(‘Asia/Shanghai’) 143 """ 144 145 def none(self): 146 # 空QuerySet對象 147 148 149 #################################### 150 # METHODS THAT DO DATABASE QUERIES # 151 #################################### 152 153 def aggregate(self, *args, **kwargs): 154 # 聚合函數,獲取字典類型聚合結果 155 from django.db.models import Count, Avg, Max, Min, Sum 156 result = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid')) 157 ===> {'k': 3, 'n': 4} 158 159 def count(self): 160 # 獲取個數 161 162 def get(self, *args, **kwargs): 163 # 獲取單個對象 164 165 def create(self, **kwargs): 166 # 建立對象 167 168 def bulk_create(self, objs, batch_size=None): 169 # 批量插入 170 # batch_size表示一次插入的個數 171 objs = [ 172 models.DDD(name='r11'), 173 models.DDD(name='r22') 174 ] 175 models.DDD.objects.bulk_create(objs, 10) 176 177 def get_or_create(self, defaults=None, **kwargs): 178 # 若是存在,則獲取,不然,建立 179 # defaults 指定建立時,其餘字段的值 180 obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2}) 181 182 def update_or_create(self, defaults=None, **kwargs): 183 # 若是存在,則更新,不然,建立 184 # defaults 指定建立時或更新時的其餘字段 185 obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1}) 186 187 def first(self): 188 # 獲取第一個 189 190 def last(self): 191 # 獲取最後一個 192 193 def in_bulk(self, id_list=None): 194 # 根據主鍵ID進行查找 195 id_list = [11,21,31] 196 models.DDD.objects.in_bulk(id_list) 197 198 def delete(self): 199 # 刪除 200 201 def update(self, **kwargs): 202 # 更新 203 204 def exists(self): 205 # 是否有結果 206 207 QuerySet方法大全
5.cookie和session
詳細內容:http://www.javashuo.com/article/p-ceqcahvy-ba.html
6.csrf詳情
(1)什麼是csrf
csrf:跨站請求僞造
百度解釋:CSRF(Cross-site request forgery)跨站請求僞造,也被稱爲「One Click Attack」或者Session Riding,一般縮寫爲CSRF或者XSRF,是一種對網站的惡意利用。儘管聽起來像跨站腳本(XSS),但它與XSS很是不一樣,XSS利用站點內的信任用戶,而CSRF則經過假裝來自受信任用戶的請求來利用受信任的網站。與XSS攻擊相比,CSRF攻擊每每不大流行(所以對其進行防範的資源也至關稀少)和難以防範,因此被認爲比XSS更具危險性
一句話解釋:CSRG是指經過經過僞造頁面來欺騙用戶,讓用戶在釣魚網址上輸入關鍵信息,而後修改部分數據提交給真正的服務端程序
(2)csrf實例
釣魚網站的頁面和正經網站的頁面對瀏覽器來講有什麼區別? (頁面是怎麼來的?)
釣魚網站如何實現釣魚:前端頁面如出一轍,可是在表單中隱藏了某些關鍵的input而後這些input寫成無用的input顯示在頁面上,這些隱藏的input的value是固定值,不管你在那些無用的input上輸入什麼值,最後提交給服務端的值都是肯定的
詳情見下面實例:
真正的網站前端代碼:
1 <!--__author__ = "wyb"--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <meta charset="UTF-8"> 6 <title>轉帳</title> 7 </head> 8 <body> 9 10 <h1>真正的網站</h1> 11 <form action="" method="post"> 12 <p> 13 轉出: 14 <input type="text" name="from"> 15 </p> 16 <p> 17 轉入: 18 <input type="text" name="to"> 19 </p> 20 <p> 21 金額: 22 <input type="text" name="money"> 23 </p> 24 <p> 25 <input type="submit" value="轉帳"> 26 </p> 27 28 </form> 29 30 </body> 31 </html>
真正的網站後端代碼:
1 # 真正網站的服務端: 2 def transfer(request): 3 if request.method == "GET": 4 return render(request, "test/transfer_test.html") 5 from_ = request.POST.get("from") 6 to_ = request.POST.get("to") 7 money = request.POST.get("money") 8 print("{} 給 {} 轉了 {}錢".format(from_, to_, money)) 9 return HttpResponse("轉帳成功!")
釣魚網站前端代碼:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>轉帳</title> 6 </head> 7 <body> 8 9 <h1>釣魚的網站</h1> 10 <form action="http://127.0.0.1:8000/basic/transfer/" method="post"> 11 <p> 12 轉出: 13 <input type="text" name="from"> 14 </p> 15 16 <p> 17 轉入: 18 <input type="text" name=""> 19 <input type="text" name="to" style="display: none" value="黑客"> 20 </p> 21 <p> 22 金額: 23 <input type="text" name="money"> 24 </p> 25 <p> 26 <input type="submit" value="轉帳"> 27 </p> 28 </form> 29 </body> 30 </html>
釣魚網站後端代碼:
1 def transfer(request): 2 return render(request, "transfer.html")
二者頁面以下:
注:頁面中的標題只是爲了便於區分,正真的釣魚網站能夠說和原網站幾乎如出一轍,能夠以假亂真
兩個網站轉帳的數據相同時轉帳效果:
釣魚網站經過隱藏的input框修改了轉帳的轉入方,在釣魚網站上的轉入方不管你填什麼最後轉入方都是黑客
(3)Django內置的處理csrf問題的中間件
django中內置的處理csrf問題的中間件是:django.middleware.csrf.CsrfViewMiddleware
這個中間件作的事情:
(4)django內置csrf中間件用法
在頁面上 form表單 裏面 寫上 {% csrf_token %}就好了而後在settings.py中去掉csrf的註釋,以後再用上面的實例測試效果以下:
釣魚網站:
真正網站:
(5)csrf補充 - CSRF Token相關裝飾器
CSRF Token相關裝飾器在CBV只能加到dispatch方法上,或者加在視圖類上而後name參數指定爲dispatch方法。
CBV寫法:
1 from django.views.decorators.csrf import csrf_exempt, csrf_protect 2 from django.utils.decorators import method_decorator 3 4 class HomeView(View): 5 @method_decorator(csrf_exempt) 6 def dispatch(self, request, *args, **kwargs): 7 return super(HomeView, self).dispatch(request, *args, **kwargs) 8 9 def get(self, request): 10 return render(request, "home.html") 11 12 def post(self, request): 13 print("Home View POST method...") 14 return redirect("/index/") 15 16 17 # 或者這樣寫: 18 @method_decorator(csrf_exempt, name='dispatch') 19 class HomeView(View): 20 21 def dispatch(self, request, *args, **kwargs): 22 return super(HomeView, self).dispatch(request, *args, **kwargs) 23 24 def get(self, request): 25 return render(request, "home.html") 26 27 def post(self, request): 28 print("Home View POST method...") 29 return redirect("/index/")
FBV寫法:
1 from django.views.decorators.csrf import csrf_exempt, csrf_protect 2 3 @csrf_exempt 4 def login(request): 5 xxx
7.django分頁
(1)分頁基本邏輯
books/?page=n --> n是整數,表示第幾頁
1 # 第一頁: all_book = models.Book.objects.all()[0:10] # 1到10 2 # 第二頁: all_book = models.Book.objects.all()[10:20] # 11到20 3 # 第三頁: all_book = models.Book.objects.all()[20:30] # 21到30 4 # 第n頁: n -> [(n-1)*10, n*10]
從request.GET中取出page對應的數,而後取出對應的數據傳給前端便可,page對應的數默認設爲1
(2)自定義分頁
views.py:
1 # 原生分頁 2 def books(request): 3 # 第一頁: all_book = models.Book.objects.all()[0:10] # 1到10 4 # 第二頁: all_book = models.Book.objects.all()[10:20] # 11到20 5 # 第三頁: all_book = models.Book.objects.all()[20:30] # 21到30 6 # 第n頁: n -> [(n-1)*10, n*10] 7 8 # 總數據是多少 9 data_count = models.Book.objects.all().count() 10 # 每一頁顯示多少條數據 11 per_page = 10 12 # 總共須要多少頁碼來展現 13 total_page, m = divmod(data_count, per_page) 14 if m: 15 total_page = total_page + 1 16 17 # 從URL中取參數: 18 page_num = request.GET.get("page", "1") 19 try: 20 page_num = int(page_num) 21 except Exception as e: 22 # 當輸入頁碼不是正常數字時 默認返回1 23 page_num = 1 24 # 若是輸入的數字大於total_page時 默認返回最大 25 if page_num > total_page: 26 page_num = total_page 27 28 # data_start和data_end分別保存數據的起始 29 data_start = (page_num - 1) * per_page 30 data_end = page_num * per_page 31 # 頁面上總共展現多少頁碼(最多) 32 max_page = 10 33 if total_page < max_page: 34 max_page = total_page 35 half_max_page = max_page//2 36 # 頁碼開始和結束 37 page_start = page_num - half_max_page 38 page_end = page_num + half_max_page 39 if page_start <= 1: 40 page_start = 1 41 page_end = max_page + 1 42 if page_end > total_page: 43 page_start = total_page - max_page 44 page_end = total_page + 1 45 46 all_book = models.Book.objects.all()[data_start:data_end] 47 48 # 拼接HTML: 49 html_str_list = [] 50 # 加上上一頁 51 # 判斷 若是是第一頁 就沒有上一頁 52 if page_num <= 1: 53 html_str_list.append('<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format(page_num-1)) 54 else: 55 html_str_list.append('<li><a href="/books/?page={}" aria-label="Previous"><span aria-hidden="true">«</span></a></li>'.format(page_num-1)) 56 # 加上第一頁 -> 寫死 57 html_str_list.append('<li><a href="/books/?page=1">首頁</a></li>') 58 for i in range(page_start, page_end): 59 # 若是是當前頁就加上active類 60 if i == page_num: 61 tmp = '<li class="active"><a href="/books/?page={0}">{0}</a></li>'.format(i) 62 else: 63 tmp = '<li><a href="/books/?page={0}">{0}</a></li>'.format(i) 64 html_str_list.append(tmp) 65 # 加上最後一頁 66 html_str_list.append('<li><a href="/books/?page={}">尾頁</a></li>'.format(total_page)) 67 # 加上下一頁 68 # 判斷 若是是最後一頁 就沒有下一頁 69 if page_num >= total_page: 70 html_str_list.append('<li class="disabled"><a href="#" aria-label="Next"><span aria-hidden="true">»</span></a></li>'.format(page_num+1)) 71 else: 72 html_str_list.append('<li><a href="/books/?page={}" aria-label="Next"><span aria-hidden="true">»</span></a></li>'.format(page_num+1)) 73 page_html = "".join(html_str_list) 74 75 return render(request, "books.html", {"books": all_book, "page_html": page_html})
HTML:
1 <!--__author__ = "wyb"--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <meta charset="UTF-8"> 6 <title>書籍列表</title> 7 <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" 8 integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> 9 </head> 10 <body> 11 12 <div class="container"> 13 <table class="table table-bordered table-striped"> 14 <thead> 15 <tr> 16 <th>序號</th> 17 <th>id</th> 18 <th>書名</th> 19 </tr> 20 </thead> 21 <tbody> 22 {% for book in books %} 23 <tr> 24 <td>{{ forloop.counter }}</td> 25 <td>{{ book.id }}</td> 26 <td>{{ book.title }}</td> 27 </tr> 28 {% endfor %} 29 </tbody> 30 </table> 31 32 <nav aria-label="Page navigation"> 33 <ul class="pagination"> 34 {{ page_html|safe }} 35 </ul> 36 </nav> 37 38 </div> 39 40 41 </body> 42 </html>
封裝以後的分頁:
1 # 分頁封裝保存版 2 class Pagination(object): 3 def __init__(self, current_page, total_count, base_url, per_page=10, max_show=10): 4 """ 5 :param current_page: 當前頁 6 :param total_count: 數據庫中數據總數 7 :param base_url: url前綴 8 :param per_page: 每頁顯示多少條數據 9 :param max_show: 最多顯示多少頁 10 """ 11 try: 12 current_page = int(current_page) 13 except Exception as e: 14 current_page = 1 15 16 self.current_page = current_page 17 self.total_count = total_count 18 self.base_url = base_url 19 self.per_page = per_page 20 self.max_show = max_show 21 22 # 總頁碼 23 total_page, more = divmod(total_count, per_page) 24 if more: 25 total_page += 1 26 self.total_page = total_page 27 28 # 左邊間隔的頁碼和右邊間隔的頁碼 29 # 10 -> 4和5 11 -> 5和5 30 if max_show % 2 == 0: 31 self.left_show = max_show // 2 - 1 32 self.right_show = max_show // 2 33 else: 34 self.left_show = self.right_show = max_show // 2 35 36 @property 37 def start(self): 38 return (self.current_page - 1) * self.per_page 39 40 @property 41 def end(self): 42 return self.current_page * self.per_page 43 44 def page_html(self): 45 46 if self.current_page <= self.left_show: 47 show_start = 1 48 show_end = self.max_show 49 else: 50 if self.current_page + self.right_show >= self.total_page: 51 show_start = self.total_page - self.max_show + 1 52 show_end = self.total_page 53 else: 54 show_start = self.current_page - self.left_show 55 show_end = self.current_page + self.right_show 56 57 # 存html的列表 58 page_html_list = [] 59 60 # 加首頁 61 first_li = '<li><a href="{}?page=1">首頁</a></li>'.format(self.base_url) 62 page_html_list.append(first_li) 63 # 加上一頁 64 if self.current_page == 1: 65 prev_li = '<li><a href="#">上一頁</a></li>' 66 else: 67 prev_li = '<li><a href="{0}?page={1}">上一頁</a></li>'.format(self.base_url, self.current_page - 1) 68 page_html_list.append(prev_li) 69 70 # 生成頁面上顯示的頁碼 71 for i in range(show_start, show_end + 1): 72 if i == self.current_page: 73 li_tag = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i) 74 else: 75 li_tag = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.base_url, i) 76 page_html_list.append(li_tag) 77 78 # 加下一頁 79 if self.current_page == self.total_page: 80 next_li = '<li><a href="#">下一頁</a></li>' 81 else: 82 next_li = '<li><a href="{0}?page={1}">下一頁</a></li>'.format(self.base_url, self.current_page + 1) 83 page_html_list.append(next_li) 84 # 加尾頁 85 page_end_li = '<li><a href="{0}?page={1}">尾頁</a></li>'.format(self.base_url, self.total_page) 86 page_html_list.append(page_end_li) 87 88 return "".join(page_html_list)
封裝的分頁的使用方法:
1 # 使用封裝的分頁 2 def books2(request): 3 data = models.Book.objects.all() 4 pager = Pagination(request.GET.get("page"), len(data), request.path_info) 5 book_list = data[pager.start:pager.end] 6 page_html = pager.page_html() 7 return render(request, "books.html", {"books": book_list, "page_html": page_html})
注:books.html見上面的HTML
(3)django內置分頁
1 from django.shortcuts import render 2 from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger 3 4 L = [] 5 for i in range(999): 6 L.append(i) 7 8 def index(request): 9 current_page = request.GET.get('p') 10 11 paginator = Paginator(L, 10) 12 # per_page: 每頁顯示條目數量 13 # count: 數據總個數 14 # num_pages:總頁數 15 # page_range:總頁數的索引範圍,如: (1,10),(1,200) 16 # page: page對象 17 try: 18 posts = paginator.page(current_page) 19 # has_next 是否有下一頁 20 # next_page_number 下一頁頁碼 21 # has_previous 是否有上一頁 22 # previous_page_number 上一頁頁碼 23 # object_list 分頁以後的數據列表 24 # number 當前頁 25 # paginator paginator對象 26 except PageNotAnInteger: 27 posts = paginator.page(1) 28 except EmptyPage: 29 posts = paginator.page(paginator.num_pages) 30 return render(request, 'index.html', {'posts': posts})
1 <!DOCTYPE html> 2 <html> 3 <head lang="en"> 4 <meta charset="UTF-8"> 5 <title></title> 6 </head> 7 <body> 8 <ul> 9 {% for item in posts %} 10 <li>{{ item }}</li> 11 {% endfor %} 12 </ul> 13 14 <div class="pagination"> 15 <span class="step-links"> 16 {% if posts.has_previous %} 17 <a href="?p={{ posts.previous_page_number }}">Previous</a> 18 {% endif %} 19 <span class="current"> 20 Page {{ posts.number }} of {{ posts.paginator.num_pages }}. 21 </span> 22 {% if posts.has_next %} 23 <a href="?p={{ posts.next_page_number }}">Next</a> 24 {% endif %} 25 </span> 26 27 </div> 28 </body> 29 </html>