day52:django:ORM單表/多表操作

Poke發表於2020-09-17

目錄

1.ORM

2.ORM單表增刪改查

  13個必知必會的查詢介面

  filter基於雙下劃線的模糊查詢

3.ORM多表增刪改查

ORM

什麼是ORM?

ORM(object relational mapping) 物件關係對映,做資料庫操作的

ORM中的物件關係對映

ORM的實際使用

1.首先,我們在django專案的app01/models.py中寫入如下內容

class Book(models.Model):
    # id 這行可寫可不寫,如果不寫的話,系統也會自動新增上去
    id = models.AutoField(primary_key=True) # id int primary key auto_increment,
    title = models.CharField(max_length=32)  # title varchar(32)
    price = models.DecimalField(max_digits=5,decimal_places=2)  #price decimal(5,2)  999.99
    pub_date = models.DateField()  # pub_date date
    publish = models.CharField(max_length=32)

2.執行資料庫同步指令,在專案根目錄下面執行

python manage.py makemigraitons
python manage.py migrate

Tip:檢視FIeld和mysql中的欄位關係對比

C:\ProgramData\Anaconda3\Lib\site-packages\django\db\backends\mysql\base.py

具體內容大致如下

   _data_types = {
        'AutoField': 'integer AUTO_INCREMENT',
        'BigAutoField': 'bigint AUTO_INCREMENT',
        'BinaryField': 'longblob',
        'BooleanField': 'bool',
        'CharField': 'varchar(%(max_length)s)',
        'CommaSeparatedIntegerField': 'varchar(%(max_length)s)',
        'DateField': 'date',
        'DateTimeField': 'datetime',
        'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)',
        'DurationField': 'bigint',
        'FileField': 'varchar(%(max_length)s)',
        'FilePathField': 'varchar(%(max_length)s)',
        'FloatField': 'double precision',
        'IntegerField': 'integer',
        'BigIntegerField': 'bigint',
        'IPAddressField': 'char(15)',
        'GenericIPAddressField': 'char(39)',
        'NullBooleanField': 'bool',
        'OneToOneField': 'integer',
        'PositiveIntegerField': 'integer UNSIGNED',
        'PositiveSmallIntegerField': 'smallint UNSIGNED',
        'SlugField': 'varchar(%(max_length)s)',
        'SmallIntegerField': 'smallint',
        'TextField': 'longtext',
        'TimeField': 'time',
        'UUIDField': 'char(32)',
    }

ORM單表的增刪改查

配置連線資料庫

1. 建立庫:create database db01

2. 修改配置:在setting.py中更改如下內容

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'db01',
        'HOST':'127.0.0.1',
        'PORT':3306,
        'USER':'root',
        'PASSWORD':'123'
    }
}

3.在專案主目錄下面的init檔案中寫上如下內容

import pymysql
pymysql.install_as_MySQLdb()

注意:前提是需要安裝pymysql : pip install pymysql

4.在pycharm中連線mysql,可以使用pycharm自帶的sql視覺化工具

在說增刪改查之前,先介紹幾個簡單的查詢介面

all()  '''獲取表中所有資料,結果為queryset型別'''
ret = models.Book.objects.all()

filter()  '''獲取部分資料,結果為queryset型別'''
ret = models.Book.objects.filter(title='西遊記')

get()  '''獲取單條資料,結果是model物件'''
ret = models.Book.objects.get(title='西遊記')
'''關於get需要注意的點'''
# 1. get() 獲取有且只能有一條
# 2.找不到會報錯:Book matching query does not exist.
# 3.結果超過1條也報錯: get() returned more than one Book -- it returned 3!

單表操作:增

'''方式1'''
    obj = models.Book( # obj就是一個普通的類物件
        title='西遊記',
        price=2.8,
        # pub_date='2000-08-12',  # 可以直接寫固定時間,也可以寫datetime當前時間
        pub_date=datetime.datetime.now(),  #時間日期型別
        publish='人民出版社',
    )
    obj.save() # 注意:必須要寫save選項
