2018-12-24

數(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í)的保存上傳文件的目錄

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容