數(shù)據(jù)庫(kù)與ORM
1) 數(shù)據(jù)庫(kù)的配置
1.1) django默認(rèn)支持sqlite, mysql, oracle, postgresql 數(shù)據(jù)庫(kù)
<1> sqlite
django默認(rèn)使用sqlite的數(shù)據(jù)庫(kù),默認(rèn)自帶sqlite的數(shù)據(jù)庫(kù)驅(qū)動(dòng) , 引擎名稱:django.db.backends.sqlite3
<2> mysql
引擎名稱:django.db.backends.mysql
1.2) mysql驅(qū)動(dòng)程序
- MySQLdb(mysql python)
- mysqlclient
- MySQL
- PyMySQL(純python的mysql驅(qū)動(dòng)程序)
1.3) 在django的項(xiàng)目中會(huì)默認(rèn)使用sqlite數(shù)據(jù)庫(kù),在settings里有如下設(shè)置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
如果我們想要更改數(shù)據(jù)庫(kù)為mysql,需要修改如下:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_com',
'USER': 'root',
'PASSWORD': '',
}
}
- 數(shù)據(jù)庫(kù)設(shè)置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'books', #你的數(shù)據(jù)庫(kù)名稱
'USER': 'root', #你的數(shù)據(jù)庫(kù)用戶名
'PASSWORD': '', #你的數(shù)據(jù)庫(kù)密碼
'HOST': '', #你的數(shù)據(jù)庫(kù)主機(jī),留空默認(rèn)為localhost
'PORT': '3306', #你的數(shù)據(jù)庫(kù)端口
}
}
注意事項(xiàng):
NAME即數(shù)據(jù)庫(kù)的名字,在mysql連接前該數(shù)據(jù)庫(kù)必須已經(jīng)創(chuàng)建,而上面的sqlite數(shù)據(jù)庫(kù)下的db.sqlite3則是項(xiàng)目自動(dòng)創(chuàng)建
USER和PASSWORD分別是數(shù)據(jù)庫(kù)的用戶名和密碼。
設(shè)置完后,再啟動(dòng)我們的Django項(xiàng)目前,我們需要激活我們的mysql。
然后,啟動(dòng)項(xiàng)目,會(huì)報(bào)錯(cuò):no module named MySQLdb
這是因?yàn)閐jango默認(rèn)你導(dǎo)入的驅(qū)動(dòng)是MySQLdb,可是MySQLdb對(duì)于py3有很大問(wèn)題,所以我們需要的驅(qū)動(dòng)是PyMySQL
所以,我們只需要找到項(xiàng)目名文件下的__init__,在里面寫入:
import pymysql
pymysql.install_as_MySQLdb()
問(wèn)題解決!
2) ORM表模型
2.1) 表(模型)的創(chuàng)建:
實(shí)例:我們來(lái)假定下面這些概念,字段和關(guān)系
<1>作者模型:一個(gè)作者有姓名。
<2>作者詳細(xì)模型:把作者的詳情放到詳情表,包含性別,email地址和出生日期,作者詳情模型和作者模型之間是一對(duì)一的關(guān)系(one-to-one)(類似于每個(gè)人和他的身份證之間的關(guān)系),在大多數(shù)情況下我們沒(méi)有必要將他們拆分成兩張表,這里只是引出一對(duì)一的概念。
<3>出版商模型:出版商有名稱,地址,所在城市,省,國(guó)家和網(wǎng)站。
<4>書籍模型:書籍有書名和出版日期,一本書可能會(huì)有多個(gè)作者,一個(gè)作者也可以寫多本書,所以作者和書籍的關(guān)系就是多對(duì)多的關(guān)聯(lián)關(guān)系(many-to-many),一本書只應(yīng)該由一個(gè)出版商出版,所以出版商和書籍是一對(duì)多關(guān)聯(lián)關(guān)系(one-to-many),也被稱作外鍵。
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30, verbose_name="名稱")
address = models.CharField("地址", max_length=50)
city = models.CharField('城市',max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Meta:
verbose_name = '出版商'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class Author(models.Model):
name = models.CharField(max_length=30)
def __str__(self):
return self.name
class AuthorDetail(models.Model):
sex = models.BooleanField(max_length=1, choices=((0, '男'),(1, '女'),))
email = models.EmailField()
address = models.CharField(max_length=50)
birthday = models.DateField()
author = models.OneToOneField(Author)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2,default=10)
def __str__(self):
return self.title
代碼分析:
<1> 每個(gè)數(shù)據(jù)模型都是django.db.models.Model的子類,它的父類Model包含了所有必要的和數(shù)據(jù)庫(kù)交互的方法。
<2> 每個(gè)模型相當(dāng)于單個(gè)數(shù)據(jù)庫(kù)表(多對(duì)多關(guān)系例外,會(huì)多生成一張關(guān)系表),每個(gè)屬性也是這個(gè)表中的字段。屬性名就是字段名,它的類型(例如CharField)相當(dāng)于數(shù)據(jù)庫(kù)的字段類型(例如varchar)。
<3> 模型之間的三種關(guān)系:一對(duì)一,一對(duì)多,多對(duì)多
- 一對(duì)一:實(shí)質(zhì)就是在主外鍵(author_id就是foreign key)的關(guān)系基礎(chǔ)上,給外鍵加了一個(gè)UNIQUE=True的屬性
- 一對(duì)多:就是主外鍵關(guān)系;(foreign key)
- 多對(duì)多:(ManyToManyField) 自動(dòng)創(chuàng)建第三張表(當(dāng)然我們也可以自己創(chuàng)建第三張表:兩個(gè)foreign key)
2.2) ORM之增(create, save)
from app01.models import *
#create方式一: Author.objects.create(name='Alvin')
#create方式二: Author.objects.create(**{"name":"alex"})
#save方式一: author=Author(name="alvin")
author.save()
#save方式二: author=Author()
author.name="alvin"
author.save()
## 推薦使用create
重點(diǎn):如何創(chuàng)建存在一對(duì)多或多對(duì)多關(guān)系的一本書的信息呢?(如何處理外鍵關(guān)系的字段如一對(duì)多的publisher和多對(duì)多的authors)
#一對(duì)多(ForeignKey):
#方式一: 由于綁定一對(duì)多的字段,比如publish,存到數(shù)據(jù)庫(kù)中的字段名叫publish_id,所以我們可以直接給這個(gè)
# 字段設(shè)定對(duì)應(yīng)值:
Book.objects.create(title='php',
publisher_id=2, #這里的2是指為該book對(duì)象綁定了Publisher表中id=2的行對(duì)象
publication_date='2017-7-7',
price=99)
#方式二:
# <1> 先獲取要綁定的Publisher對(duì)象:
pub_obj=Publisher(name='河大出版社',address='保定',city='保定',
state_province='河北',country='China',website='http://www.hbu.com')
OR pub_obj=Publisher.objects.get(id=1)
# <2>將 publisher_id=2 改為 publisher=pub_obj
#多對(duì)多(ManyToManyField()):
author1=Author.objects.get(id=1)
author2=Author.objects.filter(name='alvin')[0]
book=Book.objects.get(id=1)
book.authors.add(author1,author2)
#等同于:
book.authors.add(*[author1,author2])
book.authors.remove(*[author1,author2])
#-------------------
book=models.Book.objects.filter(id__gt=1)
authors=models.Author.objects.filter(id=1)[0]
authors.book_set.add(*book)
authors.book_set.remove(*book)
#-------------------
book.authors.add(1)
book.authors.remove(1)
authors.book_set.add(1)
authors.book_set.remove(1)
#注意: 如果第三張表是通過(guò)models.ManyToManyField()自動(dòng)創(chuàng)建的,那么綁定關(guān)系只有上面一種方式
# 如果第三張表是自己創(chuàng)建的:
class Book2Author(models.Model):
author=models.ForeignKey("Author")
Book= models.ForeignKey("Book")
# 那么就還有一種方式:
author_obj=models.Author.objects.filter(id=2)[0]
book_obj =models.Book.objects.filter(id=3)[0]
s=models.Book2Author.objects.create(author_id=1,Book_id=2)
s.save()
s=models.Book2Author(author=author_obj,Book_id=1)
s.save()
2.3) ORM之刪(delete)
Book.objects.filter(id=1).delete()
- django默認(rèn)使用 級(jí)聯(lián)刪除
2.4) ORM之改(update, save)
# <1> 使用update
Publisher.objects.filter(id=2).update(name='American publisher') # 不能用get(id=2)
# <2> 使用save
author = Author.objects.get(id=5)
author.name = 'tenglan'
author.save()
注意:
1)第一種方式修改不能用get的原因是:update是QuerySet對(duì)象的方法,get返回的是一個(gè)model對(duì)象,它沒(méi)有update方法,而filter返回的是一個(gè)QuerySet對(duì)象(filter里面的條件可能有多個(gè)條件符合,比如name='alvin',可能有兩個(gè)name='alvin'的行數(shù)據(jù))。
2)save()方法會(huì)更新一行里的所有列,而某些情況下,我們只需要更新行里的某幾列。
#---------------- update方法直接設(shè)定對(duì)應(yīng)屬性----------------
models.Book.objects.filter(id=3).update(title="PHP")
##sql:
##UPDATE "app01_book" SET "title" = 'PHP' WHERE "app01_book"."id" = 3; args=('PHP', 3)
#--------------- save方法會(huì)將所有屬性重新設(shè)定一遍,效率低-----------
obj=models.Book.objects.filter(id=3)[0]
obj.title="Python"
obj.save()
# SELECT "app01_book"."id", "app01_book"."title", "app01_book"."price",
# "app01_book"."color", "app01_book"."page_num",
# "app01_book"."publisher_id" FROM "app01_book" WHERE "app01_book"."id" = 3 LIMIT 1;
#
# UPDATE "app01_book" SET "title" = 'Python', "price" = 3333, "color" = 'red', "page_num" = 556,
# "publisher_id" = 1 WHERE "app01_book"."id" = 3;
- 此外,update()方法對(duì)于任何結(jié)果集(QuerySet)均有效,這意味著你可以同時(shí)更新多條記錄update()方法會(huì)返回一個(gè)整型數(shù)值,表示受影響的記錄條數(shù)。
注意,這里因?yàn)閡pdate返回的是一個(gè)整型,所以沒(méi)法用query屬性;對(duì)于每次創(chuàng)建一個(gè)對(duì)象,想顯示對(duì)應(yīng)的raw sql,需要在settings加上日志記錄部分:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
2.5) ORM之查(filter, value)
- 查詢API:
# 查詢相關(guān)API:
# <1>filter(**kwargs): 它包含了與所給篩選條件相匹配的對(duì)象
# <2>all(): 查詢所有結(jié)果
# <3>get(**kwargs): 返回與所給篩選條件相匹配的對(duì)象,返回結(jié)果有且只有一個(gè),如果符合篩選條件的對(duì)象超過(guò)一個(gè)或者沒(méi)有都會(huì)拋出錯(cuò)誤。
#-----------下面的方法都是對(duì)查詢的結(jié)果再進(jìn)行處理:比如 objects.filter.values()--------
# <4>values(*field): 返回一個(gè)ValueQuerySet——一個(gè)特殊的QuerySet,運(yùn)行后得到的并不是一系列 model的實(shí)例化對(duì)象,而是一個(gè)可迭代的字典序列 ;-->拿到庫(kù)內(nèi) 固定列內(nèi)的 值作為 一對(duì) key value ;如果條件是多個(gè),那就拿到多對(duì),整體是一個(gè)列表
# <5>exclude(**kwargs): 它包含了與所給篩選條件不匹配的對(duì)象
# <6>order_by(*field): 對(duì)查詢結(jié)果排序
# <7>reverse(): 對(duì)查詢結(jié)果反向排序
# <8>distinct(): 從返回結(jié)果中剔除重復(fù)紀(jì)錄
# <9>values_list(*field): 它與values()非常相似,它返回的是一個(gè)元組序列,values返回的是一個(gè)字典序列;相比于 values 左后是一個(gè) 元祖,不是字典
# <10>count(): 返回?cái)?shù)據(jù)庫(kù)中匹配查詢(QuerySet)的對(duì)象數(shù)量。
# <11>first(): 返回第一條記錄
# <12>last(): 返回最后一條記錄
# <13>exists(): 如果QuerySet包含數(shù)據(jù),就返回True,否則返回False
---------------了不起的雙下劃線(__)之單表?xiàng)l件查詢----------------
# models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大于1 且 小于10的值
#
# models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等于11、22、33的數(shù)據(jù)
# models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
#
# models.Tb1.objects.filter(name__contains="ven")
# models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
#
# models.Tb1.objects.filter(id__range=[1, 2]) # 范圍bettwen and
#
# startswith,istartswith, endswith, iendswith,
雙下劃線
3) django 模型models 常用Field字段
1、models.AutoField
自增列 = int(11)
如果沒(méi)有的話,默認(rèn)會(huì)生成一個(gè)名稱為 id 的列
如果要顯式的自定義一個(gè)自增列,必須設(shè)置primary_key=True。
2、models.CharField
字符串字段
必須設(shè)置max_length參數(shù)
3、models.BooleanField
布爾類型=tinyint(1)
不能為空,可添加Blank=True
4、models.ComaSeparatedIntegerField
用逗號(hào)分割的數(shù)字=varchar
繼承CharField,所以必須 max_lenght 參數(shù)
5、models.DateField
日期類型 date
DateField.auto_now:保存時(shí)自動(dòng)設(shè)置該字段為現(xiàn)在日期,最后修改日期
DateField.auto_now_add:當(dāng)該對(duì)象第一次被創(chuàng)建是自動(dòng)設(shè)置該字段為現(xiàn)在日期,創(chuàng)建日期。
6、models.DateTimeField
日期時(shí)間類型 datetime
同DateField的參數(shù)
7、models.Decimal
十進(jìn)制小數(shù)類型 = decimal
DecimalField.max_digits:數(shù)字中允許的最大位數(shù)
DecimalField.decimal_places:存儲(chǔ)的十進(jìn)制位數(shù)
8、models.EmailField
一個(gè)帶有檢查 Email 合法性的 CharField
9、models.FloatField
浮點(diǎn)類型 = double
10、models.IntegerField
整形
11、models.BigIntegerField
長(zhǎng)整形
integer_field_ranges = {
'SmallIntegerField': (-32768, 32767),
'IntegerField': (-2147483648, 2147483647),
'BigIntegerField': (-9223372036854775808, 9223372036854775807),
'PositiveSmallIntegerField': (0, 32767),
'PositiveIntegerField': (0, 2147483647),
}
12、models.GenericIPAddressField
一個(gè)帶有檢查 IP地址合法性的 CharField
13、models.NullBooleanField
允許為空的布爾類型
14、models.PositiveIntegerFiel
正整數(shù)
15、models.PositiveSmallIntegerField
正smallInteger
16、models.SlugField
減號(hào)、下劃線、字母、數(shù)字
17、models.SmallIntegerField
數(shù)字
數(shù)據(jù)庫(kù)中的字段有:tinyint、smallint、int、bigint
18、models.TextField
大文本。默認(rèn)對(duì)應(yīng)的form標(biāo)簽是textarea。
19、models.TimeField
時(shí)間 HH:MM[:ss[.uuuuuu]]
20、models.URLField
一個(gè)帶有URL合法性校驗(yàn)的CharField。
21、models.BinaryField
二進(jìn)制
存儲(chǔ)二進(jìn)制數(shù)據(jù)。不能使用filter函數(shù)獲得QuerySet。
22、models.ImageField
圖片
ImageField.height_field、ImageField.width_field:如果提供這兩個(gè)參數(shù),則圖片將按提供的高度和寬度規(guī)格保存。
該字段要求 Python Imaging 庫(kù)Pillow。
會(huì)檢查上傳的對(duì)象是否是一個(gè)合法圖片。
23、models.FileField(upload_to=None[, max_length=100, ** options])
文件
FileField.upload_to:一個(gè)用于保存上傳文件的本地文件系統(tǒng)路徑,該路徑由 MEDIA_ROOT 中設(shè)置
這個(gè)字段不能設(shè)置primary_key和unique選項(xiàng).在數(shù)據(jù)庫(kù)中存儲(chǔ)類型是varchar,默認(rèn)最大長(zhǎng)度為100
24、models.FilePathField(path=None[, math=None, recursive=False, max_length=100, ** options])
FilePathField.path:文件的絕對(duì)路徑,必填
FilePathField.match:用于過(guò)濾路徑下文件名的正則表達(dá)式,該表達(dá)式將用在文件名上(不包括路徑)。
FilePathField.recursive:True 或 False,默認(rèn)為 False,指定是否應(yīng)包括所有子目錄的路徑。
例如:FilePathField(path="/home/images", match="foo.*", recursive=True),將匹配 “/home/images/foo.gif” 但不匹配 “/home/images/foo/bar.gif”
4) django 模型models 字段常用參數(shù)
1、null
如果是True,Django會(huì)在數(shù)據(jù)庫(kù)中將此字段的值置為NULL,默認(rèn)值是False
2、blank
如果為True時(shí)django的 Admin 中添加數(shù)據(jù)時(shí)可允許空值,可以不填。如果為False則必須填。默認(rèn)是False。
null純粹是與數(shù)據(jù)庫(kù)有關(guān)系的。而blank是與頁(yè)面必填項(xiàng)驗(yàn)證有關(guān)的
3、primary_key = False
主鍵,對(duì)AutoField設(shè)置主鍵后,就會(huì)代替原來(lái)的自增 id 列
4、auto_now 和 auto_now_add
auto_now 自動(dòng)創(chuàng)建---無(wú)論添加或修改,都是當(dāng)前操作的時(shí)間
auto_now_add 自動(dòng)創(chuàng)建---永遠(yuǎn)是創(chuàng)建時(shí)的時(shí)間
5、choices
一個(gè)二維的元組被用作choices,如果這樣定義,Django會(huì)select box代替普通的文本框,
并且限定choices的值是元組中的值
GENDER_CHOICE = (
(u'M', u'Male'),
(u'F', u'Female'),
)
gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
6、max_length
字段長(zhǎng)度
7、default
默認(rèn)值
8、verbose_name
Admin中字段的顯示名稱,如果不設(shè)置該參數(shù)時(shí),則與屬性名。
9、db_column
數(shù)據(jù)庫(kù)中的字段名稱
10、unique=True
不允許重復(fù)
11、db_index = True
數(shù)據(jù)庫(kù)索引
12、editable=True
在Admin里是否可編輯
13、error_messages=None
錯(cuò)誤提示
14、auto_created=False
自動(dòng)創(chuàng)建
15、help_text
在Admin中提示幫助信息
16、validators=[]
驗(yàn)證器
17、upload-to
文件上傳時(shí)的保存上傳文件的目錄