什麼是orm?python
MVC框架中重要的一部分就是ORM,實現了數據模型與數據庫的解耦,即數據模型不須要依賴於特定的數據庫,經過簡單的配置就能夠輕鬆更換數據庫。mysql
ORM是對象關係映射的簡稱,主要任務是:git
ORM的優點:正則表達式
數據庫的配置sql
1.默認支持數據庫
Django默認支持sqlite,mysql, oracle,postgresql數據庫。默認使用sqlite的數據庫,默認自帶sqlite的數據庫驅動 , 引擎名稱:django.db.backends.sqlite3。django
配置前必須先建立數據庫緩存
create database Django_books charset utf8; #建立支持中文的數據庫
4.更改項目中settings.py的數據庫設置oracle
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'Django_Books', #你的數據庫名稱 'USER': 'root', #你的數據庫用戶名 'PASSWORD': '123456', #你的數據庫密碼 'HOST': 'localhost', #你的數據庫主機,留空默認爲localhost 'PORT': '3306', #你的數據庫端口 } }
Django默認導入的驅動是MySQLdb,MySQLdb對python3的支持有很大問題,因此要換成PyMySQL:在項目名文件夾下的__init__.py中:app
import pymysql pymysql.install_as_MySQLdb() # 告訴Django使用pymysql驅動程序
擴展:查看ORM操做執行的原生sql語句,在settings.py中增長:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
表(模型)的建立
示例:做者、書籍和出版社之間的關係
from django.db import models class Book(models.Model): name = models.CharField(max_length=20) price = models.IntegerField() pub_data = models.DateField() author = models.ManyToManyField("Author") publish = models.ForeignKey("Publish",on_delete=models.CASCADE) class Author(models.Model): name = models.CharField(max_length=32) sex = models.BooleanField(max_length=1,choices=((0,"男"),(1,"女"),)) phone = models.CharField(max_length=11) class Publish(models.Model): name = models.CharField(max_length=30) address = models.CharField("地址",max_length=150)
字段類型介紹
AutoField 自增列 = int(11) 若是沒有的話,默認會生成一個名稱爲 id 的列,若是要顯示的自定義一個自增列,必須將給列設置爲主鍵 primary_key=True。 CharField 字符串字段 必須有 max_length 參數 BooleanField 布爾類型=tinyint(1) 不能爲空,Blank=True ComaSeparatedIntegerField 用逗號分割的數字=varchar 繼承CharField,因此必須 max_lenght 參數 DateField 日期類型 date 對於參數,auto_now = True 則每次更新都會更新這個時間;auto_now_add 則只是第一次建立添加,以後的更新再也不改變。 DateTimeField 日期類型 datetime 同DateField的參數 Decimal 十進制小數類型 = decimal 必須指定整數位max_digits和小數位decimal_places EmailField 字符串類型(正則表達式郵箱) =varchar 對字符串進行正則表達式 FloatField 浮點類型 = double IntegerField 整形 BigIntegerField 長整形 不一樣的整型類型integer_field_ranges = { 'SmallIntegerField': (-32768, 32767), 'IntegerField': (-2147483648, 2147483647), 'BigIntegerField': (-9223372036854775808, 9223372036854775807), 'PositiveSmallIntegerField': (0, 32767), 'PositiveIntegerField': (0, 2147483647), } IPAddressField 字符串類型(ip4正則表達式)(已棄用,用1三、) GenericIPAddressField 字符串類型(ip4和ip6是可選的)參數protocol能夠是:both、ipv四、ipv6 驗證時,會根據設置報錯 NullBooleanField 容許爲空的布爾類型 PositiveIntegerFiel 正Integer PositiveSmallIntegerField 正smallInteger SlugField 減號、下劃線、字母、數字 TextField 字符串=longtext TimeField 時間 HH:MM[:ss[.uuuuuu]] URLField 字符串,地址正則表達式 BinaryField 二進制 ImageField 圖片 FilePathField 文件
null 是否能夠爲空 default 默認值 primary_key 主鍵 choices: 一個用來選擇值的2維元組。第一個值是實際存儲的值,第二個用來方便進行選擇。如:SEX_CHOICES= (( ‘F’,'Female’),(‘M’,'Male’),) gender = models.CharField(max_length=2,choices = SEX_CHOICES) db_column 列名 db_index 索引(db_index=True) unique 惟一索引(unique=True) unique_for_date 只對日期索引 unique_for_month 只對月份索引 unique_for_year 只對年作索引 blank django的 Admin 中添加數據時是否可容許空值 editable 若是爲假,admin模式下將不能改寫。缺省爲真 verbose_name Admin中字段的顯示名稱 validator_list 有效性檢查。非有效產生 django.core.validators.ValidationError 錯誤
有三種關係:一對一,一對多,多對多
一對一:實質就是在主外鍵的關係基礎上,給外鍵加了一個UNIQUE=True的屬性;OneToOne("UserGroup")
一對多:就是主外鍵關係;ForeignKeyField("UserGroup",to_field="gid",default=1,on_delete=models.CASCADE)
多對多:ORM會爲咱們自動建立第三張表(固然咱們也能夠本身建立第三張表:兩個foreign key);ManyToManyField("UserGroup")
參數:「UserGroup」 關聯的另外一張表的表名;
to_field="gid" 可省略。另一張表的字段,默認是主鍵;
on_delete=models.CASCADE(
CASCADE:這就是默認的選項,級聯刪除,你無需顯性指定它。
PROTECT: 保護模式,若是採用該選項,刪除的時候,會拋出ProtectedError錯誤。
SET_NULL: 置空模式,刪除的時候,外鍵字段被設置爲空,前提就是blank=True, null=True,定義該字段的時候,容許爲空。
SET_DEFAULT: 置默認值,刪除的時候,外鍵字段設置爲默認值,因此定義外鍵的時候注意加上一個默認值。)
python manage.py makemigrations 在應用文件夾內生成映射文件(000開頭的py文件) python manage.py migrate 提交數據庫執行建表
表的操做
增添表記錄
單表: create()方法: Book.objects.create(name="Python基礎",price=100) 或 Book.objects.create(**{"name":"Python基礎","price":"100"}) save()方法: b = Book(name="Python基礎",price=100) # 建立對象 b.save() # 將對象存數據庫 或 b = Book() b.name="Python基礎" b.price=100 b.save() 有外鍵時: Book.objects.create(name="",price="",pub_date="",publish_id=2) # 外鍵關聯表的id 或 objcet = Publish.objects.get(); Book.objects.create(name="",price="",pub_date="",publish=object) # 外鍵=對象
增添多對多之間的關聯關係
情景1:使用ManyToMany自動建立第三張表 add()方法:【調用add的主體必須是單個model對象】 例如:爲已有的一本書增添做者 author_obj = Author.objects.filter(name="alex") book_obj = Book.objects.get(id=2) book_obj.author.add(*author_obj) 這裏的author指的是Author表。添加一個列表* 添加一個字典** 或: book_obj = Book.objects.filter(name="Python") author_obj = Author.object.get(id=1) author_obj.book_set.add(*book_obj) 這裏的book指的是Book表。 注意兩種方式 _set 的區別,源於models.py中建表的author字段 情景2:本身手動建立的第三張表BookToAuthor models.BookToAuthor.objects.create(author_id=1,Book_id=2)
刪除表記錄
Book.objects.filter(name="Python").delete() # 看上去刪除了一條消息,實際上還刪除了book_author表中的數據, 這是django默認的級聯刪除
刪除多對多之間的關聯關係
clear()和remove()方法 【調用這兩種方法的主體必須是單個對象】 remove()方法: remove方法用來刪除某個對象和某些對象的關聯關係 爲已有的一本書刪除某個做者 author_obj = Author.objects.filter(name="alex") book_obj = Book.objects.get(name="Python") book_obj.author.remove(*author_obj) remove(3) 意思是刪除id=3的做者與本書的關係 或: book_obj = Book.objects.filter(name="Python") author_obj = Author.object.get(name="Python") author_obj.book_set.remove(*book_obj) clear()方法: clear方法用來刪除某個對象和全部對象的關聯關係 book_obj.author.remove(*author_obj) 刪除做者alex和Python書之間的關聯 book_obj.author.clear() 刪除Python和全部做者的關聯 author_obj[0].book_set.clear() 刪除做者alex和全部書的關聯 注意:當clear()方法和remove()應用在ForeignKey上時,必需null=True才能用
修改表數據
update()方法: Book.objects.filter(author="yuan").update(price=100) save()方法: b = Book.objects.get(author="oldboy") b.price = 200 b.save() 須要注意: 1.update()是QuerySet對象的方法,而save()是model對象的方法。即update能夠一次性修改多條記錄的數據,並返回一個整型數值,表示受影響的記錄條數。而save一次只能修改一條記錄 2.save() 方法會將全部屬性從新設定一遍,效率低。而update只更改指定的屬性,因此修改數據推薦用update
若是要修改多對多表之間的關係:
沒有專門的方法,能夠將remove()和add()組合使用
查詢API: filter(**kwargs) 它包含了與所給篩選條件相匹配的對象 all() 查詢全部結果 get(**kwargs) 返回與所給篩選條件相匹配的對象,返回結果有且只有一個,若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。 下面的方法都是對查詢的結果再進行處理:好比 objects.filter.values() values(*field) 返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列model的實例化對象,而是一個可迭代的字典序列 values_list(*field) 它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列 exclude(**kwargs) 它包含了與所給篩選條件不匹配的對象 order_by(*field) 對查詢結果排序,例如order_by("price")按照價格從小到大排序,order_by("-price")從大到小排序 reverse() 對查詢結果反向排序 distinct() 從返回結果中剔除重複紀錄 count() 返回數據庫中匹配查詢(QuerySet)的對象數量。 first() 返回第一條記錄 last() 返回最後一條記錄 exists() 若是QuerySet包含數據,就返回True,不然返回False。不會保存在緩存裏。
擴展查詢:有時候Django的查詢API不能方便地設置查詢條件,提供了另外的擴展查詢方法extra()
extra(select=None, where=None, params=None, tables=None,order_by=None, select_params=None) extra能夠指定一個或多個參數,都不是必需的,但要至少使用一個。 參數詳解: 1.select和select_params select這個參數內能夠直接寫SQL查詢語句或者函數,select_params用來給select中的語句傳值 例: v = models.Publish.objects.all().extra(select={ 'n':"select count(1) from app01_book WHERE id=%s or id=%s", 'm':"select count(1) from app01_author WHERE id=%s or id=%s", },select_params=(1,2,3,4)) 這裏取到了全部Publish表中的數據,同時還取到了如下兩個SQL語句中的東西。 for i in v: print(i.n,i.m,i.id) 2.where和params where用來直接寫查詢條件,parems給where中傳值 例: models.Book.objects.extra(where=['parice=%s'], params=['99']) models.Book.objects.extra(where=["'parice=100' OR name='Python'","id=1" ]) 3.tables用來查詢整張表 例: models.Author.objects.extra(tables=["app01_book"]) <=> select * from app01_book,app01_author models.Book.objects.extra(tables=["app01_author"],where=["app01_book.id = app01_author.id"]) <=> select * from app01_book,app01_author where app01_book.id = app01_author.id 4.order_by用來排序 綜合示例1: models.Author.objects.extra( select={"newid":"select count(1) from app01_book where id>%s"}, select_params=[1,], where=["args>%s"], params=[18,], order_by=["-ages"], ) <=> select app01_author.id, (select count(1) from app01_book where id>1) as newid from app01_author,app01_book where app01_author.age > 18 order by app01_author.age desc 綜合示例2: models.Article.objects.all().filter(user=current_user).extra(select={"filter_create_date":"strftime(‘%%Y/%%m‘,create_time)"}).values_list("filter_create_date") #查出當前用戶的全部文章的create_time,而且只取出年份和月份
單表模糊查詢:(雙下劃線)
萬能的 __雙下劃線 __gt 大於 __gte 大於等於 __lt 小於 __lte 小於等於 __icontains="p" 含有p且不區分大小寫 __contains="p" 含有p且區分大小寫 __exat="aaa" 至關於 like "aaa" __iexat="aaa" 至關於忽略大小寫 like "aaa" _in=[10,20,33,50] 獲取id等於10,20,33,50的數據 __exclude(id_in=[]) 不等於10 20 33 50的 __range=[1,2] 在範圍內的 __startswith 以...開頭 __istartswith 不以...開頭 __endswith 以...結尾 __iendswith 不以...結尾 __year 日期字段的年份 __month 日期字段的月份 __day 日期字段的日 __isnull=True/False filter(price__gt=100) 篩選價格大於100的 filter(id__gt=1,id__lt=10) id大於1小於10
1.查多條記錄(__ 雙下劃線) 找到Python這本書的出版社名稱 Book.objects.filter(name="Python").values("publish__name") 經過外鍵[publish是Book表的外鍵] Publish.objects.filter(book__name="Python").values("name") 經過對象[book是Publish關聯的表名] 2.(只能查單條記錄,不經常使用) 正向查詢(經過書查出版社) Book.objects.get(name="").publish --> 出版社對象 print(publish.屬性) 反向查詢(經過出版社找書) Publish.objects.get(name="").book_set.all() -->全部的書籍對象 注意:book_set 是模型對象中反向查詢的語法,book是表名,所有小寫 調用 _set 的主體必須是單個對象!!
所謂惰性機制,models查詢語句只是返回了一個Queryset對象,並不會立刻執行SQL,而是使用查詢結果的時候才執行。
例如:person_set = Person.objects.filter(first_name="Dave")這句話並無運行數據庫查詢,當遍歷Queryset、if queryset或者在模板渲染的時候使用的時候纔會執行數據庫查詢操做
Qureyset的特色:可迭代、可切片、有緩存。
※ Queryset是有緩存的
當遍歷Queryset時,匹配的記錄會從數據庫獲取,而後轉換成Django的model。這些model會保存在Queryset內置的緩存中,若是再次遍歷或者使用這個Queryset時,不須要重複的查詢。
而若是處理成千上萬的記錄時,一次性裝入內存是很是浪費的。要避免產生Queryset緩存,可使用iterator()方法來獲取數據,處理完數據就將其丟棄。
objs = Book.objects.all().iterator() for obj in objs: print(obj.name)
迭代器不能重複遍歷,意味着可能會形成額外的重複查詢。而緩存是用於減小對數據庫的查詢。因此使用時要考慮需求。
from django.db.models import Avg,Min,Sum,Max,Count
聚合查詢:aggregate(*args,**kwargs):
aggregate()是Queryset的一個終止子句,經過對Queryset進行計算,返回一個聚合值的字典。從整個查詢集上生成聚合值。
aggregate()子句的參數描述了咱們想要計算的聚合值,如平均Avg,求和Sum等
例如:
Book.objects.all().aggregate(Avg('price')) # 計算全部在售書的平均價錢 {'price__avg': 34.35} Book.objects.aggregate(average_price=Avg('price')) # 自定義標識符(鍵) {'average_price': 34.35} Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) # 同時輸出多個聚合值 {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
分組查詢: annotate(*args,**kwargs):
分組查詢經常和聚合查詢一塊兒。它能夠爲查詢集的每一項生成聚合。
# 查詢每一個做者出書的總價格,按照做者分組 Book.objects.all().values("authors__name").annotate(Sum("price")) [{'authors__name':'alex','price_sum':'140'},{'authors__name':'alvin','price_sum':'160'}] # 查詢各個出版社最便宜的書的價格 Book.objects.all().values("pulisher__name").annotate(Min("price")) [{'publisher__name':'清華大學出版社','price_min':'70'},{'publisher__name':'中國機械出版社','price_min':'90'}]
from django.db.models import F,Q
F查詢:就是用來更新獲取原來值的功能
models.Author.objects.all().update(age=F("age")+1) # 將Author表裏全部人的年齡+1 models.Book.objects.all().update(price=F("price")+10) # 將全部書的價格漲10元
Q查詢:用於構造複雜的查詢條件,如 與、或、非。
查詢條件咱們可使用filter()方法,在filter()裏面的兩個條件之間是and的關係,若是是或的關係,則只能使用Q查詢
Book.objects.filter(Q(id=1)) # 查詢條件爲id=1 Book.objects.filter(Q(price=99) | ~Q(name="Python")) # 查詢價格=99 或 名稱不等於Python的書 Book.objects.filter(Q(name="Go"),price=99) # Q查詢能夠和關鍵字查詢組合使用,但必需要將Q放到前面