目錄html
對象是指 orm的models類名實例化的對象前端
關係是指 orm中的數據模型和數據庫的關係python
類----------------》表 #models.py中的類對應數據庫中的表 對象--------------》記錄(數據行) #obj=models.User.objects.get(id=1) obj對應數據庫表中的行數據 屬性--------------》字段 #models.py類中的屬性對應數據庫表中的字段
映射 orm其實就是將models.類名.object.filter類對象的語法經過orm翻譯翻譯成sql語句的一個引擎mysql
''' <1> CharField 字符串字段, 用於較短的字符串. CharField 要求必須有一個參數 maxlength, 用於從數據庫層和Django校驗層限制該字段所容許的最大字符數. <2> IntegerField #用於保存一個整數. <3> DecimalField 一個浮點數. 必須 提供兩個參數: 參數 描述 max_digits 總位數(不包括小數點和符號) decimal_places 小數位數 舉例來講, 要保存最大值爲 999 (小數點後保存2位),你要這樣定義字段: models.DecimalField(..., max_digits=5, decimal_places=2) 要保存最大值一百萬(小數點後保存10位)的話,你要這樣定義: models.DecimalField(..., max_digits=17, decimal_places=10) #max_digits大於等於17就能存儲百萬以上的數了 admin 用一個文本框(<input type="text">)表示該字段保存的數據. <4> AutoField 一個 IntegerField, 添加記錄時它會自動增加. 你一般不須要直接使用這個字段; 自定義一個主鍵:my_id=models.AutoField(primary_key=True) 若是你不指定主鍵的話,系統會自動添加一個主鍵字段到你的 model. <5> BooleanField A true/false field. admin 用 checkbox 來表示此類字段. <6> TextField 一個容量很大的文本字段. admin 用一個 <textarea> (文本區域)表示該字段數據.(一個多行編輯框). <7> EmailField 一個帶有檢查Email合法性的 CharField,不接受 maxlength 參數. <8> DateField 一個日期字段. 共有下列額外的可選參數: Argument 描述 auto_now 當對象被保存時(更新或者添加都行),自動將該字段的值設置爲當前時間.一般用於表示 "last-modified" 時間戳. auto_now_add 當對象首次被建立時,自動將該字段的值設置爲當前時間.一般用於表示對象建立時間. (僅僅在admin中有意義...) <9> DateTimeField 一個日期時間字段. 相似 DateField 支持一樣的附加選項. <10> ImageField 相似 FileField, 不過要校驗上傳對象是不是一個合法圖片.#它有兩個可選參數:height_field和width_field, 若是提供這兩個參數,則圖片將按提供的高度和寬度規格保存. <11> FileField 一個文件上傳字段. 要求一個必須有的參數: upload_to, 一個用於保存上載文件的本地文件系統路徑. 這個路徑必須包含 strftime #formatting, 該格式將被上載文件的 date/time 替換(so that uploaded files don't fill up the given directory). admin 用一個<input type="file">部件表示該字段保存的數據(一個文件上傳部件) . 注意:在一個 model 中使用 FileField 或 ImageField 須要如下步驟: (1)在你的 settings 文件中, 定義一個完整路徑給 MEDIA_ROOT 以便讓 Django在此處保存上傳文件. (出於性能考慮,這些文件並不保存到數據庫.) 定義MEDIA_URL 做爲該目錄的公共 URL. 要確保該目錄對 WEB服務器用戶賬號是可寫的. (2) 在你的 model 中添加 FileField 或 ImageField, 並確保定義了 upload_to 選項,以告訴 Django 使用 MEDIA_ROOT 的哪一個子目錄保存上傳文件.你的數據庫中要保存的只是文件的路徑(相對於 MEDIA_ROOT). 出於習慣你必定很想使用 Django 提供的 get_<#fieldname>_url 函數.舉例來講,若是你的 ImageField 叫做 mug_shot, 你就能夠在模板中以 {{ object.#get_mug_shot_url }} 這樣的方式獲得圖像的絕對路徑. <12> URLField 用於保存 URL. 若 verify_exists 參數爲 True (默認), 給定的 URL 會預先檢查是否存在( 即URL是否被有效裝入且 沒有返回404響應). admin 用一個 <input type="text"> 文本框表示該字段保存的數據(一個單行編輯框) <13> NullBooleanField 相似 BooleanField, 不過容許 NULL 做爲其中一個選項. 推薦使用這個字段而不要用 BooleanField 加 null=True 選項 admin 用一個選擇框 <select> (三個可選擇的值: "Unknown", "Yes" 和 "No" ) 來表示這種字段數據. <14> SlugField "Slug" 是一個報紙術語. slug 是某個東西的小小標記(短籤), 只包含字母,數字,下劃線和連字符.#它們一般用於URLs 若你使用 Django 開發版本,你能夠指定 maxlength. 若 maxlength 未指定, Django 會使用默認長度: 50. #在 之前的 Django 版本,沒有任何辦法改變50 這個長度. 這暗示了 db_index=True. 它接受一個額外的參數: prepopulate_from, which is a list of fields from which to auto-#populate the slug, via JavaScript,in the object's admin form: models.SlugField (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields. <13> XMLField 一個校驗值是否爲合法XML的 TextField,必須提供參數: schema_path, 它是一個用來校驗文本的 RelaxNG schema #的文件系統路徑. <14> FilePathField 可選項目爲某個特定目錄下的文件名. 支持三個特殊的參數, 其中第一個是必須提供的. 參數 描述 path 必需參數. 一個目錄的絕對文件系統路徑. FilePathField 據此獲得可選項目. Example: "/home/images". match 可選參數. 一個正則表達式, 做爲一個字符串, FilePathField 將使用它過濾文件名. 注意這個正則表達式只會應用到 base filename 而不是 路徑全名. Example: "foo.*\.txt^", 將匹配文件 foo23.txt 卻不匹配 bar.txt 或 foo23.gif. recursive可選參數.要麼 True 要麼 False. 默認值是 False. 是否包括 path 下面的所有子目錄. 這三個參數能夠同時使用. match 僅應用於 base filename, 而不是路徑全名. 那麼,這個例子: FilePathField(path="/home/images", match="foo.*", recursive=True) ...會匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif <15> IPAddressField 一個字符串形式的 IP 地址, (i.e. "24.124.1.30"). <16> CommaSeparatedIntegerField 用於存放逗號分隔的整數值. 相似 CharField, 必需要有maxlength參數. '''
(1)null 若是爲True,Django 將用NULL 來在數據庫中存儲空值。 默認值是 False. (1)blank 若是爲True,該字段容許不填。默認爲False。 要注意,這與 null 不一樣。null純粹是數據庫範疇的,而 blank 是數據驗證範疇的。 若是一個字段的blank=True,表單的驗證將容許該字段是空值。若是字段的blank=False,該字段就是必填的。 (2)default 字段的默認值。能夠是一個值或者可調用對象。若是可調用 ,每有新對象被建立它都會被調用,若是你的字段沒有設置能夠爲空,那麼未來若是咱們後添加一個字段,這個字段就要給一個default值 (3)primary_key 若是爲True,那麼這個字段就是模型的主鍵。若是你沒有指定任何一個字段的primary_key=True, Django 就會自動添加一個IntegerField字段作爲主鍵,因此除非你想覆蓋默認的主鍵行爲, 不然不必設置任何一個字段的primary_key=True。 (4)unique 若是該值設置爲 True, 這個數據字段的值在整張表中必須是惟一的 (5)choices 由二元組組成的一個可迭代對象(例如,列表或元組),用來給字段提供選擇項。 若是設置了choices ,默認的表單將是一個選擇框而不是標準的文本框,<br>並且這個選擇框的選項就是choices 中的選項。 (6)db_index 若是db_index=True 則表明着爲此字段設置數據庫索引。 DatetimeField、DateField、TimeField這個三個時間字段,均可以設置以下屬性。 (7)auto_now_add 配置auto_now_add=True,建立數據記錄的時候會把當前時間添加到數據庫。 (8)auto_now 配置上auto_now=True,每次更新數據記錄的時候會更新該字段,標識這條記錄最後一次的修改時間。
1.MVC或者MVC框架中包括一個重要的部分,就是ORM,它實現了數據模型與數據庫的解耦,即數據模型的設計不須要依賴於特定的數據庫,經過簡單的配置就能夠輕鬆更換數據庫,這極大的減輕了開發人員的工做量jquery
2.ORM是「對象-關係-映射」的簡稱。git
3.執行流程正則表達式
類對象--->sql--->pymysql--->mysql服務端--->磁盤redis
orm其實就是將類對象的語法翻譯成sql語句的一個引擎sql
orm語句 -- sql -- 調用pymysql客戶端發送sql -- mysql服務端接收到指令並執行數據庫
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 引擎 'NAME': 'day53', # 數據庫名稱 'HOST': '127.0.0.1', # IP 'PORT': 3306, # 端口號 'USER': 'root', # 用戶名 'PASSWORD': '123' # 密碼 } }
做用:用pymysql替換mysqldb(djnago自帶的)
mysqldb 不能python3.4以上的版本
須要使用第三方模塊pymysql進行替換
app01中的--init--文件
MySQLdb的是一個接口鏈接到MySQL數據庫服務器從Python MySQLdb並不支持Python3.4以後版本
緣由: #python默認鏈接的MySQLdb並不支持Python3.4以後版本 解決辦法: #12使用第三方模塊pymysql進行替換 import pymysql pymysql.install_as_MySQLdb()
#引用一個模塊 from django.db import models class UserInfo(models.Model): id = models.AutoField(primary_key=True) name = models.CharField(max_length=10) bday = models.DateField() checked = models.BooleanField() # 1 翻譯成sql語句 # 2 django內置的一個sqlite客戶端將sql語句發給sqlite服務端 # 3 服務端拿到sql,到磁盤裏面進行了數據操做(create table app01_userinfo(id name...))
添加字段的時候別忘了,該字段不能爲空,全部要麼給默認值,要麼設置它容許爲空 null=True
#注意在每次增長字段時候都須要執行一遍這個方法 python manage.py makemigrations#建立一個表記錄 python版本號 python manage.py migrate 執行記錄
數據庫問題mysql 更改時區和改變版本號mysql for 5.1
更改時區鏈接 https://www.cnblogs.com/strawberry-1/p/11599376.html
(實例一個對象,調用save方法)
models.py
#建立一條記錄,增 def query(request): new_obj = models.UserInfo( id=2, name='子文', bday='2019-09-27', checked=1, ) new_obj.save() #翻譯成sql語句, #而後調用pymysql,發送給服務端 至關於執行insert into app01_userinfo values(2,'子文','2019-09-27',1) return HttpResponse('xxx')
經過選項實現對字段的約束,選項以下: null:若是爲True,表示容許爲空,默認值是False。 blank:若是爲True,則該字段容許爲空白,默認值是False。 對比:null是數據庫範疇的概念,blank是表單驗證證範疇的。 db_column:字段的名稱,若是未指定,則使用屬性的名稱。 db_index:若值爲True, 則在表中會爲此字段建立索引,默認值是False。 default:默認值。 primary_key:若爲True,則該字段會成爲模型的主鍵字段,默認值是False,通常做爲AutoField的選項使用。 unique:若是爲True, 這個字段在表中必須有惟一值,默認值是False。
配置數據庫
python3 manage.py makemigrations 建立腳本 python3 manage.py migrate 遷移
建立app01中的--init--文件
class Book(models.Model): #必需要繼承的 nid = models.AutoField(primary_key=True) #自增id(能夠不寫,默認會有自增id AutoField是自增) title = models.CharField(max_length=32) publishDdata = models.DateField() #出版日期 author = models.CharField(max_length=32) price = models.DecimalField(max_digits=5,decimal_places=2) #一共5位,保留兩位小數
替換數據庫的時候須要從新建立表記錄
更改字段時候也須要
python36 manage.py makemigrations 建立腳本 python36 manage.py migrate 遷移
建立字段django特殊說明
1.字段的值默認是不爲空的 須要手動設置 否則會報錯 2.主鍵無需手動添加 自動生成id字段(主鍵) 3.引用模塊from django.db import models
獲取id字段的兩種方式
1.表名.id 例 book.id 2.表名.pk 例 book.pk
方式1: new_obj = models.UserInfo(#直接表名建立 過程 #1.先實例化產生對象,2.而後調用save方法保存 id=2, name='子文', bday='2019-09-27', checked=1, ) new_obj.save() 方式2: # ret 是建立的新的記錄的model對象(重點) ret = models.UserInfo.objects.create( name='衛賀', bday='2019-08-07', checked=0 ) print(ret) #UserInfo object print(ret.name) #UserInfo object print(ret.bday) #UserInfo object
models.UserInfo.objects.create( name='楊澤濤2', bday=current_date, # now=current_date, 直接插入時間沒有時區問題 checked=0 ) 可是若是讓這個字段自動來插入時間,就會有時區的問題,auto_now_add建立記錄時自動添加當前建立記錄時的時間,存在時區問題 now = models.DateTimeField(auto_now_add=True,null=True) 解決方法: settings配置文件中將USE_TZ的值改成False # USE_TZ = True USE_TZ = False # 告訴mysql存儲時間時按照當地時間來寸,不要用utc時間 使用pycharm的數據庫客戶端的時候,時區問題要注意
from django.db import models 簡單查詢:filter() -- 結果是queryset類型的數據裏面是一個個的model對象,相似於列表 models.UserInfo.objects.filter(id=7).delete() #queryset對象調用 models.UserInfo.objects.filter(id=7)[0].delete() #model對象調用
方式1:update # models.UserInfo.objects.filter(id=2).update( # name='籃子文', # checked = 0, # # ) # 錯誤示例,model對象不能調用update方法 # models.UserInfo.objects.filter(id=2)[0].update( # name='加籃子+2', # # checked = 0, # ) 方式2 ret = models.UserInfo.objects.filter(id=2)[0] ret.name = '加籃子+2' ret.checked = 1 ret.save() 更新時的auto_now參數 # 更新記錄時,自動更新時間,建立新紀錄時也會幫你自動添加建立時的時間,可是在更新時只有使用save方法的方式2的形式更新才能自動更新時間,有缺陷,放棄 now2 = models.DateTimeField(auto_now=True,null=True)
步驟 1.把查詢的對象放入字典裏一次性傳入前端進行交互 # bulk_create obj_list = [] for i in range(20): obj = models.Book( title=f'金瓶{i}', price=20+i, publish_date=f'2019-09-{i+1}', publish='24期出版社' ) obj_list.append(obj) models.Book.objects.bulk_create(obj_list) #批量建立
request.POST -- querydict類型 {'title': ['asdf '], 'price': ['212'], 'publish_date': ['2019-09-12'], 'publish': ['asdf ']} data = request.POST.dict() -- 可以將querydict轉換爲普通的python字典格式 建立數據 models.Book.objects.create( ## title=title, #title='asdf ' ## price=price, #price='212' ## publish_date=publish_date, #'publish_date': ['2019-09-12'] ## publish=publish, #publish=['asdf '] **data#經過打散把鍵和值轉換成以上數據 )
篩選基本都是queryset類型
reservse 必需要排序才能反轉
查詢對應表名的全部對象,結果是對象列表
結果爲queryset類型
寫法 models.表名.object.all() 例如 all_books = models.Book.objects.all() 數量過多會自動截斷
過濾出符合條件的數據
filter 條件查詢 ret = models.Book.objects.filter(title='金瓶7',publish='24期出版社') #至關於mysql數據庫中and多條件查詢 查詢條件不能匹配到數據時,不會報錯,返回一個空的queryset,<QuerySet []>,若是沒有寫查詢條件會獲取全部數據,queryset類型的數據還可以繼續調用fitler方法
獲得一個知足條件的model對象 有且只有一個
ret = models.Book.objects.get() #獲得的是一個model對象,有且只能有一個 1. 查不到數據會報錯 :Book matching query does not exist. 2. 超過一個就報錯 :returned more than one Book -- it returned 13!
#除了這個以外 models.BOOK.objects.exclude(title__startswith=('金瓶')) #model類型不能使用這個方法 1.object可以調用,models.Book.objects.exclude(title__startswith='金瓶') 2.queryset類型數據可以調用, models.Book.objects.all().exclude(title__startswith='金瓶')
models.Book.objects.all().order_by('-price','id') #sql語句寫法 orderby price desc,id asc; models類型不能使用 排序order by 加上-字段名 不加是升序
models.Book.objects.all().order_by('id').reverse() #數據排序以後才能反轉
計數,統計返回結果的數量
models.Book.objects.all().count() sql語句 聚合函數
相似於models.類名(表名).objects.filter(條件判斷)[0] models.類名(表名).objects.filter(條件判斷).first() #返回知足條件的第一條數據
返回第一條數據,結果是model對象類型
返回最後一條數據,結果是model對象類型
ret = models.Book.objects.all().first() ret = models.Book.objects.all().last()
判斷返回結果集是否是有數據
models.Book.objects.filter(id=9999).exists() #有結果就是True,沒有結果就是False
(返回的queryset類型,裏面是字典類型數據)
(返回的queryset類型,裏面是數組類型數據)
ret = models.Book.objects.filter(id=9).values('title','price') ret = models.Book.objects.all().values_list('title','price') ret = models.Book.objects.all().values() ret = models.Book.objects.values() #調用values或者values_list的是objects控制器,那麼返回全部數據
去重,配置values和values_list來使用,不能帶有id 由於id默認惟一
models.Book.objects.all().values('publish').distinct()
queryset類型 篩選出來的是queryset類型
get篩選出來一個是model對象
queryset 類型的方法能夠屢次調用使用
13個api能調用的函數和方法(重點)
# ret = models.Book.objects.all().values('publish').distinct() # ret = models.Book.objects.filter(price__gt=35) #大於 # ret = models.Book.objects.filter(price__gte=35) # 大於等於 # ret = models.Book.objects.filter(price__lt=35) # 小於等於 # ret = models.Book.objects.filter(price__lte=35) # 小於等於 # ret = models.Book.objects.filter(price__range=[35,38]) # 大於等35,小於等於38 # where price between 35 and 38 # ret = models.Book.objects.filter(title__contains='金瓶') # 字段數據中包含這個字符串的數據都要 # ret = models.Book.objects.filter(title__contains='金瓶') # ret = models.Book.objects.filter(title__icontains="python") # 不區分大小寫 # from app01.models import Book # ret = models.Book.objects.filter(title__icontains="python") # 不區分大小寫 # ret = models.Book.objects.filter(title__startswith="py") # 以什麼開頭,istartswith 不區分大小寫 # ret = models.Book.objects.filter(publish_date='2019-09-15') 某年某月某日(對於日期的修改): ret = models.Book.objects.filter(publish_date__year='2018') ret = models.Book.objects.filter(publish_date__year__gt='2018')#2018寫數字也能夠 ret = models.Book.objects.filter(publish_date__year='2019',publish_date__month='8',publish_date__day='1') 找字段數據爲空的雙下滑線 models.Book.objects.filter(publish_date__isnull=True) #這個字段值爲空的那些數據
多表是會爲減小數據的冗餘 加速查詢的效率
models.字段類型()
rom django.db import models # Create your models here. class Author(models.Model): """ 做者表 """ name=models.CharField( max_length=32) age=models.IntegerField() #一對一 authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE) # #一對一 au=models.OneToOneField("AuthorDetail",on_delete=models.CASCADE) class AuthorDetail(models.Model): """ 做者詳細信息表 """ birthday=models.DateField() telephone=models.CharField(max_length=11) addr=models.CharField(max_length=64) # class Meta: # db_table='authordetail' #指定表名 # ordering = ['-id',] class Publish(models.Model): """ 出版社表 """ name=models.CharField( max_length=32) city=models.CharField( max_length=32) class Book(models.Model): """ 書籍表 """ title = models.CharField( max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) #一對多 publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE,) 多對多 authors=models.ManyToManyField('Author',)
#重中之重 不要把表名和庫名設置成同樣的 1.不寫字段默認外鍵默認鏈接id 2.創表默認建立主鍵 無需手動建立 3.oneto one 一對一#OneToOneField 4.id能夠省略(自動鏈接另外一個表的id字段(主鍵)) 5.djnago1.0版本能夠不寫外鍵 默認級聯刪除 6.djnago2.0版本必須寫on_delete=models.CASCADE 7.int類型不能進行模糊搜索 例如 電話去模糊匹配 前三位 字段名__startwith='151' 8.外鍵字段是賦值變量名=變量名_id 9.class AuthorDetail(models.Model) 建立表結構時 要繼承 models.Model方法 完整版寫法: authorDetail=models.ForeignKey(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE) class meta: 指定建立表時的源信息 ordering 排序 db contrations 去除強制約束效果
# 多對多沒辦法使用一個表的外鍵去設置 #多對多關係用第三張表存儲關係 優勢 存入字段數據少 數據庫小 增長執行效率 1.manytomany #authors=models.ManyToManyField('Author',) ManyToManyField不會加字段 book——author 一個表-另外一個表 1.會生成一個表 字段會本身創建 2。一個字段是表名——id 3.下一個字段是另外一個表——id 會自動建立 對應id字段,存入到一個屬性中 使用方法 4.類名或者實例化對象(表名)去調用這個屬性
#注意事項 1.若是兩張表數據不統一 是表數據少的去鏈接數據多的(數據多的是主表) 2.若是數據統一 建哪一個東西 sql語句 把外鍵變成unique(惟一)格式同樣 authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)
1。對於外鍵不須要惟一性, 2。不創建外鍵惟一(使用models.OneToOneField)創建外鍵
1.完整版寫法 authorDetail=models.ForeignKey(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE) 2.id能夠省略(自動鏈接另外一個表的id字段(主鍵)) publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE,) to=,to_field #publishs是字段名 2.鏈接表的兩種寫法 第一種寫法 to="加對應表名" 默認鏈接主鍵(id) 第二種寫法 publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE,) 能夠不寫 直接寫表名 可是若是加載在以後會報錯由於沒有預加載出來
注意要先鏈接數據庫才能進入admin頁面輸入密碼進行操做
建立與數據庫之間的鏈接 1.在對應的app01 的models文件夾下建立好表,其中表包括(字段類型(約束大小限制) 1.2外鍵的建立#須要注意的是1.1默認建立 2.0版本須要手動添加 1.2.1 一對一建立外鍵約束 #屬性名=OneToOneFlied(on_update=models.CASCADE) 一對多建立外鍵約束# 屬性名=foreignKey() 也對就是對應的子程序的models 2.建立表記錄 3.在對應子程序中把python默認支持的mysqldb 替換成pymysql 緣由mysqldb不支持3.4以上版本
寫法 createsuperuser 兩種寫法 1.pycharm的一個控制檯 #1.manage.py@dbcont > createsuperuser#一開始顯示這個 使用createsuperuser建立管理員 2.python控制檯 2.1python36 manage.py createsuperuser#建立超級管理員 2.2同理輸入帳號和密碼 郵箱能夠不用輸入
建立數據(記錄)
1.把models的表導入到admin 在對應app01(子程序中)的admin.py文件中 2.from django.contrib import admin from app01 import models admin.site.register(models.author)#格式 admin.site.reister(models.類名(表名))
在對應子程序的view視圖裏寫增刪改查
注意要先引用models模塊(對應的models.py文件)
# 一對一 # au_obj = models.AuthorDetail.objects.get(id=4) 查詢出對應的models對象 存入表類中 models.Author.objects.create( name='海狗', age=59, # 兩種方式 au_id=4 # au=au_obj #屬性對應的值是對應的models對象 )
與一對一的區別
對於鏈接字段沒有惟一的約束
pub_obj = models.Publish.objects.get(id=3) models.Book.objects.create( title='xx2', price=13, publishDate='2011-11-12', publishs=pub_obj, #類屬性做爲關鍵字時,值爲model對象 publishs_id=3 # 若是關鍵字爲數據庫字段名稱,那麼值爲關聯數據的值 )
多對多關係表記錄的增長
ziwen = models.Author.objects.get(id=3) haigou = models.Author.objects.get(id=5) new_obj = models.Book.objects.create( title='海狗產後護理第二部', price=0.5, publishDate='2019-09-29', publishs_id=2, ) new_obj是一個對象 #第一種寫法 new_obj.authors.add(對應外鍵字段的值)#對象.屬性.方法名添加add new_obj.authors.add(3,5) #*args **kwargs #添加的多個值用逗號隔開 new_obj.authors.add(*[3,5]) # 用的最多, 用法: 1.select 下拉框 的值是一個列表 使用name屬性 查看對應value的值 2.多選的value值 是提交到後端是一個列表 3.使用*[value]打散#*[3,5] #第二種寫法 添加model對象 new_obj.authors.add(ziwen, haigou) 建立完字段以後要把對應的關係字段寫到第三張表裏
models.AuthorDetail.objects.filter(id=3).delete() models.Author.objects.filter(id=3).delete()
默認級聯刪除
關聯的表是主表 主表刪除子表的相對應的整條字段也被刪除
models.Publish.objects.filter(id=3).delete()#Publish是主表 models.book.objects.filter(id=3).delete()
只操做對應第三張表 book_obj = models.Book.objects.get(id=2) book_obj.authors.add() # 添加 book_obj.authors.remove(1) #刪除括號裏對應的外鍵關聯的id book_obj.authors.clear() # 清除,篩選出的全部的對應外鍵關係字段 book_obj.authors.set(['1','5']) # 先清除對應外鍵關係字段再添加,至關於修改 #易錯點 不是在原位置修改是刪除這條對應記錄,再去添加新紀錄
# 改 ret = models.Publish.objects.get(id=2) models.Book.objects.filter(id=5).update( title='華麗麗', #publishs=ret, publishs_id=1, ) 兩種方式 publishs=ret#使用屬性 對應的值是model對象 publishs_id=1#對應的id值
obj=models.Author.objects.get(name='王洋')和filter用法同樣出來的類型不同 obj=models.Author.objects.filter(name='王洋').first()
1.filter篩選出來的是queryset對象須要轉成model對象 1.2若是是多個值 須要for循環取值轉換 寫法 a=models.Author.objects.filter()[0] a查詢出來多個值 這樣使用就只能查出一個 須要for 循環取值 2.get是對應的model對象 能夠直接拿來用
1.正向查詢是建立外鍵關係的屬性 在當前表中 用法 obj=models.Author.objects.get(name='王洋') obj.對應的外鍵屬性名.字段名 2.反向查詢是表中沒有對應建立外鍵關係的屬性 用法· obj=models.Author.objects.get(name='王洋') obj.小寫表名.字段名 #obj,表名找到對應表 若是 查詢東西多 1.須要用 注意:正向查和反向查有一些區別,當正相查結果爲多個時,直接obj.對應的外鍵屬性名.all()既能夠,可是反向查有一些不一樣obj.小寫表名_set.all()屬性名(字段)_set.all() 取值 2.使用 for循環列表進行對象取值 舉例 obj=models.表名.objects.filter(name='子文') ret=obj.book_set.all()#查詢出來的是個列表s for i in ret: print(i.title) #注意:正向查和反向查有一些區別,當正相查結果爲多個時,直接obj.對應的外鍵屬性名.all()既能夠,可是反向查有一些不一樣obj.小寫表名_set.all()
# 一對一 正向查詢 對象.屬性 obj = models.Author.objects.filter(name='王洋').first() ph = obj.au.telephone print(ph) # 查一下電話號碼爲120的做者姓名 # 反向查詢 對象.小寫的表名 obj = models.AuthorDetail.objects.filter(telephone=120).first() ret = obj.author.name #陳碩 print(ret)
# 查詢 # 一對多 # 查詢一下 海狗的慫逼人生這本書是哪一個出版社出版的 正向查詢 obj = models.Book.objects.filter(title='海狗的慫逼人生').first() ret = obj.publishs.name print(ret) #24期出版社 # 查詢一下 24期出版社出版過哪些書 obj = models.Publish.objects.filter(name='24期出版社').first() ret = obj.book_set.all() #<QuerySet [<Book: 母豬的產後護理>, <Book: 海狗的慫逼人生>]> for i in ret: print(i.title)
一句話歸納 是兩個的表的關係屬性在哪一個表裏(類) 不是外鍵字段存在哪一個表 解釋 1.多對多須要創建在數據之上 由於沒有數據的支持沒辦法創建外鍵,創建外鍵約束 2.多對多采用把關係存在第三張表裏 3.基於對象的查詢是根據屬性查詢 4.兩個表的關係屬性在哪一個表裏 哪一個表就是正向查詢
# 多對多 若是post請求多個值使用getlist(字段) 寫法 obj=request.POST.getlist("author_id") #取得的是一個列表 # 海狗的慫逼人生 是哪些做者寫的 -- 正向查詢 obj = models.Book.objects.filter(title='海狗的慫逼人生').first() ret = obj.authors.all()#能夠直接查詢到做者對應的名字 (直接查詢到) print(ret) #<QuerySet [<Author: 王洋>, <Author: 海狗>]> for i in ret: print(i.name) # 查詢一下海狗寫了哪些書 -- 反向查詢 obj = models.Author.objects.filter(name='海狗').first() ret = obj.book_set.all() print(ret) for i in ret: print(i.publishs.name) print(i.title) return HttpResponse('ok')
原生sql語句寫法
select emp.name from emp inner join dep on dep.id=emp.id where emp.name='技術部'; select emp.name from dep inner join emp on dep.id=emp.id where emp.name='技術部';
在配置裏面設置顯示orm的操做的原生sql語句
注意
1.表的查詢前後指定哪一個表均可以 2.value裏面是什麼 查詢出來字典的鍵就是什麼, 3.能夠查詢出來多個不用.all() 4.屬性__字段 小寫表名__字段都是關聯表字段
表的查詢前後指定哪一個表均可以 #正向查詢 寫法 models.含有外鍵關聯屬性的表名.filter(本表字段=條件).value( 屬性_ _外鍵字段) 海狗的慫逼人生這本書是哪一個出版社出版的 #反向查詢 寫法 models.不含有外鍵關聯屬性的表名.filter(小寫表名_ _字段).values('本表字段') 示例 海狗的慫逼人生這本書是哪一個出版社出版的 ret = models.Publish.objects.filter(book__title='海狗的慫逼人生').values('name') print(ret) #<QuerySet [{'name': '24期出版社'}]>
反向查詢返回多個值 寫法 models.不有外鍵關聯屬性的表名.filter(本表字段=條件).value( 小寫表名_ _字段) 示例 查詢一下24期出版社出版了哪些書 #反向查詢返回多個值 ret = models.Publish.objects.filter(name='24期出版社').values('book__title') print(ret) #<QuerySet [{'book__title': '華麗的產後護理'}, {'book__title': '海狗的慫逼人生'}]> 正向查詢返回多個值 寫法 models.含有外鍵關聯屬性的表名.filter(屬性_ _字段).values('本表字段') #示例 查詢一下24期出版社出版了哪些書 #正向查詢返回多個值 ret = models.Book.objects.filter(publishs__name='24期出版社').values('title') print(ret) #<QuerySet [{'title': '華麗的產後護理'}, {'title': '海狗的慫逼人生'}]>
示例
# 查詢一下王洋的電話號碼 #正向 ret = models.Author.objects.filter(name='王洋').values('au__telephone') #反向 ret = models.AuthorDetail.objects.filter(author__name='王洋').values('telephone') # print(ret) #<QuerySet [{'au__telephone': '110'}]> #<QuerySet [{'telephone': '110'}]>
示例
海狗的慫逼人生這本書是哪一個出版社出版的 #正向 ret = models.Book.objects.filter(title='海狗的慫逼人生').values('publishs__name') print(ret) #<QuerySet [{'publishs__name': '24期出版社'}]> #反向 ret = models.Publish.objects.filter(book__title='海狗的慫逼人生').values('name') print(ret) #<QuerySet [{'name': '24期出版社'}]> #返回多個值 查詢一下24期出版社出版了哪些書 #反向查詢返回多個值 ret = models.Publish.objects.filter(name='24期出版社').values('book__title') print(ret) #<QuerySet [{'book__title': '華麗的產後護理'}, {'book__title': '海狗的慫逼人生'}]> #正向查詢返回多個值 ret = models.Book.objects.filter(publishs__name='24期出版社').values('title') print(ret) #<QuerySet [{'title': '華麗的產後護理'}, {'title': '海狗的慫逼人生'}]>
示例
海狗的慫逼人生 是哪些做者寫的 正向 返回多個值 authors__name 是屬性__外鍵字段 ret = models.Book.objects.filter(title='海狗的慫逼人生').values('authors__name') print(ret) 反向 返回多個值 book__title 是小寫表名__外鍵字段 ret = models.Author.objects.filter(book__title='海狗的慫逼人生').values('name') print(ret) #<QuerySet [{'name': '王洋'}, {'name': '海狗'}]>
補充
寫法
related_name==xxx 別名 注意用了必須用 之後就代指這個字段
查看原生sql語句的配置
arregate 聚合
不分組聚合只取一個最大的
1.須要引用模塊 2.聚合查詢是orm結束符 3.查詢出來的值是python的字典 4.不能再繼續篩選
from django.db.models import AVG,SUM,Max arregate (*args,**kwargs)聚合 1.單個聚合函數 ret=models.表名.objects.all().arregate(AVG('字段名')) 2.多個聚合函數 ret=models.表名.objects.all().arregate(AVG('字段名'),Max('字段名'))
# 計算全部圖書的平均價格 from app01.models import Book from django.db.models import Avg models.Book.objects.all().aggregate(Avg('price')) Book.objects.all().aggregate(Avg('price')) #或者給它起名字(查詢出來字典顯示的鍵):aggretate(a=Avg('price')) {'price__avg': 34.35}
annotate其實就是對分組結果的統計
分組執行的順序
例如 models.Book.objects.annotate(max=Max('price')).arregate(Avg('max')) #分組完進一步用聚合函數篩選 1.以book的id進行分組 2.annotate(max=Max('price'))#以最高的價錢進行統計起一個別名max 3.arregate(Avg('max')#把篩選完的表名 進一步進行篩選 4.arregate是orm的最後結束符
跨表分組查詢本質就是將關聯表join成一張表,再按單表的思路進行分組查詢,,既然是join連表,就可使用我們的雙下劃線進行連表了。
注意
1.查詢的平均值的字段必需要起別名 用values進行別名取值 vlues('別名') 2.values是分組的依據 能夠屬性能夠字段 3.能夠直接 model.表名.objects.annotate #默認依據表名的id主鍵進行分組
#單表 select dep,Count(*) from emp group by dep; #多表 select dep.name,Count(*) from emp left join dep on emp.dep_id=dep.id group by dep.id;
兩種寫法 第一種 指定字段分組 models.分組的表名.objects.values('分組的字段').annotate(別名=聚合函數('字段名')).values('別名') #別名取值 #示例 models.emp.objects.values("dep").annotate(c=Count("id")).values('c') #對象.values() models.dep.objetcs.values("id").annotate(c=Count("emp")).values("name","c") 第二種 不指定values分組默認id進行分組 models.分組的表名.objects.annotate(別名=聚合函數('字段名')).values('別名') # 示例 ret = models.Publish.objects.annotate(a=Avg('book__price')).values('a') # print(ret) #<QuerySet [{'a': None}, {'a': 71.166667}, {'a': 6.0}]>
比較同一個 model (同一個表)實例中兩個不一樣字段的值。
能夠查詢出來全部進行修改
from django.db.models import Avg, Sum, Max, Min, Count,F F('本表字段') #示例 from django.db.models import Avg, Sum, Max, Min, Count,F #查詢一下評論數大於點贊數的書 兩個字段進行比較 ret = models.Book.objects.filter(comment__gt=F('good')) print(ret) 查詢出全部本表字段進行修改 將全部書的價格上調100塊 # models.Book.objects.all().update( # price=F('price')+100 # )
filter()
等方法中的關鍵字參數查詢都是一塊兒進行「AND」 的。 若是你須要執行更復雜的查詢(例如OR
語句),你可使用Q 對象
。
或查詢 q() #注意 models.Book.objects.filter(Q(id=2),price=3) 不能寫在Q()前面會報錯
或| 與& 非~ q()|q() q()&q() q()|~q() 1.單層 q('字段'__比較=值)|q('字段'__比較=值) 2.多層嵌套 關鍵字必須 寫在q查詢以後會報錯 想要寫以前就要用q() #示例 ret = models.Book.objects.filter(Q(id=2)&Q(Q(price__gt=112)|~Q(comment__lte=200))) print(ret)
raw()# 取的是一個對象 寫法 ret = models.Student.objects.raw('select * from app02_teacher', translations=d) for i in ret: print(i.id, i.sname, i.haha) 須要for 循環
django封裝的
from django.db import connection, connections cursor = connection.cursor() # cursor = connections['default'].cursor() cursor.execute("""SELECT * from auth_user where id = %s""", [1]) ret = cursor.fetchone()
1.是保存在用戶瀏覽器上的鍵值對,向服務端發送請求時會自動攜帶 2.cookie能夠經過 瀏覽器進行cookie刪除 max_age=None 多少秒以後自動失效 expires=None固定的時間 path="/" domain 能夠設置指定域名 http=true 就能夠設置cookie 能不能修改
document.cookie="k1=wy222;path=/"#js寫法 $.cookie("k1","wy222",{path:'/'})#jquery寫法
path默認全部域名"/" 1./ 根目錄當前網站的全部的url都能讀取到此值 2.""只能在當前頁面訪問的到此數據 3./index/,只能在/index/xxx的網頁中查看 後臺默認在根目錄也就是path=’/’ cookie修改須要指定根目錄 "decument.cookie=121313 path= /" 不寫默認path爲""
不安全 可使用瀏覽器進行修改能夠獲取到敏感數據
view.py寫法 def login(requset): if requset.method=='GET': return render(requset,'login.html',{'age':18}) # 獲取用戶提交的用戶名和密碼 user = request.POST.get('user')#獲取鍵對應的值 pwd = request.POST.get('pwd')#獲取鍵對應的值 #判斷用戶名和密碼 user_object=models.UserInfo.objects.filter(username=user,password=pwd).first() if user_object: # 用戶登陸成功 result = redirect('/index/') #在寫入一個cookie result.set_cookie('xxxxxxxx',user) return result # 用戶名或密碼輸入錯誤 return render(request,'login.html',{'error':'用戶名或密碼錯誤'}) def index(request): """ 博客後臺首頁 :param request: :return: """ #拿到存到瀏覽器的cookie user = request.COOKIES.get('xxxxxxxx') if not user:#若是沒有得到 return redirect('/login/')#返回頁面 return render(request,'index.html',{'user':user})
爲防止經過url直接訪問頁面 使用cookie進行判斷
避免把敏感數據存儲在瀏覽器使用到了session
是一種存儲數據的方式,依賴於cookie,實現本質: 用戶(瀏覽器(向服務端發送請求,服務端作兩件事: 1.生成隨機字符串; 2.爲此用戶開闢一個獨立的空間來存放當前用戶獨有的值(數據).
request.session['x1'] = 123 request.session['x2'] = 456 request.session['x2']若是不存在會報錯keyerror錯誤#在空間中取值: request.session.get('x2') #視圖函數中的業務操做處理完畢,給用戶響應,在響應時會 將隨機字符串存儲到用戶瀏覽器的cookie中
session中的數據是根據用戶相互隔離. 示例 def login(request): # 獲取用戶提交的用戶名和密碼 user = request.POST.get('user') request.session['user_name'] = user def index(request): print(request.session['user_name'])
cookie是存儲在客戶端瀏覽器上的鍵值對,發送請求時瀏覽器會自動攜帶 session是一種存儲數據方式 依賴cookie基於cookie實現,將數據存儲在服務端 (django默認)
- (默認在數據庫) - 小系統:默認放在數據庫便可. 大系統:緩存(redis)
SESSION_ENGINE = 'django.contrib.sessions.backends.file' #引擎把session放入文件中 SESSION_FILE_PATH = '/ssss/' #在根目錄的/ssss生成一個隨機文件
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_CACHE_ALIAS = 'default' CACHES = { 'default': { 'BACKEND':'django.core.cache.backends.locmem.LocMem Cache', 'LOCATION': 'unique-snowflake', } }
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' SESSION_CACHE_ALIAS = 'default' CACHES = { "default": { "BACKEND":"django_redis.cache.RedisCache", "LOCATION": "redis://127.0.0.1:6379", "OPTIONS": { "CLIENT_CLASS":"django_redis.client.DefaultClient", "CONNECTION_POOL_KWARGS": { "max_connections": 100} # "PASSWORD": "密碼", } } }
from django.shortcuts import render,redirect from app01 import models def login(request): """ 用戶登陸 :param request: :return: """ if request.method == 'GET': return render(request, 'login.html') # 獲取用戶提交的用戶名和密碼 user = request.POST.get('user') pwd = request.POST.get('pwd') print(user,pwd) # 去數據庫檢查用戶名密碼是否正確 user_object = models.UserInfo.objects.filter(username=user, password=pwd).first() if user_object: request.session['user_name']=user_object.username#名字存入session request.session['user_id']=user_object.pk#id存入session return redirect('/index/')#重定向頁面 # 用戶名或密碼輸入錯誤 return render(request,'login.html',{'error':'用戶名或密碼錯誤'}) def index(request): """ 博客後臺首頁 :param request: :return: """ name=request.session.get("user_name") if not name: return redirect('/login/') return render(request,'index.html',{'user':name}) ·············································· 簡化版爲了減小登錄驗證的重複 ·············································· from django.shortcuts import render,redirect from app01 import models def login(request): """ 用戶登陸 :param request: :return: """ if request.method == 'GET': return render(request, 'login.html') # 獲取用戶提交的用戶名和密碼 user = request.POST.get('user') pwd = request.POST.get('pwd') print(user,pwd) # 去數據庫檢查用戶名密碼是否正確 user_object = models.UserInfo.objects.filter(username=user, password=pwd).first() if user_object: request.session['user_name']=user_object.username#名字存入session request.session['user_id']=user_object.pk#id存入session return redirect('/index/')#重定向頁面 # 用戶名或密碼輸入錯誤 return render(request,'login.html',{'error':'用戶名或密碼錯誤'}) def auth(func):#防止屢次判斷 簡化判斷 裝飾器 @functools.wraps(func) def inner( request,*args,**kwargs): name = request.session.get("user_name") if not name: return redirect('/login/') return func(request,*args,**kwargs) return inner @auth def index(request): """ 博客後臺首頁 :param request: :return: """ return render(request,'index.html')
# 設置(添加&修改) request.session['x1'] = 123 request.session['x2'] = 456 # 讀取 request.session['xx'] #讀取不到會報key error錯誤 request.session.get('xx')#讀取不到值返回none (不報錯) # 刪除 del request.session['xx'] request.session.keys() #獲取當前session的鍵 request.session.values() #獲取當前session的值 request.session.items() #獲取當前session的鍵值對 # 設置會話Session和Cookie的超時時間 request.session.set_expiry(value) * 若是value是個整數,session會在些秒數後失效。 * 若是value是個datatime或timedelta,session就會在這個時間後失效。 * 若是value是0,用戶關閉瀏覽器session就會失效。 * 若是value是None,session會依賴全局session失效策略。 request.session.session_key 獲取sessionid(隨機字符串)的值
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在瀏覽器上時的key能夠修改,即: sessionid=隨機字符串 SESSION_COOKIE_DOMAIN = None #session的cookie保存的域名(均可以在那個域名,子域名下可用 全部的域名均可用讀取到) # api.baidu.com /www.baidu.com/ xxx.baidu.com SESSION_COOKIE_PATH = "/" # Session的cookie 保存的路徑 SESSION_COOKIE_HTTPONLY = True # 是否 Session的cookie只支持http傳輸 只能讀不能修改 SESSION_COOKIE_AGE = 1209600 # Session的 cookie失效日期(2周) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否關閉瀏覽器使得Session過時 SESSION_SAVE_EVERY_REQUEST = False # 是否每 次請求都保存Session,默認修改以後才保存 request會刷新 ture 按照最後一次刷新時間 false 會在兩週以後過時
SESSION_COOKIE_AGE = 1209600 # Session的 cookie失效日期(2周)