'''方式2'''
   obj = models.Book.objects.create(  # obj是當前建立的新的記錄物件
        title='紅樓夢',
        price=9.9,
        # pub_date='2000-08-12',  #這樣的格式字串
        pub_date=datetime.datetime.now(),  # 時間日期型別
        publish='人民出版社',
    )
    
'''批量新增'''
    obj_list = [] # 建立一個空列表,用來存放類物件
    for i in range(1,4): # 建立4個類物件,每個物件都有4個欄位
        obj = models.Book(
            title='水滸傳' + str(i),
            price=i,
            pub_date=f'2000-08-1{i}',
            publish='夕陽紅出版社',
        )
        obj_list.append(obj) # 將類物件新增到列表中
    models.Book.objects.bulk_create(obj_list) # 批量新增

單表操作:刪

'''query型別資料和模型類物件都可以呼叫delete方法來進行刪除'''
models.Book.objects.filter(title='西遊記').delete()
models.Book.objects.get(id=3).delete() 

單表操作:改

'''方式1'''
models.Book.objects.filter(id=4).update(
     title='西遊記',
     price=4,
 )
'''方式2'''
obj = models.Book.objects.get(id=6)
obj.price = 18 # 找到model物件,使用model物件.屬性修改值
obj.save()

obj.update()  # 注意:模型類物件不能直接使用update方法

單表查詢:查

13個必知必會的查詢介面

前面已經提到了3個簡單的查詢介面,加上它們,一共有13個查詢介面

all()  '''獲取表中所有資料,結果為queryset型別'''
ret = models.Book.objects.all()

filter()
'''獲取部分資料,結果為queryset型別''' ret = models.Book.objects.filter(title='西遊記') ret = models.Book.objects.filter(id=1,title='三國演義') # 多條件查詢,條件之間是且的關係(and)

get() '''獲取單條資料,結果是model物件''' ret = models.Book.objects.get(title='西遊記') '''關於get需要注意的點''' # 1. get() 獲取有且只能有一條 # 2.找不到會報錯:Book matching query does not exist. # 3.結果超過1條也報錯: get() returned more than one Book -- it returned 3! exclude(**kwargs): '''排除的意思,它包含了與所給篩選條件不匹配的物件,返回值是queryset型別''' models.Book.objects.exclude(id=6),# 返回id不等於6的所有的物件, models.Book.objects.all().exclude(id=6) # 在queryset基礎上也呼叫exclude

                 order_by(*field): '''queryset型別的資料來呼叫,對查詢結果排序,預設是按照id來升序排列的,返回值還是queryset型別''' models.Book.objects.all().order_by('price','id') '''注意點''' # 1.直接寫price,預設是按照price升序排列, # 2.按照欄位降序排列,就寫個負號就行了:order_by('-price'), # 3.order_by('price','id')是多條件排序,按照price進行升序,price相同的資料,按照id進行升序
reverse()
'''queryset型別的資料來呼叫,對查詢結果反向排序,返回值還是queryset型別,在排序基礎上才能使用''' models.Book.objects.all().order_by('id').reverse() # 注意:要在order_by 基礎上使用
count():
'''queryset型別的資料來呼叫,返回資料庫中匹配查詢(QuerySet)的物件數量''' models.Book.objects.all().count()
first():
'''queryset型別的資料來呼叫,返回第一條記錄''' Book.objects.all()[0] = Book.objects.all().first() # 得到的都是model物件,不是queryset
last():
'''queryset型別的資料來呼叫,返回最後一條記錄''' # 注意:在ORM中不能使用複數索引 ret = models.Book.objects.all()[-1] # 報錯,不支援負數索引:Negative indexing is not supported.

