Django基礎(三)

用戶功能
管理功能
django支持任意多個appcss

​ 注意:html

1. 使用命令行建立項目,不會自動建立templates文件夾,只能手動建
        2. settings文件中手動寫[os.path.join(BASE_DIR, 'templates')]

​ pycharm建立:前端

​ 可以自動建立template文件夾和路徑配置python

​ 也可以支持建立一個應用並註冊。mysql

三板斧

from django.shortcuts import render,HttpResponse, redirect

​ HttpResponsenginx

# 返回字符串
urls:
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'login/', views.login),


def login(request):
    return HttpResponse('Hello word~')

​ rendergit

# 返回HTML頁面,而且能夠爲該html傳值
urls:
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'login/', views.login),
    url(r'reg/', views.reg),
]



def reg(request):
    user_dict = {'name':'jason','pwd':123}
    # return render(request,'reg.html')
    # 給模板傳值的方式1
    # return render(request, 'reg.html',{'xxx':user_dict})  # 將user_dict傳遞給reg.html頁面 頁面上經過xxx就可以獲取到該字典
    # 給模板傳值的方式2
    return render(request,'reg.html',locals())  # 會將當前名稱空間中全部的變量名所有傳遞給reg.html頁面
    # locals()  會出現效率問題,但仍是要是用

​ redirect程序員

# 重定向 既能夠是咱們本身的路徑也能夠是網上的路徑
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'login/', views.login),
    url(r'reg/', views.reg),
    url(r'home/', views.home),
    url(r'index/', views.index),
]


def home(request):
    # return redirect('/index')
        return redirect('http://www.xiaohuar.com')

def index(request):
    return HttpResponse('index')


注意: 重定向的能夠是本身寫的,也能夠是第三方的。

django返回的都是HttpResponse對象正則表達式

咱們寫的視圖函數必須得有返回值sql

靜態文件配置

用戶可以訪問到的全部資源,都是程序員提早爆露好的,若是沒有暴露,用戶永遠也訪問不到。

用戶可以在瀏覽器中輸入網址訪問到相應的資源,前提是後端暴露了該資源接口。
在django中若是你想讓用戶訪問到對應的資源,咱們只須要在urls.py中設置對應關係,反過來若是我沒有在urls.py中開設資源 用戶就永遠就訪問不到對應的資源。
返回給瀏覽器的html頁面上全部的靜態資源 也須要請求後端加載獲取
一般咱們將網站所用到的html文件所有存放在templates文件夾下
網站用到的靜態資源所有存放到static文件夾下

靜態文件

​ 網站所用到的

​ 本身寫好的js

​ 本身寫好的CSS

​ 第三方的框架 bootstrap fontwesome sweetalert

一般狀況下網站所用到的靜態文件資源,統一都放在static文件夾下

settings:
STATIC_URL = '/static/'  # 是訪問靜態資源的接口前綴
"""只要你想訪問靜態資源 你就必須以static開頭"""
# 手動配置靜態文件訪問資源
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static'),
    os.path.join(BASE_DIR,'static1'),
    # os.path.join(BASE_DIR,'static2'),
] # (支持多個)

打開網頁,F12, 自定義關閉旁邊,Network, Disable cache (while DevTools is open),關閉緩存

接口前綴 動態解析

{% load static %}
<link rel="stylesheet" href="{% static'bootstrap/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>

from表單

form是一個複雜的系統標籤,其內部又可包含不少的一些輸入標籤

例如input 輸入文本標籤 checkbox 多選標籤等等

form表單有幾個屬性咱們須要注意一下

  1:action屬性,裏面寫的是url連接,接就是表單提交的地址

  2:method屬性,裏面寫的是數據提交的方式,能夠寫入get或者post

  3:enctype屬性,提交數據的編碼格式

form表單中的標籤的先後臺交互

from表單上傳文件

form表單上傳文件
1.提交方式必須是post
2.須要將form標籤的enctype屬性由默認的urlencoded改成formdata

後端須要從request.FILES中獲取上傳的文件

django內部針對不一樣數據格式的數據 會解析到不一樣的方法中
request.GET
request.POST
request.FILES

form表單被咱們應用在先後臺交互的環節的,裏面的值能夠在後臺經過某些key取出來

下面就來說解不一樣標籤取值的方法

1. input 標籤
input標籤咱們最爲常見,裏面有三個屬性比較重要
  a. type 他是表明input的類型
  b. name 他就是後臺取值的依據(key)
  c. val 他是咱們輸入的值,也是後臺須要的值
  

而後咱們根據type的類型,又能夠把input進行細分

  a. text 表示普通的文本,明文輸入
  b. password 輸入的也是文本,密文輸入
  c. number 輸入的是數字,不是數字不讓輸入
  d. submit 提交按鈕,提交form表單的內容
  e. button 普通的按鈕
  f. radio 單選框,咱們須要注意的是單選框的全部的name值必須相同
      若是name不相同,就說明不在同一個選擇方位,也就不存在單選,而後想要在後臺取到他的值,

      你必須在定義的時候給附上一個值給value,這樣才能取到值
  g. checkbox 複選框,內容和單選框同樣
  h. file 選擇文件,能夠選擇文件提交給後臺

以上基本是input的全部類型,須要注意幾個點
  1.取值都是經過name進行取值,因此必須給name賦值
  2.文本類型想要附上初始值,直接在value中加入值就能夠
  3.選擇框若是想要默認選中誰,那就在誰的標籤中加入checked屬性

2. select 標籤
select標籤是一個下拉框的形式讓用戶進行選擇選項
因此select標籤中必須包含option標籤才能顯示屬性
形式爲:

而後select中有全局屬性name,這個name是後臺又來進行取值的
每一個option標籤的文本內容是顯示給用戶看的,咱們須要取的是option標籤中的value屬性,因此在開始必須給option的value賦值
後臺經過select的name取值,直接取到的就是對應option的value

若是咱們向讓他默認選擇某個option,能夠在option標籤中加入selected屬性,若是都不加,默認是顯示第一個

3. button 按鈕標籤
新出的標籤,與input中type爲button的按鈕同樣

4. textarea 文本框標籤

與input中的text同樣都是輸入文本的,可是textarea標籤沒有字數的限制,而且輸入框能夠拖拉。

from表單 action參數能夠寫的形式
  1. 若不寫 :默認朝當前地址提交
  2. 只寫後綴/index/
  3. 寫全路徑

from表單默認朝後端提交的方式 默認是get請求

​ get請求攜帶參數的方式,是在url後面?

​ url ?username=admin&password=123

​ 缺點:

  1. 不安全
  2. get請求攜帶的參數有大小限制

若是前期要提交post請求 就去settings中註釋掉一箇中間件

request對象及方法先後端數據交互

如何獲取請求方式

獲取post請求攜帶的數據
request.POST
獲取get請求攜帶的數據:request.GET
get和post在後端獲取用戶數據的時候 規律是同樣的
<QueryDict: {'username': ['admin', 'tank'], 'password': ['123']}>
tank <class 'str'>
123 <class 'str'>
request.POST.get('username') 默認只取列列表的最後一個元素
若是你想將列表完整的取出 你必須用getlist()

request.GET  # 你就把它當成一個大字典 裏面放的是get請求攜帶過來的數據
request.POST  # 你就把它當成一個大字典 裏面放的是post請求攜帶過來的數據
"""上面的大字典 全部的value都是一個列表"""
    
request.GET.get('key')  # 默認取的是列表的最後一個元素 並非直接將列表取出
request.GET.getlist('key')  # 直接將value的列表取出


request.POST.get('key')  # 默認取的是列表的最後一個元素 並非直接將列表取出
request.POST.getlist('key')  # 直接將value的列表取出

pycharm鏈接數據庫(pycharm充當數據庫的客戶端)

點擊database,添加數據庫

Django鏈接數據庫

Django自帶一個小型的sqlite3數據庫....該數據庫功能不是很強大 尤爲是對日期格式的數據 不是很兼容

​ Django鏈接MySQL

​ 1. 配置文件

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', # 指定數據庫
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), # 究竟是用哪一個庫
     'USER':'root',
   'PASSWORD':'root',
   'HOST':'127.0.0.1',
   'PORT':3306,
   'CHARSET':'utf8'
}
}

如今已經再也不使用MySQLdb模塊,可是默認仍是使用MySQLdb 鏈接數據庫,因此告訴Django不要使用MySQLdb,而是改用pymysql 鏈接

在項目名稱下邊的__init__.py也能夠在應用名下面的__init__.py文件中指定
import pymysql
pymysql.install_as_MySQLdb()

Django orm簡介

​ orm對象關係映射

​ 類 數據庫的表

​ 對象 表的記錄

​ 對象獲取屬性 記錄的某個字段對應的值

優勢: 可以讓一個不會數據庫操做的人也可以簡單快捷的去使用數據庫

