Django 之 ORM基本操作

Django 模型(數據庫)

Django 模型是與數據庫相關的,與數據庫相關的代碼一般寫在 models.py 中,Django 支持 sqlite3,PostgreSQL、MySQL、SQLite、Oracle。等數據庫,使用對應的數據庫只需要在settings.py中配置即可,不用更改models.py中的代碼,豐富的API極大的方便了使用。

MySQL 是 Web 應用中最常用的數據庫,,接下來對MySQL的使用進行介紹,如果沒有安裝mysql 驅動,可以執行以下命令安裝:

pip install mysqlclient

數據庫配置

對MySQL的配置只需要在項目文件夾下的 settings.py 文件中找到 DATABASES 配置項,將其信息修改爲:

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

上面的變量必須使用大寫,它們與 MySQL 中對應數據庫和用戶的設置相同。Django 根據這裏的設置,與 MySQL 中相應的數據庫和用戶連接起來。

在Django中是默認使用mysqldb模塊連接數據庫的,這時候要用pymysql模塊來替換mysqldb連接數庫,有兩種方式:
方式一:在項目名文件夾下面的__ init __ .py
方式二:在app應用文件夾下面的__ init __ .py

固定寫法:


import pymysql
pymysql.install_as_MySQLdb()  # 告訴django用pymysql代替mysqldb連接數據庫

創建模型

要想使用模型必須要創建app應用,創建好app後就可以在app文件夾下的models.py定義模型。

from django.db import models
class User(models.Model):
    # user表的主鍵字段名就是id,id字段可以不寫默認會幫你創建一個主鍵id字段
    id = models.AutoField(primary_key=True)
    # varchar(32) name字段是varchar(32)   CharField在定義的時候必須要加max_length參數
    name = models.CharField(max_length=32)
    password = models.CharField(max_length=16)

    def __str__(self):
        return self.name

以上的類名代表了數據庫中的一張表,且繼承了models.Model,類裏面的屬性代表數據表中的字段(name),數據類型則有CharField(相當於varchar)、DateField(相當於datetime), max_length 參數限定長度。

常用字段類型