exists(): '''queryset型別的資料來呼叫,如果QuerySet包含資料,就返回True,否則返回False'''
values(
*field): '''用的比較多,queryset型別的資料來呼叫,返回一個QuerySet''' ret = models.Book.objects.values('title','price') # 獲取所有記錄的某些欄位資料,結果為querset型別,裡面的元素是字典型別資料,屬性名稱為鍵,對應記錄的欄位資料為值 '''還可以通過queryset型別資料來呼叫''' ret = models.Book.objects.all().values('title','price')
values_list(
*field): '''它與values()非常相似,它返回的是一個元組序列,values返回的是一個字典序列''' ret = models.Book.objects.all().values_list('title','price') ret = models.Book.objects.values_list('title','price')
distinct():
'''values和values_list得到的queryset型別的資料來呼叫,從返回結果中剔除重複記錄''' ret = models.Book.objects.all().values_list('price').distinct()

filter基於雙下劃線的模糊查詢

# 1.按日期查詢
ret = models.Book.objects.filter(pub_date__year='2000', pub_date__month='8',pub_date__day='12')


# 2.以..開頭/結尾   
ret = models.Book.objects.filter(title__startswith='少婦') # 以..開頭(區分大小寫)
ret = models.Book.objects.filter(title__istartswith='py') # 以..開頭(不區分大小寫)
ret = models.Book.objects.filter(title__endswith='2') # 以..結尾(區分大小寫)


# 3.包含
ret = models.Book.objects.filter(title_icontains='python') # title值中包含python的(區分大小寫)
ret = models.Book.objects.filter(title__icontains='python')  # title值中包含python的(不區分大小寫)


# 4.數字等於.../數字在某個範圍內
ret = models.Book.objects.filter(price__in=[3,4])  # 等於3或者等於4 -- 3 or4
ret = models.Book.objects.filter(price__range=[1,3]) # 在1-3之間 between 1 and 3


# 5.年份寫純數字和字串數字都可以
ret = models.Book.objects.filter(pub_date__year=2018)
ret = models.Book.objects.filter(pub_date__year='2018')    
    
    
# 6.大於/大於等於/小於/小於等於
ret = models.Book.objects.filter(price__gt=3) # 價格大於3的
ret = models.Book.objects.filter(price__gte=3) # 價格大於等於3的
ret = models.Book.objects.filter(price__lt=3) # 價格小於3的
ret = models.Book.objects.filter(price__lte=3) # 價格小於等於3的

ORM多表關係的增刪改查

ORM多表關係的建立

from django.db import models


# 作者表
class Author(models.Model): # 比較常用的資訊放到這個表裡面
    name=models.CharField( max_length=32)
    age=models.IntegerField()  #int
    # 與AuthorDetail建立一對一的關係,一對一的這個關係欄位寫在兩個表的任意一個表裡面都可以
    ad = models.OneToOneField(to="AuthorDetail", to_field='id', on_delete=models.CASCADE)

# 作者詳細資訊表
class AuthorDetail(models.Model): # 不常用的放到這個表裡面
    birthday=models.DateField()
    telephone=models.CharField(max_length=11)
    addr=models.CharField(max_length=64)


# 出版社表
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)
    # publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE)
    publish=models.ForeignKey(to="Publish") #預設級聯刪除,預設關聯的是另外一張表的id欄位
    authors=models.ManyToManyField(to='Author',) #自動建立第三張表,id author_id book_id,不會作為本表的欄位出現

建立欄位的一些引數講解

# 1.null  
'''如果為True,Django 將用NULL 來在資料庫中儲存空值。 預設值是 False.'''
 
    
# 2.blank
'''
如果為True,該欄位允許不填。預設為False。
要注意,這與 null 不同。null純粹是資料庫範疇的,而 blank 是資料驗證範疇的。
如果一個欄位的blank=True,表單的驗證將允許該欄位是空值。如果欄位的blank=False,該欄位就是必填的。
'''


# 3.default
'''
欄位的預設值。可以是一個值或者可呼叫物件。如果可呼叫 ,每有新物件被建立它都會被呼叫,如果你的欄位沒有設定可以為空,那麼將來如果我們後新增一個欄位,這個欄位就要給一個default值
'''


# 4.primary_key
'''
如果為True,那麼這個欄位就是模型的主鍵。如果你沒有指定任何一個欄位的primary_key=True,
Django 就會自動新增一個IntegerField欄位做為主鍵,所以除非你想覆蓋預設的主鍵行為,
否則沒必要設定任何一個欄位的primary_key=True。
'''

