1. 程式人生 > >Django基礎之數據庫與ORM

Django基礎之數據庫與ORM

page 寫入 src postgres def 由於 ont 方法 cut

一.數據庫配置

1.django默認支持sqlite,mysql, oracle,postgresql數據庫。

  • django默認使用sqlite的數據庫,默認自帶sqlite的數據庫驅動 , 引擎名稱:django.db.backends.sqlite3
  • 引擎名稱:django.db.backends.mysql

2.在django的項目中會默認使用sqlite數據庫,在settings裏有如下設置:

DATABASES = {
    ‘default‘: {
        ‘ENGINE‘: ‘django.db.backends.sqlite3‘,
        ‘NAME‘: os.path.join(BASE_DIR, ‘db.sqlite3‘),
    }
}

如果我們想要更改為MySQL數據庫,需要修改如下:

DATABASES = {
    ‘default‘: {
        ‘ENGINE‘: ‘django.db.backends.mysql‘, 
        ‘NAME‘: ‘books‘,    #你的數據庫名稱
        ‘USER‘: ‘root‘,   #你的數據庫用戶名
        ‘PASSWORD‘: ‘‘, #你的數據庫密碼
        ‘HOST‘: ‘‘, #你的數據庫主機,留空默認為localhost
        ‘PORT‘: ‘3306‘, #你的數據庫端口
    }
}

註意:

  NAME即數據庫的名字,在mysql連接前該數據庫必須已經創建,而上面的sqlite數據庫下的db.sqlite3則是項目自動創建
  USER和PASSWORD分別是數據庫的用戶名和密碼。
  設置完後,再啟動我們的Django項目前,我們需要激活我們的mysql。
  然後,啟動項目,會報錯:no module named MySQLdb
  這是因為django默認你導入的驅動是MySQLdb,可是MySQLdb對於py3有很大問題,所以我們需要的驅動是PyMySQL
  所以,我們只需要找到項目名文件下的__init__,在裏面寫入:
    import pymysql
    pymysql.install_as_MySQLdb()

二.ORM表模型

  作者模型:一個作者有姓名。

  作者詳細模型:把作者的詳情放到詳情表,包含姓名,email地址,作者詳情模型和作者模型之間是一對一的關系(one-to-one)(類似於每個人和他的身份證之間的關系),在大多數情況下我們沒有必要將他們拆分成兩張表,這裏只是引出一對一的概念。

  出版商模型:出版商有名稱,地址。

  書籍模型:書籍有書名和出版日期,一本書可能會有多個作者,一個作者也可以寫多本書,所以作者和書籍的關系就是多對多的關聯關系(many-to-many),一本書只應該由一個出版商出版,所以出版商和書籍是一對多關聯關系(one-to-many),也被稱作外鍵。

  代碼如下:

  

from django.db import models

# 作者表
class Author(models.Model):
    name = models.CharField(max_length=30)
    email = models.EmailField()
    def __str__(self):
        return self.name

# 出版社
class Publisher(models.Model):
    press = models.CharField(max_length=30)
    press_address = models.CharField(max_length=30)

# book
class Book(models.Model):
    title = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=5, decimal_places=2, default=10)
    publication_date = models.DateField()
    author = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)  # 數據庫存的是publish_id
    def __str__(self):
        return self.title

分析代碼:

  <1> 每個數據模型都是django.db.models.Model的子類,它的父類Model包含了所有必要的和數據庫交互的方法。並提供了一個簡介漂亮的定義數據庫字段的語法。

<2> 每個模型相當於單個數據庫表(多對多關系例外,會多生成一張關系表),每個屬性也是這個表中的字段。屬性名就是字段名,它的類型(例如CharField)相當於數據庫的字段類型(例如varchar)。大家可以留意下其它的類型都和數據庫裏的什麽字段對應。

<3> 模型之間的三種關系:一對一,一對多,多對多。

一對一:實質就是在主外鍵(author_id就是foreign key)的關系基礎上,給外鍵加了一個UNIQUE=True的屬性;

一對多:就是主外鍵關系;(foreign key)

多對多:(ManyToManyField) 自動創建第三張表(當然我們也可以自己創建第三張表:兩個foreign key)

2.1ORM之增加

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()

重點來了------->那麽如何創建存在一對多或多對多關系的一本書的信息呢?(如何處理外鍵關系的字段如一對多的publisher和多對多的authors)

#一對多(ForeignKey):

    #方式一: 由於綁定一對多的字段,比如publish,存到數據庫中的字段名叫publish_id,所以我們可以直接給這個
    #       字段設定對應值:
           Book.objects.create(title=‘php‘,
                               publisher_id=2,   #這裏的2是指為該book對象綁定了Publisher表中id=2的行對象
                               publication_date=‘2017-7-7‘,
                               price=99)


    #方式二:
    #       <1> 先獲取要綁定的Publisher對象:
        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

#多對多(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)

#註意: 如果第三張表是通過models.ManyToManyField()自動創建的,那麽綁定關系只有上面一種方式
#     如果第三張表是自己創建的:
     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.2ORM之刪除(delete)

 Book.objects.filter(id=1).delete()

我們表面上刪除了一條信息,實際卻刪除了三條,因為我們刪除的這本書在Book_authors表中有兩條相關信息,這種刪除方式就是django默認的級聯刪除。

2.3ORM之改(update和save)

實例:

技術分享

註意:

<1> 第二種方式修改不能用get的原因是:update是QuerySet對象的方法,get返回的是一個model對象,它沒有update方法,而filter返回的是一個QuerySet對象(filter裏面的條件可能有多個條件符合,比如name=‘alvin‘,可能有兩個name=‘alvin‘的行數據)。

<2>在“插入和更新數據”小節中,我們有提到模型的save()方法,這個方法會更新一行裏的所有列。 而某些情況下,我們只需要更新行裏的某幾列。

#---------------- update方法直接設定對應屬性----------------
    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方法會將所有屬性重新設定一遍,效率低-----------
    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()方法對於任何結果集(QuerySet)均有效,這意味著你可以同時更新多條記錄update()方法會返回一個整型數值,表示受影響的記錄條數。

註意,這裏因為update返回的是一個整形,所以沒法用query屬性;對於每次創建一個對象,想顯示對應的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‘,
        },
    }
}

Django基礎之數據庫與ORM