以下列表描述了一些更常用的字段類型。

  • CharField: 是用來定義短到中等長度的字段字符串。你必須指定max_length要存儲的數據。
  • TextField:用於大型任意長度的字符串。你可以max_length爲該字段指定一個字段,但僅當該字段以表單顯示時纔會使用(不會在數據庫級別強制執行)。
  • IntegerField:是一個用於存儲整數(整數)值的字段,用於在表單中驗證輸入的值爲整數。
  • DateField 和 DateTimeField:用於存儲/表示日期和日期/時間信息(分別是Python.datetime.date和datetime.datetime對象。這些字段可以另外表明(互斥)參數auto_now=Ture (在每次保存模型時將該字段設置爲當前日期),auto_now_add(僅設置模型首次創建時的日期)和default(設置默認日期,可以被用戶覆蓋)。
  • EmailField:用於存儲和驗證電子郵件地址。
  • FileFieldImageField:分別用於上傳文件和圖像(ImageField 只需添加上傳的文件是圖像的附加驗證)。這些參數用於定義上傳文件的存儲方式和位置。
  • AutoField:是一種 IntegerField 自動遞增的特殊類型。如果你沒有明確指定一個主鍵,則此類型的主鍵將自動添加到模型中。
  • ForeignKey:用於指定與另一個數據庫模型的一對多關係(例如,汽車有一個製造商,但製造商可以製作許多汽車)。字段的參數有 to:設置要關聯的表,to_field:設置要關聯的表的字段,on_delete:當刪除關聯表中的數據時,當前表與其關聯的行的行爲。
  • ManyToManyField: 用於指定 多對多關係(例如,一本書可以有幾種類型,每種類型可以包含幾本書)。
  • ForeignKeys:可以用更復雜的方式來描述組之間的關係。具有參數on_delete來定義關聯記錄被刪除時會發生什麼(例如,值models.SET_NULL將簡單地設置爲值NULL)。

常見字段參數

字段參數
null:用於表示某個字段可以爲空。

unique:如果設置爲unique=True 則該字段在此表中必須是唯一的 。

db_index:如果db_index=True 則代表着爲此字段設置索引。

default:爲該字段設置默認值。

除了我們前面說過的普通類型字段,Django還定義了一組關係類型字段,用來表示模型與模型之間的關係。

ForeignKey

多對一的關係,通常被稱爲外鍵。外鍵字段類的定義如下:

class ForeignKey(to, on_delete, **options)[source]

外鍵需要兩個位置參數,一個是 to 關聯的模型,另一個是 on_delete 選項。實際上,在目前版本中,on_delete 選項也可以不設置,在Django2.0版本後,該選項會設置爲必填。

在數據庫後臺,Django會爲每一個外鍵添加 _id 後綴,並以此創建數據表裏的一列。

參數說明

外鍵還有一些重要的參數,說明如下:

on_delete

當一個被外鍵關聯的對象被刪除時,Django將模仿 on_delete 參數定義的SQL約束執行相應操作。該參數可選的值都內置在 django.db.models 中,包括:

  • CASCADE:模擬SQL語言中的 ON DELETE CASCADE 約束,將定義有外鍵的模型對象同時刪除!
  • PROTECT:阻止上面的刪除操作,但是彈出 ProtectedError 異常
  • SET_NULL:將外鍵字段設爲null,只有當字段設置了 null=True 時,方可使用該值。
  • SET_DEFAULT:將外鍵字段設爲默認值。只有當字段設置了default參數時,方可使用。
  • DO_NOTHING:什麼也不做。
  • SET():設置爲一個傳遞給SET()的值或者一個回調函數的返回值。注意大小寫。

limit_choices_to

該參數用於限制外鍵所能關聯的對象,只能用於Django的ModelForm(Django的表單模塊)和admin後臺,對其它場合無限制功能。其值可以是一個字典、Q對象或者一個返回字典或Q對象的函數調用,如下例所示:

staff_member = models.ForeignKey(
    User,
    on_delete=models.CASCADE,
    limit_choices_to={'is_staff': True},
)

這樣定義,則ModelForm的 staff_member 字段列表中,只會出現那些 is_staff=True 的Users對象,這一功能對於admin後臺非常有用。

related_name

用於關聯對象反向引用模型的名稱。通常情況下,這個參數可以不設置,Django會默認以模型的小寫加上 _set 作爲反向關聯名,

如果你不想爲外鍵設置一個反向關聯名稱,可以將這個參數設置爲“+”或者以“+”結尾,如下所示:

user = models.ForeignKey(
    User,
    on_delete=models.CASCADE,
    related_name='+',
)

related_query_name

反向關聯查詢名。用於從目標模型反向過濾模型對象的名稱。

to_field

默認情況下,外鍵都是關聯到被關聯對象的主鍵上(一般爲id)。如果指定這個參數,可以關聯到指定的字段上,但是該字段必須具有 unique=True 屬性,也就是具有唯一屬性。

db_constraint

默認情況下,這個參數被設爲True,表示遵循數據庫約束,這也是大多數情況下你的選擇。如果設爲False,那麼將無法保證數據的完整性和合法性。在下面的場景中,你可能需要將它設置爲False:

  • 有歷史遺留的不合法數據,沒辦法的選擇
  • 你正在分割數據表

當它爲False,並且你試圖訪問一個不存在的關係對象時,會拋出DoesNotExist 異常。

swappable

控制遷移框架的動作,如果當前外鍵指向一個可交換的模型。使用場景非常稀少,通常請將該參數保持默認的True。

ManyToManyField

多對多關係在數據庫中也是非常常見的關係類型。比如一本書可以有好幾個作者,一個作者也可以寫好幾本書。多對多的字段可以定義在任何的一方,請儘量定義在符合人們思維習慣的一方,但不要同時都定義。

class ManyToManyField(to, **options)[source]

參數說明

除了上面的外鍵的參數外還有一下參數。

through(定義中間表)

如果你自定義多對多關係的那張額外的關聯表,可以使用這個參數!參數的值爲一箇中間模型。

through_fields

through_fields 參數接收一個二元元組(‘field1’, ‘field2’),field1是指向定義有多對多關係的模型的外鍵字段的名稱,另外一個則是指向目標模型的外鍵字段的名稱,通俗的說,就是 through_fields 參數指定從中間表模型Membership中選擇哪兩個字段,作爲關係連接字段。

db_table

設置中間表的名稱。不指定的話,則使用默認值。

OneToOneField

一對一關係類型的定義如下:

class OneToOneField(to, on_delete, parent_link=False, **options)[source]

從概念上講,一對一關係非常類似具有 unique=True 屬性的外鍵關係,但是反向關聯對象只有一個。該關係的第一位置參數爲關聯的模型,其用法和前面的多對一外鍵一樣。如果你沒有給一對一關係設置 related_name 參數,Django將使用當前模型的小寫名作爲默認值。

OneToOneField 一對一關係擁有和多對一外鍵關係一樣的額外可選參數,只是多了一個parent_link參數。

自定義字段

class MyCharField(models.Field):
    def __init__(self,max_length,*args,**kwargs):
        self.max_length = max_length
        super().__init__(max_length=max_length,*args,**kwargs)
    def db_type(self, connection):
        return 'char(%s)'%self.max_length

字段的枚舉

class User(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    info = MyCharField(max_length=32,null=True)  # 使用自定義字段
    choices = ((1,'男'),(2,'女'),(3,'其他'))
    gender = models.IntegerField(choices=choices,default=2)

枚舉字段的操作:

創建:
models.User.objects.create(...gender=1)
查詢:
res = models.User.objects.filter(id=1).first()
print(res.gender)
print(res.get_gender_display())  # 獲取編號對應的中文註釋

創建數據表

接下來建創建的模型同步到數據庫中形成表結構。先 cd進入 manage.py 所在的那個文件夾下,輸入下面的命令:

python manage.py makemigrations  # 讓 Django 知道我們在我們的模型有一些變更
python manage.py migrate  # 創建表結構,將你的數據模型變動正在同步到數據庫中

在操作上面的命令前要確保app應用已經在settings中註冊。

數據庫操作

添加數據

在app應用文件夾下的views.py中添加增加數據的函數來操作數據庫。添加數據有以下幾種方式:

方式一:通過create函數進行直接進行添加
user_obj = models.User.objects.create(name='linwow',password='123')
方式二:通過對象調用save()來添加
user_obj = models.User(name='linwow',password='123')
user_obj.save()  # 對象調用save方法保存到數據庫
方式三:
user_obj = models.User()
user_obj.name = 'linwow'
user_obj.password = '123'
user_obj.save()
方式四:首先嚐試獲取,不存在就創建,可以防止重複
models.User.objects.get_or_create(name='linwow', password='123')
# 返回的是一個元組,(object, True/False),創建時返回 True, 已經存在時返回 False
  • 當有一對多,多對一,或者多對多的關係的時候,先把相關的對象查詢出來
user_obj = models.User.objects.get(pk=1)
class_obj = models.Class.objects.get(name="python")
user_obj.cla_id = class_obj
user_obj.save()

拓展:批量插入數據

l = []
for i in range(10000):
    l.append(models.Book2(name='第%s本書'%i))
models.Book2.objects.bulk_create(l)  # 批量插入數據

獲取數據

Django提供了多種方式來獲取數據庫的內容,從數據庫中查詢出來的結果一般是一個集合,這個集合叫做 QuerySet。查詢數據需要注意的是你獲取到的到底是一個queryset還是一個數據對象

  • all():通過objects這個模型管理器的all()獲得所有數據行,相當於SQL中的SELECT * FROM user
user_list = models.User.objects.all()  # 獲取user表所有的數據
這樣獲取到的是QuerySet對象,只要是QuerySet就可以點query查看獲取到當前QuerySet對象的內部sql語句
print(user_list.query) 
  • filter():filter相當於SQL中的WHERE,可設置條件過濾結果,filter當條件不存在的情況下會返回一個空的queryset對象
user_list = models.User.objects.filter(id=1) # 獲取user表中id爲1的數據
queryset對象支持索引取值 但是不推薦你使用  推薦使用自帶的.first()獲取第一條數據
user_query = models.User.objects.filter(name=linwow).first()
  • get() :獲取單個對象,用get可以直接獲取到數據對象本身但是查詢條件不存在的情況下直接報錯
user_list = models.User.objects.get(id=1) # 如果數據不存在會報錯,一般不推薦使用

獲取數據方法總結:

獲取所有數據:
models.User.objects.all()
切片操作,獲取10個人,不支持負索引,切片可以節約內存:
models.User.objects.all()[:10] 
獲取對應條件的值,get是用來獲取一個對象的:
models.User.objects.get(name=name)
獲取滿足條件的一些人,就要用到filter:
models.User.objects.filter(name="abc")  # 等於models.User.objects.filter(name__exact="abc") 名稱嚴格等於 "abc" 的人
名稱爲 abc 但是不區分大小寫,可以找到 ABC, Abc, aBC,這些都符合條件
models.User.objects.filter(name__iexact="abc")
名稱中包含 "abc"的人:
models.User.objects.filter(name__contains="abc")
名稱中包含 "abc",且abc不區分大小寫:
models.User.objects.filter(name__icontains="abc")

正則表達式查詢:
models.User.objects.filter(name__regex="^abc")
正則表達式不區分大小寫:
models.User.objects.filter(name__iregex="^abc")

排除包含wow的User對象:
models.User.objects.exclude(name__contains="wow")
找出名稱含有abc, 但是排除年齡是23歲的
models.User.objects.filter(name__contains="abc").exclude(age=23)

1、如果只是檢查User中是否有對象,應該用 user_list = models.User.objects.all().exists()
2、用 len(user_list) 可以得到User的數量,但是推薦用 models.User.objects.count()來查詢數量。
3list(user_list) 可以強行將 QuerySet 變成列表。
4、 去重方法user_list = user_list.distinct()

defer 排除不需要的字段

在複雜的情況下,表中可能有些字段內容非常多,取出來轉化成 Python 對象會佔用大量的資源,這時候可以用 defer 來排除這些字段。

models.User.objects.all().defer('addr')

only 僅選擇需要的字段

和 defer 相反,only 用於取出需要的字段,假如只需要查出用戶名。

models.User.objects.all().only('addr')

更新數據

修改數據可以使用 save() 或 update(),save()的使用方法和新增數據是一樣的,下面介紹update的使用方法。

  • 批量更新,適用於 .all() .filter() .exclude() 等後面 。
  • 單個 object 更新,適合於 .get(), get_or_create(), update_or_create() 等得到的 obj。
基於queryset
models.User.objects.filter(id=1).update(name='lin',password='321')

刪除數據

刪除數據庫中的對象只需調用該對象的delete()方法即可

  • 刪除id=1的數據
基於對象
user_obj = models.User.objects.get(id=1)
test1.delete()
基於queryset
models.User.objects.filter(id=1).delete()
  • 刪除所有數據
models.User.objects.all().delete()

數據排序

在 Django 應用中,如果希望根據某字段的值對檢索結果排序,比如說,按字母順序。 那麼,使用order_by() 這個方法就可以了。

  • 可以對任意字段進行排序:
models.User.objects.all().order_by('name')
  • 如果需要以多個字段爲標準進行排序(第二個字段會在第一個字段的值相同的情況下被使用到),使用多個參數就可以:
models.User.objects.all().order_by('name','id')
  • 可以指定逆向排序,在前面加一個減號 - 前綴:
models.User.objects.all().order_by('-name')
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章