# 5.unique
'''如果該值設定為 True, 這個資料欄位的值在整張表中必須是唯一的'''


# 6.choices
'''由二元組組成的一個可迭代物件(例如,列表或元組),用來給欄位提供選擇項。 如果設定了choices ,預設的表單將是一個選擇框而不是標準的文字框,<br>而且這個選擇框的選項就是choices 中的選項。'''


# 7.db_index
'''如果db_index=True 則代表著為此欄位設定資料庫索引'''


# DatetimeField、DateField、TimeField這個三個時間欄位,都可以設定如下屬性。

# 8.auto_now_add
'''配置auto_now_add=True,建立資料記錄的時候會把當前時間新增到資料庫'''


# 9.auto_now
'''配置上auto_now=True,每次更新資料記錄的時候會更新該欄位,標識這條記錄最後一次的修改時間'''

Tip:關於choices屬性額外的補充

sex = models.IntegerField(choices=((1, '男性'), (2, '女性')))
'''注意點'''
# 1.資料庫裡面存的是1或者2
# 2.通過model模型類物件.get_屬性名稱_display()可以獲取到數字對應的文字內容

Tip:關於auto_now_add和auto_now屬性額外的補充

class t1(models.Model):
    d1 = models.DateTimeField(auto_now_add=True,null=True)  #自動新增建立記錄的時間
    d2 = models.DateTimeField(auto_now=True,null=True) #自動新增建立記錄的時間,更新記錄是也能自動更新為最新時間
'''注意點'''
# 1.auto_now 自動更新時間只有在save更新時才生效,update不生效
# 2.所以如果要做更新時間的處理,那麼最好手動獲取當前時間並修改
    

多表操作:增

# 一對一
    # 1.用create增
    models.AuthorDetail.objects.create(
        birthday='2018-01-01',
        telephone='13800000000',
        addr='北京'
    )
    ad_obj = models.AuthorDetail.objects.get(id=1) # 建立一對一的關聯model物件
    models.Author.objects.create(
        name='張三',
        age=38,
        # ad=ad_obj, # 方法一:寫關聯物件
        ad_id=2, # 方法二:直接寫關聯id值
    )
    # 2.用類物件去增
    ad_obj = models.AuthorDetail.objects.get(id=4)
    obj= models.Author(
        name='楊浩',
        age=47,
        ad=ad_obj, # 方法一
        # ad_id=3, #  方法二
    )
    obj.save()

# 一對多
'''出版社和書是一對多的關係;一個出版社可以出版多本書'''
# 一對多,在多的一方寫關聯語句
    models.Book.objects.create(
        title='西遊記',
        publishDate='2018-08-08',
        price=22,
        # publishs=models.Publish.objects.get(id=1), # 方法一
        publishs_id=1, # 方法二
    )

 # 多對多
'''書和作者是多對多的關係;一本書可以有多個作者,一個作者也可以寫很多本書'''
    obj = models.Book.objects.filter(id=1).first()
    # 方法一:通過get(id=?)獲取物件
    a1 = models.Author.objects.get(id=1)
    a2 = models.Author.objects.get(id=2)
    obj.authors.add(a1,a2)
    # 方法二:add中直接寫id
    obj.authors.add(1,2)
    # 方法三:id寫入列表中,用*號打散
    obj.authors.add(*[1,2])

多表操作:刪

# 一對一和一對多刪除
    '''一對一和一對多 ,基本和單表一樣(級聯刪除)'''
    models.Author.objects.get(id=1).delete()
    
    models.AuthorDetail.objects.get(id=2).delete()
    models.Book.objects.get(id=1).delete()

# 多對多刪除
    ret = models.Book.objects.get(id=2)
    ret.authors.clear()  # 清空該書籍對應的第三張表中的記錄(全部刪除)
    ret.authors.remove(3,4)  #指定刪除該書和哪些作者的關係 (指定刪除)

 

相關文章