一、ORM介紹
1、ORM概念
對象關系映射(Object Relational Mapping,簡稱ORM)模式是一種為了解決面向對象與關系資料庫存在的互不比對的現象的技術。
簡單的說,ORM是通過使用描述對象和資料庫之間映射的中繼資料,将程式中的對象自動持久化到關系資料庫中。
ORM在業務邏輯層和資料庫層之間充當了橋梁的作用。
2、ORM由來
讓我們從O/R開始。字母O起源于"對象"(Object),而R則來自于"關系"(Relational)。
幾乎所有的軟體開發過程中都會涉及到對象和關系資料庫。在使用者層面和業務邏輯層面,我們是面向對象的。當對象的資訊發生變化的時候,我們就需要把對象的資訊儲存在關系資料庫中。
按照之前的方式來進行開發就會出現程式員會在自己的業務邏輯代碼中夾雜很多SQL語句用來增加、讀取、修改、删除相關資料,而這些代碼通常都是重複的。
3、ORM的優勢
ORM解決的主要問題是對象和關系的映射。它通常把一個類和一個表一一對應,類的每個執行個體對應表中的一條記錄,類的每個屬性對應表中的每個字段。
ORM提供了對資料庫的映射,不用直接編寫SQL代碼,隻需像操作對象一樣從資料庫操作資料。
讓軟體開發人員專注于業務邏輯的處理,提高了開發效率。
4、ORM的劣勢
ORM的缺點是會在一定程度上犧牲程式的執行效率。
ORM用多了SQL語句就不會寫了,關系資料庫相關技能退化...
5、ORM總結
ORM隻是一種工具,工具确實能解決一些重複,簡單的勞動。這是不可否認的。
但我們不能指望某個工具能一勞永逸地解決所有問題,一些特殊問題還是需要特殊處理的。
但是在整個軟體開發過程中需要特殊處理的情況應該都是很少的,否則所謂的工具也就失去了它存在的意義。
二、Django中的ORM
1、Django項目使用MySQL資料庫
1. 手動建立一個資料庫
2. 在Django項目的settings.py檔案中,配置資料庫連接配接資訊:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "你的資料庫名稱", # 需要自己手動建立資料庫
"USER": "資料庫使用者名",
"PASSWORD": "資料庫密碼",
"HOST": "資料庫IP",
"POST": 3306
}
}
3. 告訴Django用什麼子產品連接配接MySQL,在和settings.py同級的__init__.py中:
import pymysql
pymysql.install_as_MySQLdb()
4. 在app下面的models.py中建立類,類一定要繼承models.Model
5.執行兩個指令
1. python manage.py makemigrations --> 判斷models.py中是否有改動,把改動記錄到migrations目錄下
2. python manage.py migrate --> 把改動翻譯成SQL語句去資料庫執行
注意:當項目中不止有一個APP時,python manage.py makemigrations appname 可以單獨判斷某個app裡面的models.py的變更
2、Model
在Django中model是你資料的單一、明确的資訊來源。它包含了你存儲的資料的重要字段和行為。通常,一個模型(model)映射到一個資料庫表
基本情況:
每個模型都是一個Python類,它是django.db.models.Model的子類。
模型的每個屬性都代表一個資料庫字段。
綜上所述,Django為您提供了一個自動生成的資料庫通路API。、
3、說明
ORM定義表
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=20)
publisher = models.CharField(max_length=30)
title 和 publisher 是模型的字段。每個字段被指定為一個類屬性,每個屬性映射到一個資料庫列。
上面的模型等于下面的SQL建表語句
CREATE TABLE myapp_book (
"id" serial NOT NULL PRIMARY KEY,
"title" varchar(20) NOT NULL,
"publisher" varchar(30) NOT NULL
);
表myapp_book的名稱是自動生成的,如果你要自定義表名,需要在model的Meta類中指定 db_table 參數,強烈建議使用小寫表名,特别是使用MySQL作為後端資料庫時。
id字段是自動添加的,如果你想要指定自定義主鍵,隻需在其中一個字段中指定 primary_key=True 即可。如果Django發現你已經明确地設定了Field.primary_key,它将不會添加自動ID列。
Django會根據配置檔案中指定的資料庫後端類型來生成相應的SQL語句。
Django支援MySQL5.5及更高版本。
4、字段
總覽
AutoField(Field)
- int自增列,必須填入參數 primary_key=True
BigAutoField(AutoField)
- bigint自增列,必須填入參數 primary_key=True
注:當model中如果沒有自增列,則自動會建立一個列名為id的列
from django.db import models
class UserInfo(models.Model):
# 自動建立一個列名為id的且為自增的整數列
username = models.CharField(max_length=32)
class Group(models.Model):
# 自定義自增列
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
- 小整數 -32768 ~ 32767
PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正小整數 0 ~ 32767
IntegerField(Field)
- 整數列(有符号的) -2147483648 ~ 2147483647
PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
- 正整數 0 ~ 2147483647
BigIntegerField(IntegerField):
- 長整型(有符号的) -9223372036854775808 ~ 9223372036854775807
BooleanField(Field)
- 布爾值類型
NullBooleanField(Field):
- 可以為空的布爾值
CharField(Field)
- 字元類型
- 必須提供max_length參數, max_length表示字元長度
TextField(Field)
- 文本類型
EmailField(CharField):
- 字元串類型,Django Admin以及ModelForm中提供驗證機制
IPAddressField(Field)
- 字元串類型,Django Admin以及ModelForm中提供驗證 IPV4 機制
GenericIPAddressField(Field)
- 字元串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6
- 參數:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定為True,則輸入::ffff:192.0.2.1時候,可解析為192.0.2.1,開啟此功能,需要protocol="both"
URLField(CharField)
- 字元串類型,Django Admin以及ModelForm中提供驗證 URL
SlugField(CharField)
- 字元串類型,Django Admin以及ModelForm中提供驗證支援 字母、數字、下劃線、連接配接符(減号)
CommaSeparatedIntegerField(CharField)
- 字元串類型,格式必須為逗号分割的數字
UUIDField(Field)
- 字元串類型,Django Admin以及ModelForm中提供對UUID格式的驗證
FilePathField(Field)
- 字元串,Django Admin以及ModelForm中提供讀取檔案夾下檔案的功能
- 參數:
path, 檔案夾路徑
match=None, 正則比對
recursive=False, 遞歸下面的檔案夾
allow_files=True, 允許檔案
allow_folders=False, 允許檔案夾
FileField(Field)
- 字元串,路徑儲存在資料庫,檔案上傳到指定目錄
- 參數:
upload_to = "" 上傳檔案的儲存路徑
storage = None 存儲元件,預設django.core.files.storage.FileSystemStorage
ImageField(FileField)
- 字元串,路徑儲存在資料庫,檔案上傳到指定目錄
- 參數:
upload_to = "" 上傳檔案的儲存路徑
storage = None 存儲元件,預設django.core.files.storage.FileSystemStorage
width_field=None, 上傳圖檔的高度儲存的資料庫字段名(字元串)
height_field=None 上傳圖檔的寬度儲存的資料庫字段名(字元串)
DateTimeField(DateField)
- 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
DateField(DateTimeCheckMixin, Field)
- 日期格式 YYYY-MM-DD
TimeField(DateTimeCheckMixin, Field)
- 時間格式 HH:MM[:ss[.uuuuuu]]
DurationField(Field)
- 長整數,時間間隔,資料庫中按照bigint存儲,ORM中擷取的值為datetime.timedelta類型
FloatField(Field)
- 浮點型
DecimalField(Field)
- 10進制小數
- 參數:
max_digits,小數總長度
decimal_places,小數位長度
BinaryField(Field)
- 二進制類型
字段總覽
常用字段
1. AutoField() *****
- int自增列,必須填入參數 primary_key=True
- 當model中如果沒有自增列,則自動會建立一個列名為id的列(即自增的id主鍵)
2. IntegerField *****
- 整數列(有符号的) -2147483648 ~ 2147483647
3. BooleanField
- 布爾值類型
4. CharField *****
- 字元類型varchar
- 必須提供max_length參數, max_length表示字元長度
5. TextField
- 文本類型
6. EmailField
- 字元串類型,Django Admin以及ModelForm中提供驗證機制
7. GenericIPAddressField
- 字元串類型,Django Admin以及ModelForm中提供驗證 Ipv4和Ipv6
- 參數:
protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"
unpack_ipv4, 如果指定為True,則輸入::ffff:192.0.2.1時候,可解析為192.0.2.1,開啟此功能,需要protocol="both"
8. UUIDField *****
- 字元串類型,Django Admin以及ModelForm中提供對UUID格式的驗證
9. FileField
- 字元串,路徑儲存在資料庫,檔案上傳到指定目錄
- 參數:
upload_to = "" 上傳檔案的儲存路徑
storage = None 存儲元件,預設django.core.files.storage.FileSystemStorage
10. ImageField
- 字元串,路徑儲存在資料庫,檔案上傳到指定目錄
- 參數:
upload_to = "" 上傳檔案的儲存路徑
storage = None 存儲元件,預設django.core.files.storage.FileSystemStorage
width_field=None, 上傳圖檔的高度儲存的資料庫字段名(字元串)
height_field=None 上傳圖檔的寬度儲存的資料庫字段名(字元串)
11. DateTimeField *****
- 日期+時間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]
12. DateField *****
- 日期格式 YYYY-MM-DD
13. TimeField
- 時間格式 HH:MM[:ss[.uuuuuu]]
14. FloatField
- 浮點型
15. DecimalField *****
- 10進制小數
- 參數:
max_digits,小數總長度
decimal_places,小數位長度
5、自定義字段
1.自定義char類型字段:
from django.db import models
class MycharField(models.Field):
"""
自定義的char類型的字段類
"""
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(MycharField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
"""
限定生成資料庫表的字段類型為char,長度為length指定的值
"""
return 'char(%s)' % self.max_length
class UserInfo(models.Model):
name = MycharField(max_length=12)
2.自定義無符号整數字段:
class UnsignedIntegerField(models.IntegerField):
def db_type(self, connection):
return 'integer UNSIGNED'
3.傳回值為字段在資料庫中的屬性,Django字段預設的值為:
'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)',
字段的屬性
6、字段參數
null 資料庫中字段是否可以為空
db_column 資料庫中字段的列名
default 資料庫中字段的預設值
primary_key 資料庫中字段是否為主鍵
db_index 資料庫中字段是否可以建立索引
unique 資料庫中字段是否可以建立唯一索引
unique_for_date 資料庫中字段【日期】部分是否可以建立唯一索引
unique_for_month 資料庫中字段【月】部分是否可以建立唯一索引
unique_for_year 資料庫中字段【年】部分是否可以建立唯一索引
verbose_name Admin中顯示的字段名稱
blank Admin中是否允許使用者輸入為空
editable Admin中是否可以編輯
help_text Admin中該字段的提示資訊
choices Admin中顯示選擇框的内容,用不變動的資料放在記憶體中進而避免跨表操作
如:sex = models.IntegerField(choices=[(1, '男'), (2, '女'), (3, '保密')], default=3)
error_messages 自定義錯誤資訊(字典類型),進而定制想要顯示的錯誤資訊;
字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date
如:{'null': "不能為空.", 'invalid': '格式錯誤'}
validators 自定義錯誤驗證(清單類型),進而定制想要的驗證規則
from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator
如:
test = models.CharField(
max_length=32,
error_messages={
'c1': '優先錯資訊1',
'c2': '優先錯資訊2',
'c3': '優先錯資訊3',
},
validators=[
RegexValidator(regex='root_\d+', message='錯誤了', code='c1'),
RegexValidator(regex='root_112233\d+', message='又錯誤了', code='c2'),
EmailValidator(message='又錯誤了', code='c3'), ]
)
字段參數總覽
常用字段的參數
1.null 資料庫中字段是否可以為空
2.db_column 資料庫中字段的列名
3.default 資料庫中字段的預設值
4.primary_key 資料庫中字段是否為主鍵
5.db_index 資料庫中字段是否可以建立索引
6.unique 資料庫中字段是否可以建立唯一索引
7.unique_for_date 資料庫中字段【日期】部分是否可以建立唯一索引
8.unique_for_month 資料庫中字段【月】部分是否可以建立唯一索引
9.unique_for_year 資料庫中字段【年】部分是否可以建立唯一索引
10.DatetimeField和Datefield獨有的參數:
auto_now_add = True --> 目前資料的建立時間
auto_now = True --> 目前資料的最後修改時間
注意:auto_now_add和auto_now 不能寫在同一個字段上
11. 帶choice參數的字段
get_字段名_display() --> 擷取choice字段的顯示值
例如:
sex = models.IntegerField(choices=[(1, '男'), (2, '女'), (3, '保密')], default=3)
get_sex_display() --> 保密
12. 建表的元資訊
class Meta:
db_table = '表名'
unique_together = (('ip', 'port'),)
index_together = (("pub_date", "deadline"),)
7、元資訊
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 資料庫中生成的表名稱預設是app名稱 + 下劃線 + 類名(全小寫)
# 可以通過db_table進行修改
db_table = "userinfo" # 告訴Django這個表名就叫userinfo,不要預設建成 app名稱_userinfo
# 聯合索引
index_together = [
("pub_date", "deadline"),
]
# 聯合唯一索引
unique_together = (("ip", "port"),)
# admin中顯示的表名稱
verbose_name
# verbose_name加s
verbose_name_plural
例如:
# 部落格表
class Blog(models.Model):
title = models.CharField(max_length=32)
push_time = models.DateTimeField(auto_now_add=True) # 建立時間
edit_time = models.DateTimeField(auto_now=True) # 最後修改時間
class Meta:
db_table = 'blog' # 控制建表名稱
# 應用程式表
class Size(models.Model):
ip = models.GenericIPAddressField()
port = models.IntegerField()
class Meta:
unique_together = (('ip', 'port'),)
三、ORM的相關操作
小知識:
去manage.py把__name__的下一行,一直到最上面的那幾行代碼複制到一個py檔案,
import django
django.setup()
from appname.models import TableName
測試内容
小知識點
UserInfo表:
class UserInfo(models.Model):
name = MycharField(max_length=12)
birthday = models.DateTimeField(verbose_name='生日', null=True)
sex = models.IntegerField(choices=[(1, '男'), (2, '女'), (3, '保密')], default=3)
def __str__(self):
return self.name
UserInfo
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcugzNxQTNxkDO10SO3kjNzUzMxEzNwETM4EDMy0yN3QTO0QTMvwVMxgTMwIzLcdzN0kDN0EzLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
1、基本操作13條(必會)
1-1、傳回QuerySet對象(清單)的方法(傳回的是清單,清單中的元素是對象)
all()
查詢所有結果
filter(**kwargs)
它包含了與所給篩選條件相比對的對象
exclude(**kwargs)
它包含了與所給篩選條件不比對的對象
order_by(*field)
對查詢結果排序
reverse()
對查詢結果反向排序,請注意reverse()通常隻能在具有已定義順序的QuerySet上調用(在model類的Meta中指定ordering或調用order_by()方法)。
distinct()
從傳回結果中剔除重複紀錄(如果你查詢跨越多個表,可能在計算QuerySet時得到重複的結果。此時可以使用distinct(),注意隻有在PostgreSQL中支援按字段去重。)
1-2、特殊的QuerySet(傳回的是清單,但清單中的元素不是對象)
values(*field)
傳回一個ValueQuerySet——一個特殊的QuerySet,運作後得到的并不是一系列model的執行個體化對象,而是一個可疊代的字典序列
User.objects.all().values('id', 'name')
QuerySet [{'id': 1, 'name': '小明'}, {'id': 2, 'name': '小東'}]
values_list(*field)
它與values()非常相似,它傳回的是一個元組序列,values傳回的是一個字典序列
User.objects.all().values_list('id')
QuerySet [(1, '小明'), (2, '小東')]
1-3、傳回具體對象的
get(**kwargs)
傳回與所給篩選條件相比對的對象,傳回結果有且隻有一個,如果符合篩選條件的對象超過一個或者沒有都會抛出錯誤。
first()
傳回第一條記錄
last()
傳回最後一條記錄
1-4、傳回布爾值的方法
exists()
如果QuerySet包含資料,判斷表中是否有資料,有就傳回True,否則傳回False
1-5、傳回數字的方法
count()
傳回資料庫中比對查詢(QuerySet)的對象數量。
例子:
# all()找到UserInfo表中所有的對象
ret = UserInfo.objects.all()
print(ret)
# filter()找到名字是小明的那個人
ret1 = UserInfo.objects.filter(name='小明')
print(ret1)
# exclude()找到名字不是小明的那些人
ret1 = UserInfo.objects.exclude(name='小明')
print(ret1)
# values()傳回的還是清單,但清單中的不是對象,而是字典
ret = UserInfo.objects.all().values('name', 'sex')
print(ret)
# values_list()傳回的還是清單,但清單中的不是對象,而是元組
ret1 = UserInfo.objects.all().values_list('name', 'sex')
print(ret1)
# order_by('xx')根據xx升序排序,order_by('-xx')根據xx降序排序
ret = UserInfo.objects.all().order_by('id')
ret1 = UserInfo.objects.all().order_by('-id')
ret2 = UserInfo.objects.all().order_by('birthday')
print(ret)
print(ret1)
print(ret2)
# reverse() 對排序的結果進行反序
ret = UserInfo.objects.all().order_by('id').reverse()
print(ret)
# count()傳回數量
ret = UserInfo.objects.all().count()
print(ret)
# first()傳回第一條記錄和last()傳回最後一條記錄
ret1 = UserInfo.objects.all().first()
ret2 = UserInfo.objects.all().last()
print(ret1)
print(ret2)
# exists()判斷表中是否有資料
ret = UserInfo.objects.exists()
print(ret)
2、單表查詢之神奇的雙下劃線
# __lt:查詢id值小于3的對象
ret = UserInfo.objects.filter(id__lt=3)
print(ret)
# __lte:查詢id值小于等于3的對象
ret = UserInfo.objects.filter(id__lte=3)
print(ret)
# __gt:查詢id值大于3的對象
ret = UserInfo.objects.filter(id__gt=3)
print(ret)
# __in:id是1,3,5的對象
ret = UserInfo.objects.filter(id__in=[1, 3, 5])
print(ret)
# __in:id不是1,3,5的對象
ret = UserInfo.objects.exclude(id__in=[1, 3, 5])
print(ret)
# __contains:找到名字包含"小"的對象,__icontains:和__contains一樣,但是不區分大小寫
ret = UserInfo.objects.filter(name__contains='小')
print(ret)
# __range:找到範圍在[1, 3]之間的對象
ret = UserInfo.objects.filter(id__range=[1, 3])
print(ret)
# __endswith:找到以"仔"結尾的對象
ret = UserInfo.objects.filter(name__endswith='仔')
print(ret)
# date字段還可以使用__year、__month等:找到10月出生的人
ret = UserInfo.objects.filter(birthday__month=10)
print(ret)
# __isnull:判斷這個字段是否為空
ret = UserInfo.objects.filter(name__isnull=True)
print(ret)
# 雙下還可以鍊式操作:找到出生小于2000年的
ret = UserInfo.objects.filter(birthday__year__lt=2000)
print(ret)
轉載于:https://www.cnblogs.com/yidashi110/p/10091981.html