缺點: 因爲封裝程度過高,可能會致使sql語句的執行效率變低

有時候結合項目需求可能須要你手寫sql語句

注意事項:

1. django的orm不會自動幫你建立庫,須要你手動指定一個django項目用一個數據庫
2. 表會自動幫你建立,你只須要書寫符合Django orm語法的代碼便可
from django.db import models
# Create your models here.
class Userinfo(models.Model):
# 設置id字段爲userinfo表的主鍵  id int primary key auto_increment
id = models.AutoField(primary_key=True) # 在django中 你能夠不指定主鍵字段 django orm會自動給你當前表新建一個名爲id的主鍵字段    # 設置username字段  username varchar(64)  CharField必需要指i定max_length參數
username = models.CharField(max_length=32)  # 在django orm中 沒有char字段  可是django 暴露給用戶 能夠自定義char字段    # 設置password字段  password int
password = models.IntegerField()

數據庫遷移(同步)命令:

  1. python manage.py makemigrations # 不會建立表 僅僅是生成一個記錄 將你當前的操做記錄到一個小本本上(migrations文件夾)

  2. python manage.py migrate # 將你的orm語句真正的遷移到(同步)到數據庫中

  3. 只要你在models.py中修改了跟數據庫相關的代碼 你就必須從新開始執行上面兩條命令

當你第一次執行上面兩條命令的時候 django會自動建立不少張表 這些表都是django默認須要用到的表
你本身寫的模型類所對應的表 表名有固定格式
應用名_表名

字段的增刪改查

增:

在項目的modles文件夾下
 phone = models.BigIntegerField(default=110)  # 新增的字段 能夠提早設置默認值 
addr = models.CharField(max_length=64,null=True)  # 新增的字段 能夠設置爲空

新增的字段
1.直接提供默認值 default
2.設置改字段能夠爲空 null=True
注意的是 不要輕易的註釋models.py中任何跟數據庫相關的代碼
主要是跟數據庫相關的代碼 你在處理的時候必定要當心謹慎

數據的增刪改查

表記錄的增改查:

能夠再客戶端瀏覽器顯示

