一、Django ORM 操作數據庫的概念
Django有一個強大的功能是它的對象關係映射Object-Relational Mapper(ORM),它允許你就像使用 SQL 一樣去和你的數據庫交互。事實上,Django 的 ORM 就是創建 SQL 去查詢和操作數據庫的一個利用 Python 類去操作數據庫的方式。
二、Django ORM 操作數據庫的方法
我們的程序涉及到數據庫相關操作時,常用的方法:
- 創建數據庫,設計表結構和字段
- 使用 MySQLdb 來連接數據庫,並編寫數據訪問層代碼
- 業務邏輯層去調用數據訪問層執行數據庫操作
ORM是什麼?:(在django中,根據代碼中的類自動生成數據庫的表也叫--code first)
ORM:Object Relational Mapping(關係對象映射)
類名對應------》數據庫中的表名
類屬性對應---------》數據庫裏的字段
類實例對應---------》數據庫表裏的一行數據
obj.id obj.name.....類實例對象的屬性
Django orm的優勢:
Django的orm操作本質上會根據對接的數據庫引擎,翻譯成對應的sql語句;所有使用Django開發的項目無需關心程序底層使用的是MySQL、Oracle、sqlite....,如果數據庫遷移,只需要更換Django的數據庫引擎即可;
2.1、Django連接MySQL
1、創建數據庫 (注意設置 數據的字符編碼)
由於Django自帶的orm是data_first類型的ORM,使用前必須先創建數據庫
create database django01 default charset=utf8 collate utf8_general_ci;
2、修改project中的settings.py文件中設置 連接 MySQL數據庫(Django默認使用的是sqllite數據庫)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME':'django01',
'USER': 'root',
'PASSWORD': '123123',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
擴展:查看orm操作執行的原生SQL語句,在project中的settings.py文件增加
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
3、修改project 中的__init__.py 文件設置 Django默認連接MySQL的方式
import pymysql
pymysql.install_as_MySQLdb()
4、settings.py文件註冊APP
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
]
5、進行數據遷移
5.1、在winds cmd或者Linux shell的項目的manage.py目錄下執行
python manage.py makemigrations # 將python類遷移爲sql語句,並保存在 makemigrations 文件中
python manage.py migrate # 執行遷移的sql語句,將數據寫入數據庫
擴展:修改表之後常見報錯
這個報錯:因爲表創建好之後,新增字段沒有設置默認值,或者原來表中字段設置了不能爲空參數,修改後的表結構和目前的數據衝突導致;
6、modles.py創建表
6.1、表的基本操作
from django.db import models
class UserInfo(models.Model): # 必須繼承models.Model
# 不寫則,django默認創建ID列,自增,主鍵
# 用戶名列,字符串類型,指定長度
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
6.1.1、常用字段
AutoField |
|
一個能夠根據可用ID自增的 IntegerField |
BooleanField |
|
一個真/假(true/false)字段 |
CharField |
(max_length) |
一個字符串字段,適用於中小長度的字符串。對於長段的文字,請使用 TextField |
CommaSeparatedIntegerField |
(max_length) |
一個用逗號分隔開的整數字段 |
DateField |
([auto_now], [auto_now_add]) |
日期字段 |
DateTimeField |
|
時間日期字段,接受跟 DateField 一樣的額外選項 |
EmailField |
|
一個能檢查值是否是有效的電子郵件地址的 CharField |
FileField |
(upload_to) |
一個文件上傳字段 |
FilePathField |
(path,[match],[recursive]) |
一個擁有若干可選項的字段,選項被限定爲文件系統中某個目錄下的文件名 |
FloatField |
(max_digits,decimal_places) |
一個浮點數,對應Python中的 float 實例 |
ImageField |
(upload_to, [height_field] ,[width_field]) |
像 FileField 一樣,只不過要驗證上傳的對象是一個有效的圖片。 |
IntegerField |
|
一個整數。 |
IPAddressField |
|
一個IP地址,以字符串格式表示(例如: "24.124.1.30" )。 |
NullBooleanField |
|
就像一個 BooleanField ,但它支持 None /Null 。 |
PhoneNumberField |
|
它是一個 CharField ,並且會檢查值是否是一個合法的美式電話格式 |
PositiveIntegerField |
|
和 IntegerField 類似,但必須是正值。 |
PositiveSmallIntegerField |
|
與 PositiveIntegerField 類似,但只允許小於一定值的值,最大值取決於數據庫. |
SlugField |
|
嵌條 就是一段內容的簡短標籤,這段內容只能包含字母、數字、下 劃線或連字符。通常用於URL中 |
SmallIntegerField |
|
和 IntegerField 類似,但是隻允許在一個數據庫相關的範圍內的數值(通常是-32,768到 +32,767) |
TextField |
|
一個不限長度的文字字段 |
TimeField |
|
時分秒的時間顯示。它接受的可指定參數與 DateField 和 DateTimeField 相同。 |
URLField |
|
用來存儲URL的字段。 |
USStateField |
|
美國州名稱縮寫,兩個字母。 |
XMLField |
(schema_path) |
它就是一個 TextField ,只不過要檢查值是匹配指定schema的合法XML。 |
通用字段參數列表(所有的字段類型都可以使用下面的參數,所有的都是可選的。)
參數名 |
意義 |
null |
如果設置爲 True 的話,Django將在數據庫中存儲空值爲 NULL 。默認爲 False 。 |
blank |
如果是 True ,該字段允許留空,默認爲 False 。 |
choices |
一個包含雙元素元組的可迭代的對象,用於給字段提供選項。 |
db_column |
當前字段在數據庫中對應的列的名字。 |
db_index |
如果爲 True ,Django會在創建表格(比如運行 manage.py syncdb )時對這一列創建數據庫索引。 |
default |
字段的默認值 |
editable |
如果爲 False ,這個字段在管理界面或表單裏將不能編輯。默認爲 True 。 |
help_text |
在管理界面表單對象裏顯示在字段下面的額外幫助文本。 |
primary_key |
如果爲 True ,這個字段就會成爲模型的主鍵。 |
radio_admin |
默認地,對於 ForeignKey 或者擁有 choices 設置的字段,Django管理界面會使用列表選擇框(<select>)。如果 radio_admin 設置爲 True 的話,Django就會使用單選按鈕界面。 |
unique |
如果是 True ,這個字段的值在整個表中必須是唯一的。 |
unique_for_date |
把它的值設成一個 DataField 或者 DateTimeField 的字段的名稱,可以確保字段在這個日期內不會出現重複值。 |
unique_for_month |
和 unique_for_date 類似,只是要求字段在指定字段的月份內唯一。 |
unique_for_year |
和 unique_for_date 及 unique_for_month 類似,只是時間範圍變成了一年。 |
verbose_name |
除 ForeignKey 、 ManyToManyField 和 OneToOneField 之外的字段都接受一個詳細名稱作爲第一個位置參數。 |
常用字段與參數表
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)
- 二進制類型
6.2、字段操作
增
models.Tb1.objects.create(c1='xx', c2='oo') #增加一條數據,可以接受字典類型數據 **kwargs
obj = models.Tb1(c1='xx', c2='oo')
dic = {'user':'yangmv','pwd':'123456'}
models.UserInfo.objects.create(**dic)
obj.save()
查
models.Tb1.objects.get(id=123) # 獲取單條數據,不存在則報錯(不建議)
models.Tb1.objects.get(user='yangmv')
models.Tb1.objects.all() # 獲取全部
models.Tb1.objects.all().values('user') #只取user列
models.Tb1.objects.all().values_list('id','user') #取出id和user列,並生成一個列表
models.Tb1.objects.filter(name='seven') # 獲取指定條件的數據
models.Tb1.objects.exclude(name='seven') # 獲取指定條件的數據
刪
models.Tb1.objects.filter(name='seven').delete() # 刪除指定條件的數據
改
models.Tb1.objects.filter(name='seven').update(gender='0') # 將指定條件的數據更新,均支持 **kwargs
obj = models.Tb1.objects.get(id=1)
obj.c1 = '35445'
obj.save() # 修改單條數據
6.3、查詢操作
獲取個數
models.Tb1.objects.filter(name='seven').count()
大於,小於
models.Tb1.objects.filter(id__gt=1) # 獲取id大於1的值
models.Tb1.objects.filter(id__gte=1) # 獲取id大於等於1的值
models.Tb1.objects.filter(id__lt=10) # 獲取id小於10的值
models.Tb1.objects.filter(id__lte=10) # 獲取id小於10的值
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值
in
models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於11、22、33的數據
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
isnull
Entry.objects.filter(pub_date__isnull=True)
contains
models.Tb1.objects.filter(name__contains="ven")
models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
models.Tb1.objects.exclude(name__icontains="ven")
range
models.Tb1.objects.filter(id__range=[1, 2]) # 範圍bettwen and
order by
models.Tb1.objects.filter(name='seven').order_by('id') # asc
models.Tb1.objects.filter(name='seven').order_by('-id') # desc
limit 、offset
models.Tb1.objects.all()[10:20]
regex正則匹配,iregex 不區分大小寫
Entry.objects.get(title__regex=r'^(An?|The) +')
Entry.objects.get(title__iregex=r'^(an?|the) +')
執行原生SQL
from django.db import connection, connections
cursor = connection.cursor()
django的settings中的db配置 ' default',指定數據庫
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
row = cursor.fetchone()
2 .extra
Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
3 . raw
name_map = {'a':'A','b':'B'}
models.UserInfo.objects.raw('select * from xxxx',translations=name_map)
6.4、自定義字段
class FixedCharField(models.Field):
"""
自定義的char類型的字段類
"""
def __init__(self, max_length, *args, **kwargs):
self.max_length = max_length
super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs)
def db_type(self, connection):
"""
限定生成數據庫表的字段類型爲char,長度爲max_length指定的值
"""
return 'char(%s)' % self.max_length
class Class(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=25)
# 使用自定義的char類型的字段
cname = FixedCharField(max_length=25)
7、補充
7.1 ORM字段參數
null:用於表示某個字段可以爲空。
unique:如果設置爲unique=True 則該字段在此表中必須是唯一的 。
db_index:如果db_index=True 則代表着爲此字段設置索引。
default:爲該字段設置默認值。
DateField 和 DateTimeField
auto_now_add:配置auto_now_add=True,創建數據記錄的時候會把當前時間添加到數據庫。
auto_now:配置上auto_now=True,每次更新數據記錄的時候會更新該字段。
null 數據庫中字段是否可以爲空
db_column 數據庫中字段的列名
db_tablespace
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中顯示選擇框的內容,用不變動的數據放在內存中從而避免跨表操作
如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)
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'), ]
)
7.3 關係字段
ForeignKey
外鍵類型在ORM中用來表示外鍵關聯關係,一般把ForeignKey字段設置在 '一對多'中'多'的一方。
ForeignKey:可以和其他表做關聯關係同時也可以和自身做關聯關係。
to:設置要關聯的表
to_field:設置要關聯的表的字段
related_name:反向操作時,使用的字段名,用於代替原反向查詢時的'表名_set'。
例如:
class Classes(models.Model):
name = models.CharField(max_length=32)
class Student(models.Model):
name = models.CharField(max_length=32)
theclass = models.ForeignKey(to="Classes")
當我們要查詢某個班級關聯的所有學生(反向查詢)時,我們會這麼寫:
models.Classes.objects.first().student_set.all()
當我們在ForeignKey字段中添加了參數 related_name 後,
class Student(models.Model):
name = models.CharField(max_length=32)
theclass = models.ForeignKey(to="Classes", related_name="students")
當我們要查詢某個班級關聯的所有學生(反向查詢)時,我們會這麼寫:
models.Classes.objects.first().students.all()
related_query_name:反向查詢操作時,使用的連接前綴,用於替換表名。
on_delete:當刪除關聯表中的數據時,當前表與其關聯的行的行爲。
models.CASCADE
刪除關聯數據,與之關聯也刪除
models.DO_NOTHING
刪除關聯數據,引發錯誤IntegrityError
models.PROTECT
刪除關聯數據,引發錯誤ProtectedError
models.SET_NULL
刪除關聯數據,與之關聯的值設置爲null(前提FK字段需要設置爲可空)
models.SET_DEFAULT
刪除關聯數據,與之關聯的值設置爲默認值(前提FK字段需要設置默認值)
models.SET
刪除關聯數據,
a. 與之關聯的值設置爲指定值,設置:models.SET(值)
b. 與之關聯的值設置爲可執行對象的返回值,設置:models.SET(可執行對象)
def func():
return 10
class MyModel(models.Model):
user = models.ForeignKey(
to="User",
to_field="id",
on_delete=models.SET(func)
)
db_constraint:是否在數據庫中創建外鍵約束,默認爲True。
OneToOneField
一對一字段。
通常一對一字段用來擴展已有字段。
一對一的關聯關係多用在當一張表的不同字段查詢頻次差距過大的情況下,將本可以存儲在一張表的字段拆開放置在兩張表中,然後將兩張表建立一對一的關聯關係。
class Author(models.Model):
name = models.CharField(max_length=32)
info = models.OneToOneField(to='AuthorInfo')
class AuthorInfo(models.Model):
phone = models.CharField(max_length=11)
email = models.EmailField()
to:設置要關聯的表。
to_field:設置要關聯的字段。
on_delete:同ForeignKey字段。
ManyToManyField
用於表示多對多的關聯關係。在數據庫中通過第三張表來建立關聯關係
to:設置要關聯的表
related_name:同ForeignKey字段。
related_query_name:同ForeignKey字段。
symmetrical:僅用於多對多自關聯時,指定內部是否創建反向操作的字段。默認爲True。
舉個例子:
class Person(models.Model):
name = models.CharField(max_length=16)
friends = models.ManyToManyField("self")
此時,person對象就沒有person_set屬性。
class Person(models.Model):
name = models.CharField(max_length=16)
friends = models.ManyToManyField("self", symmetrical=False)
此時,person對象現在就可以使用person_set屬性進行反向查詢。
through:
在使用ManyToManyField字段時,Django將自動生成一張表來管理多對多的關聯關係。
但我們也可以手動創建第三張表來管理多對多關係,此時就需要通過through來指定第三張表的表名。
through_fields:設置關聯的字段。
db_table:默認創建第三張表時,數據庫中表的名稱。
7.4 多對多關聯關係的三種方式
方式一:自行創建第三張表
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="書名")
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
# 自己創建第三張表,分別通過外鍵關聯書和作者
class Author2Book(models.Model):
author = models.ForeignKey(to="Author")
book = models.ForeignKey(to="Book")
class Meta:
unique_together = ("author", "book")
方式二:通過ManyToManyField自動創建第三張表
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="書名")
# 通過ORM自帶的ManyToManyField自動創建第三張表
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
books = models.ManyToManyField(to="Book", related_name="authors")
方式三:設置ManyTomanyField並指定自行創建的第三張表
class Book(models.Model):
title = models.CharField(max_length=32, verbose_name="書名")
# 自己創建第三張表,並通過ManyToManyField指定關聯
class Author(models.Model):
name = models.CharField(max_length=32, verbose_name="作者姓名")
books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
# through_fields接受一個2元組('field1','field2'):
# 其中field1是定義ManyToManyField的模型外鍵的名(author),field2是關聯目標模型(book)的外鍵名。
class Author2Book(models.Model):
author = models.ForeignKey(to="Author")
book = models.ForeignKey(to="Book")
class Meta:
unique_together = ("author", "book")
注意:
當我們需要在第三張關係表中存儲額外的字段時,就要使用第三種方式。但是當我們使用第三種方式創建多對多關聯關係時,就無法使用set、add、remove、clear方法來管理多對多的關係了,需要通過第三張表的model來管理多對多關係。
7.5 元信息
ORM對應的類裏面包含另一個Meta類,而Meta類封裝了一些數據庫的信息。主要字段如下:
db_table
ORM在數據庫中的表名默認是 app_類名,可以通過db_table可以重寫表名。
index_together:聯合索引。
unique_together:聯合唯一索引。
ordering:指定默認按什麼字段排序。
只有設置了該屬性,我們查詢到的結果纔可以被reverse()。
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
class Meta:
# 數據庫中生成的表名稱 默認 app名稱 + 下劃線 + 類名
db_table = "table_name"
# 聯合索引
index_together = [
("pub_date", "deadline"),
]
# 聯合唯一索引
unique_together = (("driver", "restaurant"),)
ordering = ('name',)
# admin中顯示的表名稱
verbose_name='哈哈'
# verbose_name加s
verbose_name_plural=verbose_name