django進階

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:

  • filename: 上傳文件名,用字符串表示
  • content_type: 上傳文件的Content Type
  • content: 上傳文件的原始內容

前端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字段

經常使用字段:

  • AutoField -->  int自增列 必須填入參數primary_key=True
  • CharField -->  字符類型 varchar(xx) 必須提供max_length參數
  • TextField  -->  文本類型
  • ForeignKey --> 外鍵
  • ManyToManyField --> 多對多關聯
  • DateField  -->  日期字段  YYYY-MM-DD 至關於python的datetime.date()實例
  • DateTimeField  -->  日期時間字段 YYYY-MM-DD HH:MM 至關於python的datetime.datetime()實例
  • IntegerField  -->  整數類型

經常使用的字段參數:

  • null 表示某個字段能夠爲空
  • default 爲字段設置默認值
  • unique 表示該字段在此表中惟一
  • db_index 爲此字段設置索引


DateField和DateTimeField纔有的參數:

  • auto_now_add=True --> 建立數據的時候自動把當前時間賦值
  • auto_add=True --> 每次更新數據的時候更新當前時間
  • 注意: 上述兩個不能同時設置!!!

 

(3)關係字段

  • ForeignKey:外鍵類型在ORM中用來表示外鍵關聯關係,通常把ForeignKey字段設置在 '一對多'中'多'的一方
  • OneToOneField:一對一字段  一般一對一字段用來擴展已有字段
  • ManyToManyField: 用於表示多對多的關聯關係。在數據庫中經過第三張表來創建關聯關係

eg:

  • ForeignKey(to="類名",related_name=「xx」)   -->  1對多,外鍵一般設置在多的那一邊
  • ManyToMany(to="類名",related_name="xx")  -->   多對多,一般設置在正向查詢多的那一邊
  • OneToOneField(to="類名")  --> 1對1,把不怎麼經常使用的字段 單獨拿出來作成一張表 而後用過一對一關聯起來

關於多對多:

 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對象:

  • all(): 查詢全部結果
  • filter(**kwargs): 它包含了與所給篩選條件相匹配的對象
  • exclude(**kwargs): 它包含了與所給篩選條件不匹配的對象
  • order_by(*field): 對查詢結果排序
  • reverse(): 對查詢結果反向排序,請注意reverse()一般只能在具備已定義順序的QuerySet上調用(在model類的Meta中指定ordering或調用order_by()方法
  • distinct(): 從返回結果中剔除重複紀錄(若是你查詢跨越多個表,可能在計算QuerySet時獲得重複的結果。此時可使用distinct(),注意只有在PostgreSQL中支持按字段去重

返回一個特殊的QuerySet對象:

  • values(*field): 返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列model的實例化對象,而是一個可迭代的字典序列
  • values_list(*field): 它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列

返回一個具體對象:

  • first(): 返回第一條記錄
  • last(): 返回最後一條記錄
  • get(**kwargs): 返回與所給篩選條件相匹配的對象,返回結果有且只有一個,若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤

返回布爾值:

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方法大全
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

這個中間件作的事情:

  • 在render返回頁面的時候,在頁面中塞了一個隱藏的input標籤(eg: <input type="hidden" name="csrfmiddlewaretoken" value="8gthvLKulM7pqulNl2q3u46v1oEbKG7BSwg6qsHBv4zf0zj0UcbQmpbAdijqyhfE">)
  • 當你提交POST數據的時候,它幫你作校驗,若是校驗不經過就拒絕此次請求

 

(4)django內置csrf中間件用法
在頁面上 form表單 裏面 寫上 {% csrf_token %}就好了而後在settings.py中去掉csrf的註釋,以後再用上面的實例測試效果以下:
釣魚網站:

真正網站:

(5)csrf補充 - CSRF Token相關裝飾器

CSRF Token相關裝飾器在CBV只能加到dispatch方法上,或者加在視圖類上而後name參數指定爲dispatch方法。

  • csrf_protect:爲當前函數強制設置防跨站請求僞造功能,即使settings中沒有設置全局中間件
  • csrf_exempt:取消當前函數防跨站請求僞造功能,即使settings中設置了全局中間件

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是整數,表示第幾頁

  • page=1:  第一條到第十條數據
  • page=2:  第十一條到第二十條數據
  • page=3:  第二十一條到第三十條數據
  • 之後依次類推
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">&laquo;</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">&laquo;</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">&raquo;</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">&raquo;</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})
View Code

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>
View Code

 

封裝以後的分頁:

 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})
內置分頁view部分
 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>
內置分頁HTML部分
相關文章
相關標籤/搜索