{# 模板語法註釋 #},不能在網頁顯示,只能在後端顯示,

數據的查:

​ get()

​ 1. 條件存在的狀況下,獲取的直接是數據對象的自己

​ 2. 條件不存在的狀況下,會直接報錯,因此不推薦使用get方法查詢數據

filter()
  1. 條件存在的清華況下獲取的是一個能夠當作列表的數據,列表裏面放的纔是一個個數據
    1. 條件不存在的狀況下,並不會報錯,會返回一個能夠當作空列表的數據
    2. filter括號內能夠寫多個參數逗號隔開這多個參數在查詢的時候 是and關係
  2. filter的結果支持索引取值 可是不支持負數 而且不推薦你使用索引 推薦你使用它封裝好的方法 first取第一個數據對象數據的增

數據的增

##### 1. create()

1. 括號內寫關鍵字參數的形式,建立數據
        2. 該方法會有一個返回值,返回值就是當前的對象前身。

##### 2. 利用對象點方法的方式

user_obj = User(username='jason')

user_obj.save()  # 將當前對象保存到數據庫中

改:

def edit_user(request):
  # 1.如何獲取用戶想要編輯的數據
  edit_id = request.GET.get('edit_id')
  if request.method == 'POST':
    # 將用戶新修改的全部的數據
    username = request.POST.get("username")
    password = request.POST.get("password")
    """POST中也是能夠獲取GET請求攜帶的參數""" 
    # 去數據庫中修改對應的數據 
    # 方式1:        models.Userinfo.objects.filter(pk=edit_id).update(username=username,password=password)# 批量更新
    # 方式2: 獲取當前數據對象 而後利用對象點屬性的方式 先修改數據  而後調用對象方法保存
    # 不推薦你使用第二種方式  效率低   挨個從新寫入一遍
     edit_obj = models.Userinfo.objects.filter(pk=edit_id).first()  # pk可以自動幫你查詢出當前表的主鍵字段名
       edit_obj.username = username
       edit_obj.password = password
       edit_obj.save()
        """update方法會將filter查詢出來的queryset對象中全部的數據對象所有更新""" 
        # 跳轉到數據展現頁面
        return redirect('/userlist')
      # 2.根據主鍵值去數據庫中查詢出當前對象 展現給用戶看
      edit_obj = models.Userinfo.objects.filter(pk=edit_id).first()
      # pk可以自動幫你查詢出當前表的主鍵字段名 
      # 3.將查詢出來的數據對象傳遞給前端頁面 展現給用戶看
      return render(request,'edit_user.html',locals())

刪:

def delete_user(request):
  # 獲取想要刪除的數據id 直接刪除
  delete_id = request.GET.get('delete_id')    models.Userinfo.objects.filter(pk=delete_id).delete()  # 批量刪除
  return redirect('/userlist')

圖書管理系統OR表建立:

​ 表與表之間的關係:

​ 一對多:外鍵字段創建在多的一

​ models.Foreignkey(to="關聯的表名") # 自動建表關係,默認就是跟關聯表的主鍵字段

「」「

Foreignkey字段在建立的時候 orm會自動在字段後面加_id

"""

​ 多對多: ManyToManyField(to=「關聯的表名」) # 並不會建立一個實際字段,僅僅是用來告訴django orm自動建立第三張表

​ 一對一:

​ OneToOneField(to="關聯的表名")

​ """

​ OneToOneField字段在建立的時候orm會自動在字段後面加_id

​ """

​ 一對一(做者和做者信息)

​ 一對多(書和出版社)

​ 多對多(書和做者)

​ 圖書表(book):id/title/price/publish_id

​ 出版社表(publish):id/name/ addr

​ 做者表(author): id/name/phone

​ 多對多第三方表:id/book_id/author_id

django請求生命週期

  1. 當用戶在瀏覽器中輸入url時,瀏覽器會生成請求頭和請求體發給服務端請求頭和請求體中會包含瀏覽器的動做(action),這個動做一般爲get或者post,體如今url之中.
  2. url通過Django中的wsgi,再通過Django的中間件,最後url到過路由映射表,在路由中一條一條進行匹配, 一旦其中一條匹配成功就執行對應的視圖函數,後面的路由就再也不繼續匹配了.
  3. 視圖函數根據客戶端的請求查詢相應的數據.返回給Django,而後Django把客戶端想要的數據作爲一個字符串返回給客戶端.
    4.客戶端瀏覽器接收到返回的數據,通過渲染後顯示給用戶.


路由層 urls.py

路由匹配

urls.py: 路由與視圖函數的對應關係》》》路由層

  1. urls.py 的第一個參數是正則,
  2. 一旦匹配上會馬上執行對應的視圖函數,再也不往下匹配了
  3. APPEND_SLASH = False # 控制url後面不自動增長斜槓
  4. APPEND_SLASH = True # 默認是True自動加斜槓
  5. ^ & # 上升號表示限制開頭,&表示限制結尾,放在一塊兒能夠限制一個獨一無二的字符,用於首頁
  6. url(r'', admin.site.urls) # 空表示接受所有的,不會在往下走,直接攔截住。url(r'', views.errors) # 用於尾頁

有名與無名分組

無名分組
urlpatterns = [
  url(r'^test/(\d+)/', views.test)
]  
會將括號內的內容當作位置參數傳遞給後面的視圖函數test(reqiest, args)
在調用視圖函數test的時候 會將\d+匹配到的內容 當作位置參數傳遞給test


有名分組(給正則表達式定義別名)
urlpatterns = [
  url(r'^test/(?P<month>\d+)/', views.test)
]  
定義了別名month
會將括號內的內容當作關鍵字傳遞給後面的視圖函數test(request, month=123)
在調用視圖函數test的時候 會將\d+匹配到的內容 當作關鍵字參數(month='')傳遞給test
views內定義的形參必須是month

無名和無名不能結合使用,可是能夠單獨使用.
有名無名單獨使用的狀況下  能夠用多個

注意:+表示(1-無窮大)*(0-無窮大)?(0-1)

反向解析

​ 根據某一個東西動態解析出一個結果,該結果能夠直接訪問對應的url。

給路由與視圖函數對應關係 起一個別名 後續根據這個別名 就可以動態解析出所對應的url。

url(r'^test_add/', views.testadd,name='xxx')

起別名 別名必定不要重複

  1. 前端解析

    {% url 'xxx' %}

    222

  2. 後端解析

from django.shortcuts import render,HttpResponse,redirect,reverse

url = reverse('修更名')

有名和無名反向解析
<a href="{% url 'xxx' year=1 %}">222</a>
<a href="{% url 'xxx' 1 %}">222</a>
url = reverse('xxx', args=(1,))
url = reverse('xxx', kwargs=('year':231,))

經過名字可以動態表達出一個結果,這個結果可以訪問到這個名字對應的url

url(r'^edit_user/(\d+)/',views.edit_user,name='edit')
user_queryset = models.User.objects.all()
{% for user_obj in user_queryset %}
<td>
<a href="{% url 'edit' user_obj.pk %}">編輯</a>
<a>刪除</a>
</td>{% endfor %}def edit(request,edit_id):
pass

注意: 反向解析的別名必定不能重複

路由分發

​ Django裏面的APP能夠有本身的static文件,templates文件夾,urls.py等。正是因爲上述的特色 你基於django開發項目 就真正能夠作到分組分功能分模塊獨立的去開發。

注意:當應用特別多的時候 總路由中的代碼過於冗長 很差維護

​ 項目名下的urls.py再也不作路由與視圖函數對應關係了,而是作一箇中轉站,只負責將請求分發到不一樣的app中

在APP的urls.py 完成路因爲視圖函數的對應關係

from django.conf.urls import url,include

url(r'^app01/',include(app01_urls)),
url(r'^app02/',include(app02_urls))

# 1.在應用下本身手動建立urls.py
# 2.在路由中導入 
# 1
from app01 import urls as app01_urls
from app02 import urls as app02_urls
                
url(r'^app01/',include(app01_urls)),
url(r'^app02/',include(app02_urls))
# 2
url(r'^app01/',include('app01.urls')),
url(r'^app02/',include('app02.urls'))

名稱空間

總路由
url(r'^app01/',include('app01.urls',namespace='app01'))
url(r'^app02/',include('app02.urls',namespace='app02'))

print(reverse('app01:index'))
    print(reverse('app02:index'))

由於起別名衝突纔用到名稱空間,因此一般狀況下 起別名的時候 前面能夠加上你的應用名

僞靜態

url看起來像是一個靜態頁面(.html結尾)

將動態網頁僞裝成靜態的

這樣作能夠提升搜索引擎的SEO查詢優先級

搜索在收錄網站的時候會優先收錄看上去像是靜態文件的資源

可是不管你怎麼使用僞靜態進行優化 你也幹不過RMB玩家(參考百度)

虛擬環境

​ 不一樣的項目應該有各自獨立的解釋器環境 最大化節省資源
​ 實際功能中針對不一樣的項目 會有一個叫requestsments.txt文件
​ 該文件中列出來是一個個該項目須要用的到模塊名和版本號
​ eg:
django = 1.11.11
nginx = 1.21
​ 後期經過命令直接會去下載該文件內全部的模塊及對應版本
​ 每建立一個虛擬環境,就相似於從新下載一個純淨的python解釋器環境

​ 虛擬環境會佔用硬盤資源,因此不要建立太多。

Django版本的區別

####    Django1.x

####    Django2.x

區別:

urls.py中1.x用的是url,而2.x用的是path

而且2.x中的path第一個不支持正則表達式,寫什麼就匹配什麼

若是你以爲很差用,2.x裏面還有re_path 這個re_path就是你1.x裏面的url

Django之視圖層

視圖函數

三板斧:
  1. HttpResponse # 返回字符串

  2. render # 返回一個html頁面 還能夠給模板傳遞

    from django.template import Template,Context
                    def index(request):
                        res = Template("<h1> {{ user }} </h1>")
                        con = Context({'user':{'username':'jason','pwd':'123'}})
                        ret = res.render(con)
                        print(ret)
                        return HttpResponse(ret)
  3. redirect # 重定向

JsonResponse

​ 返回json格式數據

​ 爲何要給前端回json 格式字符串

​ 先後端分離 就是基於json格式傳輸數據的

​ 後端給前端返回一個json的格式的字符串(至關於反悔了一個大字典)

​ 而後前端利用序列化反序列化轉換成前端對應的數據類型

​ js經常使用數據類型:

​ 數值類型
​ 字符類型
​ 數組
​ 自定義對象
​ undefined與null
​ 布爾值
​ symbol

​ JSON.stringify 序列化 >>> json.dumps

​ JSON.parse 反序列 >>> json.loads

FBV與CBV

FBV (Function Based View) 基於函數的視圖

CBV (Class Based View) 基於類的視圖

CBV 的請求流程

當服務端使用cbv模式的時候,用戶發給服務端的請求包含urI和method,這兩個信息都是字符串類型
服務端經過路由映射表匹配成功後會自動去找dispatch方法,而後Django會經過dispatch反射的方式找到類中對應的方法並執行
類中的方法執行完畢以後,會把客戶端想要的數據返回給dispatch方法,由dispatch方法把數據返回經客戶端

在類中寫的兩個方法(get和post)

get請求會觸發get方法,post請求會觸發post方法

url(r'^reg/',views.MyReg.as_view()),
# url(r'^reg/',views.view)
# CBV和FBV在路由匹配上 規則都是同樣的 都是路由後面跟的函數的內存地址

CBV結合源碼

# CBV路由
url(r'^reg/',views.MyReg.as_view())(經過as_view進入源碼)

@classonlymethod
def as_view(cls, **initkwargs):
  def view(request, *args, **kwargs):
    self = cls(**initkwargs)  # cls就是咱們本身的寫的MyReg類
    if hasattr(self, 'get') and not hasattr(self, 'head'):
      self.head = self.get
      self.request = request
      self.args = args
      self.kwargs = kwargs
      # 上面的一通操做 就是給咱們本身寫的類的對象賦值
      return self.dispatch(request, *args, **kwargs)
    # 對象在查找屬性或方法的時候 順序是什麼?  先從本身找 再從產生對象的類中找  再去類的父類中找...
    """也就意味着你在看源碼的時候 你必定要牢記上面的話"""
    return view

  # views.py 
  from django.views import View


  class MyReg(View):
    def get(self,request):
      return render(request,'reg.html')

    def post(self,request):
      return HttpResponse("我是MyReg類中post方法")


    """CBV最精髓的部分"""
    def dispatch(self, request, *args, **kwargs):
      if request.method.lower() in self.http_method_names:  # 判斷當前請求方式在不在默認的八個請求方式中
        handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        # handler = getattr(本身寫的類產生的對象,'小寫的請求方法(get\post)','獲取不到對應的方法就報錯')
        # handler就是咱們本身定義的跟請求方法相對應的方法的函數內存地址
        else:
          handler = self.http_method_not_allowed
          return handler(request, *args, **kwargs)  # 在調用獲取到的方法

CBV說明1:

在url中會執行一個叫作as_view的方法,這個方法在加載url時候會執行 獲得一個返回值view 是一個函數 供url調用,

當url執行view時候,會把下邊這句代碼做爲返回值

self.dispatch(request, *args, **kwargs)

所view 會調用當前調用類的dispatch

CBV說明2:

在執行dispatch的時候,若是views中的視圖類 自定義了dispatch那麼將優先執行自定義的dispatch 由此可在請求處理前增長一些處理,

而後再用super方法去調用父類的dispatch ,固然也能夠本身把父類的功能所有寫在本身的自定義裏邊。

簡單的說-----分發

複雜的說-----找到此次請求對應的類型,而後用反射把這個方法取到,而後做爲本身的返回值,返回給調用這個方法的view

方式二:

案例:
urls.py

from django.urls import path,register_converter,re_path
from app01 import views
urlpatterns = [
 re_path(r'^login/',views.LoginView.as_view()), # 必須調用類下的方法as_view
]

views.py

from django.shortcuts import render,HttpResponse,redirect
from django.views import View
class LoginView(View):
    def dispatch(self, request, *args, **kwargs): # 可在該方法內作一些預處理操做
  # 當請求url爲:http://127.0.0.1:8008/login/會先觸發dispatch的執行

    # 若是http協議的請求方法爲GET,則調用下述get方法

    # 若是http協議的請求方法爲POST,則調用下述post方法
   obj=super().dispatch(request, *args, **kwargs) # 必須繼承        父類的dispatch功能
        return obj # 必須返回obj
        def get(self,request):
        return render(request,'login.html')
        def post(self,request):
        name=request.POST.get('name')
         pwd=request.POST.get('pwd')
         if name == 'egon' and pwd == '123':
         res='登陸成功'
         else:
         res='用戶名或密碼錯誤'
         return HttpResponse(res)

測試:

python manage.py runserver 8001

# 驗證GET請求:在瀏覽器輸入:http://127.0.0.1:8001/login/

# 驗證POST請求:在表單內輸入數據而後提交

Django源碼分析及實際應用

django的配置文件有兩個
    一個是暴露給用戶能夠自定義配置的
    一個是默認的全局配置文件
        用戶指定了就用用戶的
        用戶沒有指定就用默認的

from django.conf import settings

settings = LazySettings()

class LazySettings(LazyObject):

  def _setup(self, name=None):

    # os.environ你能夠把它當作是一個全局的大字典
    settings_module = os.environ.get(ENVIRONMENT_VARIABLE)  # 從大字典中取值
    # settings_module = 'day59.settings'

    self._wrapped = Settings(settings_module)  # Settings('day59.settings')

    class Settings(object):
      def __init__(self, settings_module):  # settings_module = 'day59.settings'
        for setting in dir(global_settings):  # 循環獲取global_settings文件中全部的名字
          if setting.isupper():  # 在判斷名字是不是大寫
            # 若是是大寫 利用反射 獲取到大寫的名字所對應的值  不停地添加到對象中
            setattr(self, setting, getattr(global_settings, setting))
            # store the settings module in case someone later cares
            self.SETTINGS_MODULE = settings_module
            mod = importlib.import_module(self.SETTINGS_MODULE)  # 'day59.settings'
            # from day59 import settings
            # mod 指代的就是暴露給用戶的配置文件模塊名

            for setting in dir(mod):  # 循環獲取暴露給用戶配置文件中全部的名字
              if setting.isupper():  # 判斷是不是大寫
                setting_value = getattr(mod, setting)  # 若是是大寫 獲取大寫的變量名所對應的值
                setattr(self, setting, setting_value)  # 不停的給對象設置值

思考:基於django settings源碼 實現本身的項目也有兩個配置文件 一個是暴露給用戶的一個是項目默認
用戶配置了 就用用戶的
用戶沒有配置 就用默認的
django settings源碼
django暴露給用戶一個自定義配置的文件 
用戶配置了就用用戶的 用戶沒有配置就使用默認的  而且配置文件中的變量名必須是大寫纔有效
from django.conf import settings

settings = LazySettings()

class LazySettings(object):
  ...

  class Settings(object):
    # 循環獲取默認的配置文件中全部的大寫配置
    # 利用setattr給對象不停的設置鍵值對
    # 再循環獲取暴露給用戶的自定義配置文件中全部的大寫的配置
    # 再利用setattr給對象不停的設置鍵值對
    """字典的鍵存在的狀況 再設值其實就是替換"""

Django之模板

爲將前端頁面和Python的代碼分離, Django專門提供了模板系統 (Template System,即模板層)來實現 django的模板=HTML代碼+模板語法 .

存放於templates目錄下的html文件稱之爲模板文件,若是咱們想要返回的html頁 面中的數據是動態的,那麼必須在html頁面中嵌入變量,這便用到了django的模 板語法。

模板層

{{}}變量相關

{%%}邏輯相關

模板傳值

傳函數名的時候 會自動加括號調用函數 將函數的返回值展現在html頁面上

django模板語法不支持函數傳參

django模板語法在獲取容器類型內部元素的值的時候 統一隻採用 句點符(.)

#### 1. 變量:{{ 變量名 }}

若是html代碼中的數據不是固定死的,而是動態變化的,則必須在html中嵌入變 量,爲此,模板語法提供了變量的概念,容許咱們在html代碼中嵌入變量,咱們 只須要在視圖函數中用render方法爲html文件中指定的變量賦值便可

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Title</title>
</head>
<body>
<p>{{ msg }}</p>
<p>{{ dic }}</p>
<p>{{ obj }}</p>
<p>{{ li }}</p>
</body>
</html>

咱們須要在視圖函數中爲模板test.html的變量名msg、li、dic、obj、obj_li賦值,views.py內容以下

from django.shortcuts import render
def test(request):

# 傳給模板的變量值能夠是任意python類型,以下

 msg='hello world'
 dic={'k1':1,'k2':2}
 class Person(object):
 def __init__(self,name,age):
 self.name=name
 self.age=age
 obj=Person('egon',18)
 li = [1,'aaa',obj]
 return render(request,'test.html',{'msg':msg,'dic':dic,'obj':obj,'li':li})

# 注意:

# 一、render函數的第三個參數包含了要傳給模板的變量值,是一個字典類型,該字典中的key必須與模板文件中

的變量名相對應,render函數會去templates目錄下找到模板文件,而後根據字典中的key對應到模板文件中的變量名
進行賦值操做,最後將賦值後的模板文件內容返回給瀏覽器

# 二、能夠將render函數的第三個參數簡寫爲locals(),以下

 return render(request,'test.html',locals()) #locals()會將函數test內定義的名字與值轉換爲字
典中的k與v
深度查詢:句點符的應用

當視圖函數傳給模板的值中包含多個元素時,若想取出其中的單個元素,就必須
使用句點符了。
句點符既能夠引用容器類型的元素,也能夠引用對象的方法,以下

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Title</title>
</head>
<body>
<!--調用字符串對象的upper方法,注意不要加括號-->
<p>{{ msg.upper }}</p>
<!--取字典中k1對應的值-->
<p>{{ dic.k1 }}</p>
<!--取對象的name屬性-->
<p>{{ obj.name }}</p>
<!--取列表的第2個元素,而後變成大寫-->
<p>{{ li.1.upper }}</p>
<!--取列表的第3個元素,並取該元素的age屬性-->
<p>{{ li.2.age }}</p>
</body>
</html>
過濾器

過濾器相似於python的內置函數,用來把視圖傳入的變量值加以修飾後再顯示,
具體語法以下

{{ 變量名|過濾器名:傳給過濾器的參數 }}

經常使用內置過濾器

一、default
做用:若是一個變量值是False或者爲空,使用default後指定的默認值,不然,使用變量自己的值,若是
value=’‘則輸出「nothing」
{{ value|default:"nothing" }}
二、length
做用:返回值的長度。它對字符串、列表、字典等容器類型都起做用,若是value是 ['a', 'b', 'c', 'd'],那麼輸出是4
{{ value|length }}

三、filesizeformat
#做用:將值的格式化爲一個"人類可讀的"文件尺寸(如13KB、4.1 MB、102bytes等等),若是 value 是
12312312321,輸出將會是 11.5 GB
{{ value|filesizeformat }}

四、date
做用:將日期按照指定的格式輸出,若是value=datetime.datetime.now(),按照格式Y-m-d則輸出2019-02-02
{{ value|date:"Y-m-d" }}

五、slice
做用:對輸出的字符串進行切片操做,顧頭不顧尾,若是value=「egon「,則輸出"eg"
{{ value|slice:"0:2" }}

六、truncatechars
做用:若是字符串字符多於指定的字符數量,那麼會被截斷。截斷的字符串將以可翻譯的省略號序列(「...」)結尾,
若是value=」hello world egon 嘎嘎「,則輸出"hello...",注意8個字符也包含末尾的3個點
{{ value|truncatechars:8 }}

七、truncatewords
做用:同truncatechars,但truncatewords是按照單詞截斷,注意末尾的3個點不算做單詞,若是value=」
hello world egon 嘎嘎「,則輸出"hello world ..."
{{ value|truncatewords:2 }}

八、safe(前端)
做用:出於安全考慮,Django的模板會對HTML標籤、JS等語法標籤進行自動轉
義,例如value="<script>alert(123)</script>",模板變量
{{ value }}會被渲染成&lt; script&gt;alert(123)&lt;/script&gt;交給瀏覽器後會被解析成普通字符」<script>alert(123)</script>「,
失去了js代碼的語法意義,但若是咱們就想讓模板變量{{ value }}被渲染的結果又要有語法意義,那麼就用到了過濾器safe,
好比value='<a href="https://www.baidu.com">點我啊</a>',
在被safe過濾器處理後就成爲了真正的超連接,不加safe過濾器則會當作普通字符顯示’<a href="https://www.baidu.com">點我啊</a>‘
{{ value|safe }}
過濾器 描述 示例
upper 以大寫方式輸出 {{ user.name|upper}}
add 給value加上一個數值 {{ user.age|add:」5」 }}
addslashes 單引號加上轉義號
capfirst 第一個字母大寫 {{ ‘good’|capfirst }} 返回」Good」
center 輸出指定長度的字符串,把變量居中 {{ 「abcd」|center:」50」 }}
cut 刪除指定字符串 {{ 「You are not a Englishman」|cut:」not」 }}
date 格式化日期
default 若是值不存在,則使用默認值代替 {{ value|default:」(N/A)」 }}
default_if_none 若是值爲None, 則使用默認值代替
dictsort 按某字段排序,變量必須是一個dictionary {% for moment in moments|dictsort:」id」 %}
dictsortreversed 按某字段倒序排序,變量必須是dictionary
divisibleby 判斷是否能夠被數字整除 {{ 224|divisibleby:2 }} 返回 True
escape 按HTML轉義,好比將」<」轉換爲」&lt」
filesizeformat 增長數字的可讀性,轉換結果爲13KB,89MB,3Bytes等 {{ 1024|filesizeformat }} 返回 1.0KB
first 返回列表的第1個元素,變量必須是一個列表
floatformat 轉換爲指定精度的小數,默認保留1位小數 {{ 3.1415926|floatformat:3 }} 返回 3.142 四捨五入
get_digit 從個位數開始截取指定位置的數字 {{ 123456|get_digit:’1’}}
join 用指定分隔符鏈接列表 {{ [‘abc’,’45’]|join:’’ }} 返回 abc45
length 返回列表中元素的個數或字符串長度
length_is 檢查列表,字符串長度是否符合指定的值 {{ ‘hello’|length_is:’3’ }}
linebreaks

標籤包裹變量
{{ 「Hi\n\nDavid」|linebreaks }} 返回
Hi
David
linebreaksbr 用標籤代替換行符
linenumbers 爲變量中的每一行加上行號
ljust 輸出指定長度的字符串,變量左對齊 {{‘ab’|ljust:5}}返回 ‘ab ’
lower 字符串變小寫
make_list 將字符串轉換爲列表
pluralize 根據數字肯定是否輸出英文複數符號
random 返回列表的隨機一項
removetags 刪除字符串中指定的HTML標記 {{value|removetags: 「h1 h2」}}
rjust 輸出指定長度的字符串,變量右對齊
slice 切片操做, 返回列表 {{[3,9,1]|slice:’:2’}} 返回 [3,9]{{ 'asdikfjhihgie'|slice:':5' }} 返回‘asdik’
slugify 在字符串中留下減號和下劃線,其它符號刪除,空格用減號替換 {{ '5-2=3and5 2=3'|slugify }} 返回 5-23and5-23
stringformat 字符串格式化,語法同python
time 返回日期的時間部分
timesince 以「到如今爲止過了多長時間」顯示時間變量 結果可能爲 45days, 3 hours
timeuntil 以「從如今開始到時間變量」還有多長時間顯示時間變量
title 每一個單詞首字母大寫
truncatewords 將字符串轉換爲省略表達方式 {{ 'This is a pen'|truncatewords:2 }}返回``This is ...
truncatewords_html 同上,但保留其中的HTML標籤 {{ '<p>This is a pen</p>'|truncatewords:2 }}返回``<p>This is ...</p>
urlencode 將字符串中的特殊字符轉換爲url兼容表達方式 {{ ‘http://www.aaa.com/foo?a=b&b=c’|urlencode}}
urlize 將變量字符串中的url由純文本變爲連接
wordcount 返回變量字符串中的單詞數
yesno 將布爾變量轉換爲字符串yes, no或maybe |{{ True|yesno }}{{ False|yesno }}{{None|yesno }} 返回yesnomaybe

2. 標籤:{% 標籤名 %}

標籤是爲了在模板中完成一些特殊功能,語法爲{% 標籤名 %},一些標籤還須要搭 配結束標籤 {% endtag %}

經常使用標籤之for標籤
一、遍歷每個元素:
{% for person in person_list %}
    <p>{{ person.name }}</p>
{% endfor %} 
二、能夠利用{% for obj in list reversed %}反向循環。
三、遍歷一個字典: {% for key,val in dic.items %}  
    <p>{{ key }}:{{ val }}</p>
{% endfor %}
四、循環序號能夠經過{{ forloop }}顯示
forloop.counter 當前循環的索引值(從1開始)
forloop.counter0 當前循環的索引值(從0開始)
forloop.revcounter 當前循環的倒序索引值(從1開始) forloop.revcounter0 當前循環的倒序索引值(從0開始)
forloop.first 當前循環是第一次循環則返回True,不然返回False forloop.last 當前循環是最後一次循環則返回True,不然返回False forloop.parentloop 本層循環的外層循環
五、for標籤能夠帶有一個可選的{% empty %} 從句,在變量person_list爲空或者沒有被找到時,則執行empty子 句
{% for person in person_list %}  
    <p>{{ person.name }}</p>
{% empty %}
if 判斷
# 一、注意:
{% if 條件 %}條件爲真時if的子句纔會生效,條件也能夠是一個變量,if會對變量進行求值,在變量值爲空、或者視圖沒有爲其傳值的狀況下均爲False
{% if xo %}
    <p>xo有值</p>
{% else %}
    <p>xo沒有值</p>
{% endif %}

{% if xo %}
    <p>xo有值</p>
{% elif xo1 %}
    <p>xo1有值</p>
{% else %}
    <p>去他大爺的</p>
{% endif %}

if語句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判斷。

3. 自定義標籤和過濾器

自定義過濾器

當內置的過濾器或標籤沒法知足咱們需求時,咱們能夠自定義,具體操做步驟以下

  1. 在settings中的INSTALLED_APPS添加當前app的名字,否則django沒法找到自定義的過濾器或標籤

settings.py

# 在settings.py中找到該列表,而後加以配置
INSTALLED_APPS = [
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'app01.apps.App01Config',
 'app01', # 添加當前app的名字
]
  1. 在應用名下面新建一個templatetags文件夾(必須叫這個名字)

  2. 在該文件夾下 新建一個任意名稱的py文件,在該py文件內自定義過濾器或標籤

from django import template
register = template.Library() # 注意變量名必須爲register,不可改變
#一、自定義過濾器
@register.filter
def my_multi_filter(v1 ,v2): # 自定義的過濾器只能定義最多兩個參數,針對{{ value1 |filter_multi:value2 }},參數傳遞v1=value1,v2=value2
 return v1 * v2
#二、自定義標籤
@register.simple_tag
def my_multi_tag(v1, v2): # 自定義的標籤能夠定義多個參數
 return v1 * v2
#三、自定義標籤擴展之mark_safe
# 註釋:咱們能夠用內置的標籤safe來讓標籤內容有語法意義,若是咱們想讓自定義標籤處理的結果也有語法意義,則不能使用內置標籤safe了,須要使用mark_safe,能夠實現與內置標籤safe一樣的功能
from django.utils.safestring import mark_safe
@register.simple_tag
def my_input_tag(id, name):
   res = "<input type='text' id='%s' name='%s' />" % (id, name)
    return mark_safe(res)
  1. 自定義過濾器或標籤必須從新啓動django方可生效
  2. 自定義過濾器或標籤的使用
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--必須先加載存有自定義過濾器和標籤的文件-->
{% load my_tags %} 
<!--salary的值爲10, 通過濾器my_multi_filter的處理結果爲120-->
{{ salary|my_multi_filter:12 }}
<!--結果爲2-->
{% my_multi_tag 1 2 %}
<!--結果爲一個input標籤,該表的屬性id="inp1" name="username"
注意: input的的屬性值均爲字符串;類型,因此my_input_tag後的;兩個值均爲字符串類型-->
{% my_input_tag "inp1" "username" %}
</body>
</html>
對比自定義標籤與自定義過濾器
#一、自定義過濾器只能傳兩個參數,而自定義標籤卻能夠傳多個參數
#二、過濾器能夠用於if判斷,而標籤不能
{% if salary|my_multi_filter:12 > 200 %}
{% else %}   {% endif %}

4. 模板的導入和繼承

在實際開發中,模板文件彼此之間可能會有大量冗餘代碼,爲此django提供了專 門的語法來解決這個問題,主要圍繞三種標籤的使用:include標籤、extends標籤、 block標籤.

模板的導入之include標籤
#做用:在一個模板文件中,引入/重用另一個模板文件的內容,
{% include '模版名稱' %}

事先須要再模板中 經過block劃定區域
{% block 區域名字 %}

{% endblock %}
子板中如何使用
{% extends '模板的名字'%}

{% block 區域名字 %}
<h1>登陸頁面</h1>
{% endblock %}

一個頁面上 block塊越多 頁面的擴展性越高
一般狀況下 都應該有三片區域
{% block css %}

{% endblock %}

{% block content %}

{% endblock %}

{% block js %}

{% endblock %}

子板中還能夠經過
{{ block.super }}  來繼續使用母版的內容

模板的導入
    當你寫了一個特別好看的form表單 你想再多個頁面上都使用這個form表單
    你就能夠將你寫的form表單看成模塊的形式導入 導入過來以後 就能夠直接展現
    
    {% include 模塊名 %}

模型層

ORM查詢

若是要查詢orm語句內部真正的sql語句有兩種方式

  1. 若是是queryset對象,能夠直接點query查看
  2. 配置文件中 直接配置
LOGGING = {
  'version': 1,
  'disable_existing_loggers': False,
  'handlers': {
    'console': {
      'level': 'DEBUG',
      'class': 'logging.StreamHandler',
    },
  },
  'loggers': {
    'django.db.backends': {
      'handlers': ['console'],
      'propagate': True,
      'level': 'DEBUG',
    },
  }}

只要是queryset對象就能夠無限制的點queryset對象的方法

如:queryset.filter().filter().filter()

​ Django測試環境搭建

django測試環境搭建
import os


if __name__ == "__main__":
  os.environ.setdefault("DJANGO_SETTINGS_MODULE", "one_search.settings")
  import django
  django.setup()
  # 能夠在下面測試django任何的py文件

補充(知道就行):

import os


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "one_search.settings")
    import django
    django.setup()
    from app01 import models
    res = models.Book.objects.all()  # 惰性查詢,你不去找他要,他就一直不顯示
    print(res)
運行後若是數據庫中的表沒有數據,會提示,其中LIMIT表示限制一次拿多少條(參考分頁)

單表查詢

1 、models.Book.objects.create(title='西遊記',price=123.23,publish_date='2019-      10-24')

二、from datetime import date
    ctime = date.today()
    book_obj = models.Book(title='三國演義',price=666.66,publish_date=ctime)
    book_obj.save()
一、models.Book.objects.filter(pk=3).update(price=999.66)

二、book_obj = models.Book.objects.filter(pk=3).first()
    book_obj.title = '在這兒改數據'
    book_obj.save()
models.Book.objects.filter(pk=3).delete()
查13條:

#1: .all() 查詢全部
# 無參

# 返回值爲QuerySet對象,QuerySet對象中包含了查詢出的全部記錄對象
  res = models.Book.objects.all()  # 惰性查詢
  print(res)
  for i in res:
    print(i.title)
# 打印:
res = <QuerySet [<Book: 就是要改你>, <Book: 三國演義>]>
i.title = 就是要改你,三國演義
    
  
#2: filter() 過濾                 QuerySet
# 有參,參數爲過濾條件
# 返回值爲QuerySet對象,QuerySet對象中包含了符合過濾條件的多個記錄對象
  res = models.Book.objects.filter(pk=3)# 惰性查詢
  print(res) 
# 打印: <QuerySet [<Book: 就是要改你>]>



#3: get(**kwargs)                               數據對象自己
#  有參,參數爲篩選條件
#  返回值爲一個符合篩選條件的記錄對象(有且只有一個),若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
    res = models.Book.objects.get(pk=3)
    print(res)
# 打印:就是要改你   
    
    
#4:first()                                拿第一個
    # 無參
    # 返回查詢出的第一個記錄對象
    res = models.Book.objects.all()
    print(res)
    print(res.first())
# 打印: <QuerySet [<Book: 就是要改你>, <Book: 三國演義>]>    就是要改你   
  
  
#5: last()      拿最後一個   
#  無參
# 返回查詢出的最後一個記錄對象
    res = models.Book.objects.all()
    print(res)
    print(res.last())
# 打印: <QuerySet [<Book: 就是要改你>, <Book: 三國演義>]>    三國演義
    
    
    
# 6.exclude  除此以外        QuerySet
#  有參,參數爲過濾條件
#  返回值爲QuerySet對象,QuerySet對象中包含了不符合過濾條件的多個記錄對象
res = models.Book.objects.exclude(pk=3).filter(pk=4).filter(pk=1).filter(pk=4)
print(res)
# 打印: <QuerySet []>


# 7.values  QuerySet    列表套字典
# 有參,參數爲字段名,能夠指定多個字段
# 返回值爲QuerySet對象,QuerySet對象中包含的並非一個個的記錄對象,而上多個字典,字典的key即咱們傳入的字段名
    res = models.Book.objects.values('title')
    for r in res:
        print(r.get('title'))
# 打印: <QuerySet [{'title': '就是要改你'}, {'title': '三國演義'}]>   就是要改你  三國演義

 
 
# 8.values_list  QuerySet    列表套元組
# 有參,參數爲字段名,能夠指定多個字段
# 返回值爲QuerySet對象,QuerySet對象中包含的並非一個個的記錄對象,而上多個小元組,字典的key即咱們傳入的字段名
    res = models.Book.objects.values_list('title')
    print(res)
# 打印: <QuerySet [('就是要改你',), ('三國演義',)]>


# 9.count()  統計數據的個數
# 無參
# 返回包含記錄對象的總數量
    res = models.Book.objects.count()
    res1 = models.Book.objects.all().count()
    print(res,res1)
# 打印:  2 2
    

# 10.distinct() 去重
# 若是使用的是Mysql數據庫,那麼distinct()無需傳入任何參數
# 從values或values_list的返回結果中剔除重複的記錄對象,返回值爲QuerySet對象
"""去重:數據必須是如出一轍的狀況下才能去重"""
    res = models.Book.objects.all().distinct()
    res1 = models.Book.objects.values('title','price').distinct()
    print(res1)
# 打印: <QuerySet [{'title': '就是要改你', 'price': Decimal('999.66')}, {'title': '三國演義', 'price': Decimal('666.66')}]>



# 11.order_by()
# 有參,參數爲排序字段,能夠指定多個字段,在字段1相同的狀況下,能夠按照字段2進行排序,以此類推,默認升序排列,在字段前加橫杆表明降序排(如"-id")
# 返回值爲QuerySet對象,QuerySet對象中包含了排序好的記錄對象
     res = models.Book.objects.order_by('price')  # 默認是升序
     res1 = models.Book.objects.order_by('-price')  # 加負號就是降序
     print(res)
# 打印 看備註


# 12.reverse()  前面必須是先結果排序才能夠反轉
# 無參
# 對排序的結果取反,返回值爲QuerySet對象
    res = models.Book.objects.order_by('price').reverse()
    print(res)
# 打印:<QuerySet [<Book: 就是要改你>, <Book: 三國演義>]>


# 13.exists()
# 無參
# 返回值爲布爾值
         res = models.Book.objects.filter(pk=1).exists()
     print(res)
# 有查詢的數據就返回True,沒有就返回False

神奇的雙下劃線查詢

表:

# 查詢價格大於200的書籍
    res = models.Book.objects.filter(price__gt=200)
    print(res)
# 打印:  <QuerySet [<Book: 就是要改你>, <Book: 三國演義>, <Book: 老人與海>, <Book: 山海經>]>


# 查詢價格小於200的書籍
    res = models.Book.objects.filter(price__lt=200)
    print(res)
# 打印:<QuerySet [<Book: 計算機原理>]>


# 查詢價格大於或者等於200的書籍
    res = models.Book.objects.filter(price__gte=200)
    res1 = models.Book.objects.filter(price__lte=200)
    print(res,res1)
# 打印:    <QuerySet [<Book: 就是要改你>, <Book: 三國演義>, <Book: 老人與海>, <Book: 山海經>]> <QuerySet [<Book: 計算機原理>]>


# 價格是200 或者是123.23 或者666.66
    res = models.Book.objects.filter(price__in=[200,123.23,666.66])
    print(res)
# 打印: <QuerySet []>


# 價格在200 到700之間的書籍
    res = models.Book.objects.filter(price__range=(200,666.66))  # 顧頭不顧尾
    print(res)
# 打印: <QuerySet [<Book: 老人與海>]>

模糊匹配

sql 原生語句使用模糊查詢: like (%:匹配任意個數任意字符和 下劃線 _ :匹配一個任意字符)

# 查詢書籍名稱中包含p的
    res = models.Book.objects.filter(title__contains='p')  # 區分大小寫
    print(res)
# 打印  <QuerySet [<Book: python入門>]>


# 忽略大小寫
    res = models.Book.objects.filter(title__icontains='P')  # 忽略大小寫
    print(res)
# 打印  <QuerySet [<Book: python入門>]>


# 查詢書籍名稱是以三開頭的書籍
  res = models.Book.objects.filter(title__startswith='三')
  print(res)
# 打印  <QuerySet [<Book: 三國演義>]>


# 查詢書籍名稱是以你開頭的書籍
    res = models.Book.objects.filter(title__endswith='你')
  print(res)
# 打印 <QuerySet [<Book: 就是要改你>]>


# 查詢出版日期是2019年的書籍
     res = models.Book.objects.filter(publish_date__year='2017')
     print(res)
# 打印 <QuerySet [<Book: 山海經>]>


# 查詢出版日期是10月的書籍
     res = models.Book.objects.filter(publish_date__month='10')
     print(res)
# 打印 <QuerySet [<Book: 就是要改你>, <Book: 三國演義>, <Book: 老人與海>, <Book: python入門>]>

多表查詢

1. 建表:

from django.db import models

# Create your models here.
"""
你在寫orm語句的時候 跟你寫sql語句同樣
不要想着一次性寫完
寫一點查一點看一點
"""



class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)
    publish_date = models.DateField(auto_now_add=True)

    # 書籍與出版社 是一對多關係
    publish = models.ForeignKey(to='Publish')
    # 書籍與做者 是多對多
    authors = models.ManyToManyField(to='Author')
    """
    authors虛擬字段
        1.告訴orm自動幫你建立第三張關係表
        2.orm查詢的時候  可以幫助你更加方便的查詢
    """

    def __str__(self):
        return self.title


class Publish(models.Model):
    name = models.CharField(max_length=32)
    addr = models.CharField(max_length=64)

    def __str__(self):
        return self.name
    """return返回的數據必須是字符串類型"""



class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    # author_detail = models.ForeignKey(unique=True,to='AuthorDetail')
    author_detail = models.OneToOneField(to='AuthorDetail')


    def __str__(self):
        return self.name

class AuthorDetail(models.Model):
    phone = models.BigIntegerField()
    addr = models.CharField(max_length=64)

一對多字段:

# 首先在test文件中加入下面代碼:
import os


if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "many_search.settings")
    import django
    django.setup()
    from app01 import models
    # 建立數據
    models.Book.objects.create(title='三國演義',price=123.23,publish_id=1)  # publish_id直接傳出版社主鍵值
    models.Book.objects.create(title='紅樓夢',price=523.23,publish_id=3)  # publish_id直接傳出版社主鍵值
    models.Book.objects.create(title='老人與海',price=23.23,publish_id=3)  # publish_id直接傳出版社主鍵值

    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.create(title='水滸傳',price=123.23,publish=publish_obj)  # publish直接傳出版社數據對象
查:
book_obj = models.Book.objects.filter(pk=1).first()
    print(book_obj.publish)  # 獲取到當前所對應的出版社對象
    print(book_obj.publish_id)  # 獲取到的就是表中的實際字段
    
    
# 打印:   東海出版社 ,1
改:
models.Book.objects.filter(pk=1).update(publish_id=3)
    publish_obj = models.Publish.objects.filter(pk=2).first()
    models.Book.objects.filter(pk=1).update(publish=publish_obj)

刪:
models.Publish.objects.filter(pk=2).delete()
# 默認也是級聯更新 級聯刪除

多對多的表關係:

增:
# 給主鍵爲3的書籍添加兩個做者 1 2
book_obj = models.Book.objects.filter(pk=3).first()
# print(book_obj.authors)  # 就至關於 已經在書籍和做者的關係表了
# book_obj.authors.add(1)
# book_obj.authors.add(2,3)
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
# book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj,author_obj1)

    """
    add() 括號內既能夠傳數字也能夠傳數據對象而且都支持傳多個
    """
改:
# 修改關係
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.set([3,])
book_obj.authors.set([1,3])
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
book_obj.authors.set((author_obj,))
book_obj.authors.set((author_obj,author_obj1))
"""
set() 括號內 既能夠傳數字也傳對象 而且也是支持傳多個的
可是須要注意 括號內必須是一個可迭代對象
"""
book_obj = models.Book.objects.filter(pk=3).first()
# book_obj.authors.remove(2)
# book_obj.authors.remove(1,2)
author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
#book_obj.authors.remove(author_obj)
book_obj.authors.remove(author_obj,author_obj1)
    """
    remove() 括號內 既能夠傳數字也傳對象 
    而且也是支持傳多個的
    """
清空:
book_obj = models.Book.objects.filter(pk=3).first()
book_obj.authors.clear()
"""clear()括號內不須要傳任何參數 直接清空當前書籍對象全部的記錄"""

ORM跨表查詢

誰有外鍵字段誰就是正向

沒有外鍵字段的就是反向

正向查詢按字段,反向查詢表名小寫

書籍對象 查 出版社 外鍵字段在書籍 正向查詢

出版社 查 書籍 外鍵字段書籍 反向查詢

基於對象的跨表查詢,子查詢

基於雙下劃線的跨表查詢 連表查詢

1.基於對象的跨表查詢 子查詢

步驟:先獲取一個數據對性,而後利用對象點的方式查詢到所對應的數據

2.基於雙下劃線的跨表查詢 連表查詢

表:app01_book

表:app01_book_authors

表:app01_author

表:app01_authordetail

表:app01_publish

# 1.查詢書籍是三國演義的出版社名稱
book_obj = models.Book.objects.filter(title='三國演義').first()
# 正向查詢按字段
print(book_obj.publish.name)
print(book_obj.publish.addr)
# 打印 山海出版社山海

#2.查詢書籍主鍵是2的做者姓名
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.authors)
app01.Author.Noneprint(book_obj.authors.all())
# 打印: app01.Author.None,  <QuerySet [<Author: 錢>]>


# 3.查詢做者是趙的手機號
author_obj = models.Author.objects.filter(name='趙').first()
print(author_obj.author_detail.phone)
print(author_obj.author_detail.addr)
# 打印: 110,  山東

"""
正向查詢 按字段 當該字段所對應的數據有多個的時候 須要加.all()
否者點外鍵字段直接就可以拿到數據對象
"""

# 4.查詢出版社是山海出版社出版過的書籍
publish_obj = models.Publish.objects.filter(name='山海出版社').first()
print(publish_obj.book_set)
app01.Book.Noneprint(publish_obj.book_set.all())
# 打印 app01.Book.None,  <QuerySet [<Book: 三國演義>, <Book: 水滸傳>]>

# 5.查詢做者是jason寫過的全部的書
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.book_set)
app01.Book.Noneprint(author_obj.book_set.all())
# 打印app01.Book.None,  <QuerySet [<Book: 三國演義>]>


# 6.查詢手機號是110的做者
author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
print(author_detail_obj.author)
print(author_detail_obj.author.name)
print(author_detail_obj.author.age)
# 打印: 趙, 趙, 18

"""
反向查詢按表名小寫
何時須要加_set
當查詢的結果能夠是多個的狀況下 須要加_set.all()
何時不須要加_set
當查詢的結果有且只有一個的狀況下 不須要加任何東西 直接表名小寫便可"""

# 7.查詢書籍是python入門的做者的手機號
book_obj = models.Book.objects.filter(title='三國演義').first()
print(book_obj.authors.all())
# 打印 <QuerySet [<Author: 趙>]>

# 2.基於雙下劃綫的跨表查詢   連表查詢
"""MySQL
        left join
    inner join
    right join
    union
"""
# 1.查詢書籍是三國演義的出版社名稱正向
res = models.Book.objects.filter(title='三國演義').values('publish__name')
print(res)
# 打印: <QuerySet [{'publish__name': '山海出版社'}]>

# 反向
res = models.Publish.objects.filter(book__title='三國演義').values('name')
print(res)
# 打印: <QuerySet [{'name': '山海出版社'}]>

# 2.查詢做者是李的手機號碼正向
res1 = models.Author.objects.filter(name='李').values('author_detail__phone')
print(res1)
# 打印:<QuerySet [{'author_detail__phone': 114}]>

# 反向
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
print(res)
# 打印:<QuerySet [{'phone': 114, 'author__age': 21}]>

# 3.查詢手機號是120的做者姓名
res2 = models.AuthorDetail.objects.filter(phone=120).values('author__name')
print(res2)
# 打印: <QuerySet [{'author__name': '錢'}]>

res = models.Author.objects.filter(author_detail__phone=120).values('name','author_detail__addr')
print(res)
# 打印: <QuerySet [{'name': '錢', 'author_detail__addr': '河北'}]>

# 4.查詢出版社是山海出版社出版的書籍名稱
res = models.Publish.objects.filter(name='山海出版社').values('book__title','addr')
print(res)
# 打印:<QuerySet [{'book__title': '三國演義', 'addr': '山海'}, {'book__title': '水滸傳', 'addr': '山海'}]>

# 5.查詢做者是錢的寫過的書的名字和價格
res = models.Author.objects.filter(name='錢').values('book__title','book__price')print(res)
# 打印: <QuerySet [{'book__title': '紅樓夢', 'book__price': Decimal('523.23')}]>

# 6.查詢書籍是三國演義的做者的手機號
res = models.Book.objects.filter(title='三國演義').values('authors__author_detail__phone')
print(res)
# 打印: <QuerySet [{'authors__author_detail__phone': 110}]>

聚合函數

關鍵字:aggregate

# 導入模塊   
from django.db.models import Max,Min,Sum,Count,Avg
res = models.Book.objects.all().aggregate(Avg('price')) # 求全部書的平均價格
res1 = models.Book.objects.all().aggregate(Max('price')) # 求全部書的最大價格
res2 = models.Book.objects.all().aggregate(Min('price')) # 求全部書的最小价格
res3 = models.Book.objects.all().aggregate(Sum('price')) # 求全部書的價格和
res4 = models.Book.objects.all().aggregate(Count('title')) # 求全部書的計數
res5 = models.Book.objects.all().aggregate(Avg('price'),Max('price'),Min('price'),Sum('price'),Count('title'))
print(res5)

# 打印: 
{'price__avg': 198.73, 'price__max': Decimal('523.23'), 
 'price__min': Decimal('23.23'), 'price__sum': Decimal('794.92'), 'title__count': 4}

分組查詢

關鍵字:annotate

# 1.統計每一本書的做者個數
res = models.Book.objects.annotate(author_num=Count('authors')).values('author_num')
print(res)

# 打印: <QuerySet [{'author_num': 1}, {'author_num': 1}, {'author_num': 1}, {'author_num': 1}]>


# 2.統計出每一個出版社賣的最便宜的書的價格
res = models.Publish.objects.annotate(price_min=Min('book__price')).values('price_min')
print(res)

# 打印: <QuerySet [{'price_min': Decimal('23.23')}, {'price_min': Decimal('123.23')}, {'price_min': None}]>


# 3.統計不止一個做者的圖書
"""
步驟:
1.統計每本書對應的做者個數
2.基於上面的結果 篩選出做者個數大於1 的

"""
res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('author_num')
print(res)

# 打印: <QuerySet []>


# 4.查詢各個做者出的書的總價格
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('sum_price')
print(res)

# 打印: <QuerySet [{'sum_price': Decimal('125.23')}, {'sum_price': Decimal('523.23')}, {'sum_price': Decimal('23.23')}, {'sum_price': Decimal('123.23')}]>

F與Q查詢

from django.db.models import F, Q
# 1.查詢出賣出數大於庫存數的書籍
res = models.Book.objects.filter(maichu__gt=F('kucun'))
print(res)

# 打印: <QuerySet []>


# 2.將全部的書的價格 所有提升100塊
models.Book.objects.update(price=F('price') + 100)

Q:

res = models.Book.objects.filter(title='三國演義', price=123.33) # 逗號就是and
res1 = models.Book.objects.filter(Q(title='三國演義'), Q(price=544.44))  # 逗號就是and
res2 = models.Book.objects.filter(Q(title='三國演義') | Q(kucun=666))  # 用來Q以後 就可以支持|表示或
res3 = models.Book.objects.filter(~Q(title='三國演義') | Q(kucun=666))  # esc下面那個鍵 波浪號  表示非
print(res)
print(res1)
print(res2)
print(res3)

# 打印結果: <QuerySet []>, <QuerySet []>, <QuerySet [<Book: 三國演義>], <QuerySet [<Book: 紅樓夢>, <Book: 水滸傳>, <Book: 老人與海>]>
Q查詢進階用法 用Q產生對象 而後再使用
q = Q()
q.connector = 'or'
q.children.append(('title__icontains','三'))
q.children.append(('kucun',666))
res = models.Book.objects.filter(q)
print(res)
"""
字符串的左邊 跟變量名條件書寫如出一轍
"""

# 打印: <QuerySet [<Book: 三國演義>]>
only會將括號內的字段對應的值 直接封裝到返回給你的對象中  點該字段 不須要再走數據庫一旦你點了不是括號內的字段  就會頻繁的去走數據庫查詢

ORM經常使用字段:

AutoField
int自增列,必須填入參數 primary_key=True。當model中若是沒有自增列,則自動會建立一個列名爲id的列。

IntegerField
一個整數類型,範圍在 -2147483648 to 2147483647。(通常不用它來存手機號(位數也不夠),直接用字符串存,)

CharField
字符類型,必須提供max_length參數, max_length表示字符長度.

DateField
日期字段,日期格式  YYYY-MM-DD,至關於Python中的datetime.date()實例。

DateTimeField
日期時間字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],至關於Python中的datetime.datetime()實例。

這裏須要知道的是Django中的CharField對應的MySQL數據庫中的varchar類型,沒有設置對應char類型的字段,可是Django容許咱們自定義新的字段,下面我來自定義對應於數據庫的char類型

from django.db import models

# Create your models here.
#Django中沒有對應的char類型字段,可是咱們能夠本身建立
class FixCharField(models.Field):
    '''
    自定義的char類型的字段類
    '''
    def __init__(self,max_length,*args,**kwargs):
        self.max_length=max_length
        super().__init__(max_length=max_length,*args,**kwargs)

    def db_type(self, connection):
        '''
        限定生成的數據庫表字段類型char,長度爲max_length指定的值
        :param connection:
        :return:
        '''
        return 'char(%s)'%self.max_length
#應用上面自定義的char類型
class Class(models.Model):
    id=models.AutoField(primary_key=True)
    title=models.CharField(max_length=32)
    class_name=FixCharField(max_length=16)
    gender_choice=((1,'男'),(2,'女'),(3,'保密'))
    gender=models.SmallIntegerField(choices=gender_choice,default=3)

字段合集:

AutoField(Field)
        - int自增列,必須填入參數 primary_key=True

    BigAutoField(AutoField)
        - bigint自增列,必須填入參數 primary_key=True

        注:當model中若是沒有自增列,則自動會建立一個列名爲id的列
        from django.db import models

        class UserInfo(models.Model):
            # 自動建立一個列名爲id的且爲自增的整數列
            username = models.CharField(max_length=32)

        class Group(models.Model):
            # 自定義自增列
            nid = models.AutoField(primary_key=True)
            name = models.CharField(max_length=32)

    SmallIntegerField(IntegerField):
        - 小整數 -32768 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整數 0 ~ 32767
    IntegerField(Field)
        - 整數列(有符號的) -2147483648 ~ 2147483647

    PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整數 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 長整型(有符號的) -9223372036854775808 ~ 9223372036854775807

    BooleanField(Field)
        - 布爾值類型

    NullBooleanField(Field):
        - 能夠爲空的布爾值

    CharField(Field)
        - 字符類型
        - 必須提供max_length參數, max_length表示字符長度

    TextField(Field)
        - 文本類型

    EmailField(CharField):
        - 字符串類型,Django Admin以及ModelForm中提供驗證機制

    IPAddressField(Field)
        - 字符串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制

    GenericIPAddressField(Field)
        - 字符串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6
        - 參數:
            protocol,用於指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
            unpack_ipv4, 若是指定爲True,則輸入::ffff:192.0.2.1時候,可解析爲192.0.2.1,開啓此功能,須要protocol="both"

    URLField(CharField)
        - 字符串類型,Django Admin以及ModelForm中提供驗證 URL

    SlugField(CharField)
        - 字符串類型,Django Admin以及ModelForm中提供驗證支持 字母、數字、下劃線、鏈接符(減號)

    CommaSeparatedIntegerField(CharField)
        - 字符串類型,格式必須爲逗號分割的數字

    UUIDField(Field)
        - 字符串類型,Django Admin以及ModelForm中提供對UUID格式的驗證

    FilePathField(Field)
        - 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能
        - 參數:
                path,                      文件夾路徑
                match=None,                正則匹配
                recursive=False,           遞歸下面的文件夾
                allow_files=True,          容許文件
                allow_folders=False,       容許文件夾

    FileField(Field)
        - 字符串,路徑保存在數據庫,文件上傳到指定目錄
        - 參數:
            upload_to = ""      上傳文件的保存路徑
            storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路徑保存在數據庫,文件上傳到指定目錄
        - 參數:
            upload_to = ""      上傳文件的保存路徑
            storage = None      存儲組件,默認django.core.files.storage.FileSystemStorage
            width_field=None,   上傳圖片的高度保存的數據庫字段名(字符串)
            height_field=None   上傳圖片的寬度保存的數據庫字段名(字符串)

    DateTimeField(DateField)
        - 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

    DateField(DateTimeCheckMixin, Field)
        - 日期格式      YYYY-MM-DD

    TimeField(DateTimeCheckMixin, Field)
        - 時間格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 長整數,時間間隔,數據庫中按照bigint存儲,ORM中獲取的值爲datetime.timedelta類型

    FloatField(Field)
        - 浮點型

    DecimalField(Field)
        - 10進制小數
        - 參數:
            max_digits,小數總長度
            decimal_places,小數位長度

    BinaryField(Field)
        - 二進制類型
      
      
      
對應關係:
    'AutoField': 'integer AUTO_INCREMENT',
    'BigAutoField': 'bigint AUTO_INCREMENT',
    'BinaryField': 'longblob',
    'BooleanField': 'bool',
    'CharField': 'varchar(%(max_length)s)',
    'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
    'DateField': 'date',
    'DateTimeField': 'datetime',
    'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
    'DurationField': 'bigint',
    'FileField': 'varchar(%(max_length)s)',
    'FilePathField': 'varchar(%(max_length)s)',
    'FloatField': 'double precision',
    'IntegerField': 'integer',
    'BigIntegerField': 'bigint',
    'IPAddressField': 'char(15)',
    'GenericIPAddressField': 'char(39)',
    'NullBooleanField': 'bool',
    'OneToOneField': 'integer',
    'PositiveIntegerField': 'integer UNSIGNED',
    'PositiveSmallIntegerField': 'smallint UNSIGNED',
    'SlugField': 'varchar(%(max_length)s)',
    'SmallIntegerField': 'smallint',
    'TextField': 'longtext',
    'TimeField': 'time',
    'UUIDField': 'char(32)',
相關文章
相關標籤/搜索