Django之ORM
ORM介紹
ORM概念
ORM就是對(duì)象關(guān)系映射(Object Relational Mapping)的縮寫,顧名思義就是一種為了解決面向?qū)ο笈c關(guān)系數(shù)據(jù)庫存在的互不匹配的現(xiàn)象的技術(shù)。
簡單的說,ORM是通過使用描述對(duì)象和數(shù)據(jù)庫之間映射的元數(shù)據(jù),將程序中的對(duì)象自動(dòng)持久化到關(guān)系數(shù)據(jù)庫中。
ORM在業(yè)務(wù)邏輯層和數(shù)據(jù)庫層之間充當(dāng)了橋梁的作用。
ORM由來
字母O起源于"對(duì)象"(Object),而R則來自于"關(guān)系"(Relational)。
幾乎所有的軟件開發(fā)過程中都會(huì)涉及到對(duì)象和關(guān)系數(shù)據(jù)庫。在用戶層面和業(yè)務(wù)邏輯層面,我們是面向?qū)ο蟮摹.?dāng)對(duì)象的信息發(fā)生變化的時(shí)候,我們就需要把對(duì)象的信息保存在關(guān)系數(shù)據(jù)庫中。
按照之前的方式來進(jìn)行開發(fā)就會(huì)出現(xiàn)程序員會(huì)在自己的業(yè)務(wù)邏輯代碼中夾雜很多SQL語句用來增加、讀取、修改、刪除相關(guān)數(shù)據(jù),而這些代碼通常都是重復(fù)的。
ORM優(yōu)勢
ORM解決的主要問題是對(duì)象和關(guān)系的映射。它通常把一個(gè)類和一個(gè)表一一對(duì)應(yīng),類的每個(gè)實(shí)例對(duì)應(yīng)表中的一條記錄,類的每個(gè)屬性對(duì)應(yīng)表中的每個(gè)字段。?
ORM提供了對(duì)數(shù)據(jù)庫的映射,不用直接編寫SQL代碼,只需像操作對(duì)象一樣從數(shù)據(jù)庫操作數(shù)據(jù)。
讓軟件開發(fā)人員專注于業(yè)務(wù)邏輯的處理,提高了開發(fā)效率。
ORM劣勢
ORM的缺點(diǎn)是會(huì)在一定程度上犧牲程序的執(zhí)行效率。
ORM用多了SQL語句就不會(huì)寫了,關(guān)系數(shù)據(jù)庫相關(guān)技能退化..
Django中的ORM
Django項(xiàng)目中使用MySQL數(shù)據(jù)庫
1. 在Django項(xiàng)目的settings.py文件中,配置數(shù)據(jù)庫連接信息:
DATABASES = {"default": {"ENGINE": "django.db.backends.mysql","NAME": "你的數(shù)據(jù)庫名稱", # 需要自己手動(dòng)創(chuàng)建數(shù)據(jù)庫"USER": "數(shù)據(jù)庫用戶名","PASSWORD": "數(shù)據(jù)庫密碼","HOST": "數(shù)據(jù)庫IP","POST": 3306} }2. 在Django項(xiàng)目的__init__.py文件中寫如下代碼,告訴Django使用pymysql模塊連接MySQL數(shù)據(jù)庫:
import pymysqlpymysql.install_as_MySQLdb()Model
在Django中model是你數(shù)據(jù)的單一、明確的信息來源。它包含了你存儲(chǔ)的數(shù)據(jù)的重要字段和行為。通常,一個(gè)模型(model)映射到一個(gè)數(shù)據(jù)庫表,
基本情況:
每個(gè)模型都是一個(gè)Python類,它是django.db.models.Model的子類。
模型的每個(gè)屬性都代表一個(gè)數(shù)據(jù)庫字段。
綜上所述,Django為您提供了一個(gè)自動(dòng)生成的數(shù)據(jù)庫訪問API,詳詢https://docs.djangoproject.com/en/2.0/topics/db/queries/。
快速入門
下面這個(gè)例子定義了一個(gè)?Person?模型,包含?first_name?和?last_name。
from django.db import modelsclass Person(models.Model):first_name = models.CharField(max_length=30)last_name = models.CharField(max_length=30)first_name?和?last_name?是模型的字段。每個(gè)字段被指定為一個(gè)類屬性,每個(gè)屬性映射到一個(gè)數(shù)據(jù)庫列。
上面的?Person?模型將會(huì)像這樣創(chuàng)建一個(gè)數(shù)據(jù)庫表:
CREATE TABLE myapp_person ("id" serial NOT NULL PRIMARY KEY,"first_name" varchar(30) NOT NULL,"last_name" varchar(30) NOT NULL );補(bǔ)充說明:
表myapp_person的名稱是自動(dòng)生成的,如果你要自定義表名,需要在model的Meta類中指定?db_table?參數(shù),強(qiáng)烈建議使用小寫表名,特別是使用MySQL作為后端數(shù)據(jù)庫時(shí)。
id字段是自動(dòng)添加的,如果你想要指定自定義主鍵,只需在其中一個(gè)字段中指定?primary_key=True?即可。如果Django發(fā)現(xiàn)你已經(jīng)明確地設(shè)置了Field.primary_key,它將不會(huì)添加自動(dòng)ID列。
本示例中的CREATE TABLE SQL使用PostgreSQL語法進(jìn)行格式化,但值得注意的是,Django會(huì)根據(jù)配置文件中指定的數(shù)據(jù)庫后端類型來生成相應(yīng)的SQL語句。
Django支持MySQL5.5及更高版本。
字段
AutoField(Field)- int自增列,必須填入?yún)?shù) primary_key=TrueBigAutoField(AutoField)- bigint自增列,必須填入?yún)?shù) primary_key=True注:當(dāng)model中如果沒有自增列,則自動(dòng)會(huì)創(chuàng)建一個(gè)列名為id的列from django.db import modelsclass UserInfo(models.Model):# 自動(dòng)創(chuàng)建一個(gè)列名為id的且為自增的整數(shù)列username = models.CharField(max_length=32)class Group(models.Model):# 自定義自增列nid = models.AutoField(primary_key=True)name = models.CharField(max_length=32)SmallIntegerField(IntegerField):- 小整數(shù) -32768 ~ 32767PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正小整數(shù) 0 ~ 32767IntegerField(Field)- 整數(shù)列(有符號(hào)的) -2147483648 ~ 2147483647PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)- 正整數(shù) 0 ~ 2147483647BigIntegerField(IntegerField):- 長整型(有符號(hào)的) -9223372036854775808 ~ 9223372036854775807BooleanField(Field)- 布爾值類型NullBooleanField(Field):- 可以為空的布爾值CharField(Field)- 字符類型- 必須提供max_length參數(shù), max_length表示字符長度TextField(Field)- 文本類型EmailField(CharField):- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證機(jī)制IPAddressField(Field)- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 IPV4 機(jī)制GenericIPAddressField(Field)- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 Ipv4和Ipv6- 參數(shù):protocol,用于指定Ipv4或Ipv6, 'both',"ipv4","ipv6"unpack_ipv4, 如果指定為True,則輸入::ffff:192.0.2.1時(shí)候,可解析為192.0.2.1,開啟此功能,需要protocol="both"URLField(CharField)- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 URLSlugField(CharField)- 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證支持 字母、數(shù)字、下劃線、連接符(減號(hào))CommaSeparatedIntegerField(CharField)- 字符串類型,格式必須為逗號(hào)分割的數(shù)字UUIDField(Field)- 字符串類型,Django Admin以及ModelForm中提供對(duì)UUID格式的驗(yàn)證FilePathField(Field)- 字符串,Django Admin以及ModelForm中提供讀取文件夾下文件的功能- 參數(shù):path, 文件夾路徑match=None, 正則匹配recursive=False, 遞歸下面的文件夾allow_files=True, 允許文件allow_folders=False, 允許文件夾FileField(Field)- 字符串,路徑保存在數(shù)據(jù)庫,文件上傳到指定目錄- 參數(shù):upload_to = "" 上傳文件的保存路徑storage = None 存儲(chǔ)組件,默認(rèn)django.core.files.storage.FileSystemStorageImageField(FileField)- 字符串,路徑保存在數(shù)據(jù)庫,文件上傳到指定目錄- 參數(shù):upload_to = "" 上傳文件的保存路徑storage = None 存儲(chǔ)組件,默認(rèn)django.core.files.storage.FileSystemStoragewidth_field=None, 上傳圖片的高度保存的數(shù)據(jù)庫字段名(字符串)height_field=None 上傳圖片的寬度保存的數(shù)據(jù)庫字段名(字符串)DateTimeField(DateField)- 日期+時(shí)間格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]DateField(DateTimeCheckMixin, Field)- 日期格式 YYYY-MM-DDTimeField(DateTimeCheckMixin, Field)- 時(shí)間格式 HH:MM[:ss[.uuuuuu]]DurationField(Field)- 長整數(shù),時(shí)間間隔,數(shù)據(jù)庫中按照bigint存儲(chǔ),ORM中獲取的值為datetime.timedelta類型FloatField(Field)- 浮點(diǎn)型DecimalField(Field)- 10進(jìn)制小數(shù)- 參數(shù):max_digits,小數(shù)總長度decimal_places,小數(shù)位長度BinaryField(Field)- 二進(jìn)制類型 字段相關(guān)內(nèi)容自定義字段
class UnsignedIntegerField(models.IntegerField):def db_type(self, connection):return 'integer UNSIGNED'PS: 返回值為字段在數(shù)據(jù)庫中的屬性,Django字段默認(rèn)的值為:'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)', 自定義一個(gè)無符號(hào)整數(shù)字段自定義char類型字段:
class FixedCharField(models.Field):"""自定義的char類型的字段類"""def __init__(self, max_length, *args, **kwargs):self.max_length = max_lengthsuper(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs)def db_type(self, connection):"""限定生成數(shù)據(jù)庫表的字段類型為char,長度為max_length指定的值"""return 'char(%s)' % self.max_lengthclass Class(models.Model):id = models.AutoField(primary_key=True)title = models.CharField(max_length=25)# 使用自定義的char類型的字段cname = FixedCharField(max_length=25)創(chuàng)建的表結(jié)構(gòu):
注意事項(xiàng)
1.觸發(fā)Model中的驗(yàn)證和錯(cuò)誤提示有兩種方式:a. Django Admin中的錯(cuò)誤信息會(huì)優(yōu)先根據(jù)Admiin內(nèi)部的ModelForm錯(cuò)誤信息提示,如果都成功,才來檢查Model的字段并顯示指定錯(cuò)誤信息b. 使用ModelFormc. 調(diào)用Model對(duì)象的 clean_fields 方法,如:# models.pyclass UserInfo(models.Model):nid = models.AutoField(primary_key=True)username = models.CharField(max_length=32)email = models.EmailField(error_messages={'invalid': '格式錯(cuò)了.'})# views.pydef index(request):obj = models.UserInfo(username='11234', email='uu')try:print(obj.clean_fields())except Exception as e:print(e)return HttpResponse('ok')# Model的clean方法是一個(gè)鉤子,可用于定制操作,如:上述的異常處理。2.Admin中修改錯(cuò)誤提示# admin.pyfrom django.contrib import adminfrom model_club import modelsfrom django import formsclass UserInfoForm(forms.ModelForm):age = forms.IntegerField(initial=1, error_messages={'required': '請(qǐng)輸入數(shù)值.', 'invalid': '年齡必須為數(shù)值.'})class Meta:model = models.UserInfo# fields = ('username',)fields = "__all__"exclude = ['title']labels = { 'name':'Writer', }help_texts = {'name':'some useful help text.',}error_messages={ 'name':{'max_length':"this writer name is too long"} }widgets={'name':Textarea(attrs={'cols':80,'rows':20})}class UserInfoAdmin(admin.ModelAdmin):form = UserInfoFormadmin.site.register(models.UserInfo, UserInfoAdmin) 注意事項(xiàng)字段參數(shù)
null 數(shù)據(jù)庫中字段是否可以為空db_column 數(shù)據(jù)庫中字段的列名default 數(shù)據(jù)庫中字段的默認(rèn)值primary_key 數(shù)據(jù)庫中字段是否為主鍵db_index 數(shù)據(jù)庫中字段是否可以建立索引unique 數(shù)據(jù)庫中字段是否可以建立唯一索引unique_for_date 數(shù)據(jù)庫中字段【日期】部分是否可以建立唯一索引unique_for_month 數(shù)據(jù)庫中字段【月】部分是否可以建立唯一索引unique_for_year 數(shù)據(jù)庫中字段【年】部分是否可以建立唯一索引verbose_name Admin中顯示的字段名稱blank Admin中是否允許用戶輸入為空editable Admin中是否可以編輯help_text Admin中該字段的提示信息choices Admin中顯示選擇框的內(nèi)容,用不變動(dòng)的數(shù)據(jù)放在內(nèi)存中從而避免跨表操作如:gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)error_messages 自定義錯(cuò)誤信息(字典類型),從而定制想要顯示的錯(cuò)誤信息;字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date如:{'null': "不能為空.", 'invalid': '格式錯(cuò)誤'}validators 自定義錯(cuò)誤驗(yàn)證(列表類型),從而定制想要的驗(yàn)證規(guī)則from django.core.validators import RegexValidatorfrom django.core.validators import EmailValidator,URLValidator,DecimalValidator,\MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator如:test = models.CharField(max_length=32,error_messages={'c1': '優(yōu)先錯(cuò)信息1','c2': '優(yōu)先錯(cuò)信息2','c3': '優(yōu)先錯(cuò)信息3',},validators=[RegexValidator(regex='root_\d+', message='錯(cuò)誤了', code='c1'),RegexValidator(regex='root_112233\d+', message='又錯(cuò)誤了', code='c2'),EmailValidator(message='又錯(cuò)誤了', code='c3'), ]) 字段參數(shù)元信息
class UserInfo(models.Model):nid = models.AutoField(primary_key=True)username = models.CharField(max_length=32)class Meta:# 數(shù)據(jù)庫中生成的表名稱 默認(rèn) app名稱 + 下劃線 + 類名db_table = "table_name"# 聯(lián)合索引index_together = [("pub_date", "deadline"),]# 聯(lián)合唯一索引unique_together = (("driver", "restaurant"),)# admin中顯示的表名稱 verbose_name# verbose_name加sverbose_name_plural 元信息多表關(guān)系和參數(shù)
ForeignKey(ForeignObject) # ForeignObject(RelatedField)to, # 要進(jìn)行關(guān)聯(lián)的表名to_field=None, # 要關(guān)聯(lián)的表中的字段名稱on_delete=None, # 當(dāng)刪除關(guān)聯(lián)表中的數(shù)據(jù)時(shí),當(dāng)前表與其關(guān)聯(lián)的行的行為- models.CASCADE,刪除關(guān)聯(lián)數(shù)據(jù),與之關(guān)聯(lián)也刪除- models.DO_NOTHING,刪除關(guān)聯(lián)數(shù)據(jù),引發(fā)錯(cuò)誤IntegrityError- models.PROTECT,刪除關(guān)聯(lián)數(shù)據(jù),引發(fā)錯(cuò)誤ProtectedError- models.SET_NULL,刪除關(guān)聯(lián)數(shù)據(jù),與之關(guān)聯(lián)的值設(shè)置為null(前提FK字段需要設(shè)置為可空)- models.SET_DEFAULT,刪除關(guān)聯(lián)數(shù)據(jù),與之關(guān)聯(lián)的值設(shè)置為默認(rèn)值(前提FK字段需要設(shè)置默認(rèn)值)- models.SET,刪除關(guān)聯(lián)數(shù)據(jù),a. 與之關(guān)聯(lián)的值設(shè)置為指定值,設(shè)置:models.SET(值)b. 與之關(guān)聯(lián)的值設(shè)置為可執(zhí)行對(duì)象的返回值,設(shè)置:models.SET(可執(zhí)行對(duì)象)def func():return 10class MyModel(models.Model):user = models.ForeignKey(to="User",to_field="id"on_delete=models.SET(func),)related_name=None, # 反向操作時(shí),使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()related_query_name=None, # 反向操作時(shí),使用的連接前綴,用于替換【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')limit_choices_to=None, # 在Admin或ModelForm中顯示關(guān)聯(lián)數(shù)據(jù)時(shí),提供的條件:# 如:- limit_choices_to={'nid__gt': 5}- limit_choices_to=lambda : {'nid__gt': 5}from django.db.models import Q- limit_choices_to=Q(nid__gt=10)- limit_choices_to=Q(nid=8) | Q(nid__gt=10)- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')db_constraint=True # 是否在數(shù)據(jù)庫中創(chuàng)建外鍵約束parent_link=False # 在Admin中是否顯示關(guān)聯(lián)數(shù)據(jù) OneToOneField(ForeignKey)to, # 要進(jìn)行關(guān)聯(lián)的表名to_field=None # 要關(guān)聯(lián)的表中的字段名稱on_delete=None, # 當(dāng)刪除關(guān)聯(lián)表中的數(shù)據(jù)時(shí),當(dāng)前表與其關(guān)聯(lián)的行的行為###### 對(duì)于一對(duì)一 ####### 1. 一對(duì)一其實(shí)就是 一對(duì)多 + 唯一索引# 2.當(dāng)兩個(gè)類之間有繼承關(guān)系時(shí),默認(rèn)會(huì)創(chuàng)建一個(gè)一對(duì)一字段# 如下會(huì)在A表中額外增加一個(gè)c_ptr_id列且唯一:class C(models.Model):nid = models.AutoField(primary_key=True)part = models.CharField(max_length=12)class A(C):id = models.AutoField(primary_key=True)code = models.CharField(max_length=1)ManyToManyField(RelatedField)to, # 要進(jìn)行關(guān)聯(lián)的表名related_name=None, # 反向操作時(shí),使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all()related_query_name=None, # 反向操作時(shí),使用的連接前綴,用于替換【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名')limit_choices_to=None, # 在Admin或ModelForm中顯示關(guān)聯(lián)數(shù)據(jù)時(shí),提供的條件:# 如:- limit_choices_to={'nid__gt': 5}- limit_choices_to=lambda : {'nid__gt': 5}from django.db.models import Q- limit_choices_to=Q(nid__gt=10)- limit_choices_to=Q(nid=8) | Q(nid__gt=10)- limit_choices_to=lambda : Q(Q(nid=8) | Q(nid__gt=10)) & Q(caption='root')symmetrical=None, # 僅用于多對(duì)多自關(guān)聯(lián)時(shí),symmetrical用于指定內(nèi)部是否創(chuàng)建反向操作的字段# 做如下操作時(shí),不同的symmetrical會(huì)有不同的可選字段 models.BB.objects.filter(...)# 可選字段有:code, id, m1class BB(models.Model):code = models.CharField(max_length=12)m1 = models.ManyToManyField('self',symmetrical=True)# 可選字段有: bb, code, id, m1class BB(models.Model):code = models.CharField(max_length=12)m1 = models.ManyToManyField('self',symmetrical=False)through=None, # 自定義第三張表時(shí),使用字段用于指定關(guān)系表through_fields=None, # 自定義第三張表時(shí),使用字段用于指定關(guān)系表中那些字段做多對(duì)多關(guān)系表from django.db import modelsclass Person(models.Model):name = models.CharField(max_length=50)class Group(models.Model):name = models.CharField(max_length=128)members = models.ManyToManyField(Person,through='Membership',through_fields=('group', 'person'),)class Membership(models.Model):group = models.ForeignKey(Group, on_delete=models.CASCADE)person = models.ForeignKey(Person, on_delete=models.CASCADE)inviter = models.ForeignKey(Person,on_delete=models.CASCADE,related_name="membership_invites",)invite_reason = models.CharField(max_length=64)db_constraint=True, # 是否在數(shù)據(jù)庫中創(chuàng)建外鍵約束db_table=None, # 默認(rèn)創(chuàng)建第三張表時(shí),數(shù)據(jù)庫中表的名稱 多表關(guān)系和參數(shù)ORM操作
基本操作
# 增 models.Tb1.objects.create(c1='xx', c2='oo') # 增加一條數(shù)據(jù),可以接受字典類型數(shù)據(jù) **kwargs obj = models.Tb1(c1='xx', c2='oo') obj.save()# 查 models.Tb1.objects.get(id=123) # 獲取單條數(shù)據(jù),不存在則報(bào)錯(cuò)(不建議) models.Tb1.objects.all() # 獲取全部 models.Tb1.objects.filter(name='seven') # 獲取指定條件的數(shù)據(jù) models.Tb1.objects.exclude(name='seven') # 去除指定條件的數(shù)據(jù)# 刪 # models.Tb1.objects.filter(name='seven').delete() # 刪除指定條件的數(shù)據(jù)# 改 models.Tb1.objects.filter(name='seven').update(gender='0') # 將指定條件的數(shù)據(jù)更新,均支持 **kwargs obj = models.Tb1.objects.get(id=1) obj.c1 = '111' obj.save() # 修改單條數(shù)據(jù)進(jìn)階操作
# 獲取個(gè)數(shù)# # 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的數(shù)據(jù)# 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# 其他類似# # startswith,istartswith, endswith, iendswith,# order by# # models.Tb1.objects.filter(name='seven').order_by('id') # asc# models.Tb1.objects.filter(name='seven').order_by('-id') # desc# group by# # from django.db.models import Count, Min, Max, Sum# models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num'))# SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id"# limit 、offset# # models.Tb1.objects.all()[10:20]# regex正則匹配,iregex 不區(qū)分大小寫# # Entry.objects.get(title__regex=r'^(An?|The) +')# Entry.objects.get(title__iregex=r'^(an?|the) +')# date# # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))# Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))# year# # Entry.objects.filter(pub_date__year=2005)# Entry.objects.filter(pub_date__year__gte=2005)# month# # Entry.objects.filter(pub_date__month=12)# Entry.objects.filter(pub_date__month__gte=6)# day# # Entry.objects.filter(pub_date__day=3)# Entry.objects.filter(pub_date__day__gte=3)# week_day# # Entry.objects.filter(pub_date__week_day=2)# Entry.objects.filter(pub_date__week_day__gte=2)# hour# # Event.objects.filter(timestamp__hour=23)# Event.objects.filter(time__hour=5)# Event.objects.filter(timestamp__hour__gte=12)# minute# # Event.objects.filter(timestamp__minute=29)# Event.objects.filter(time__minute=46)# Event.objects.filter(timestamp__minute__gte=29)# second# # Event.objects.filter(timestamp__second=31)# Event.objects.filter(time__second=2)# Event.objects.filter(timestamp__second__gte=31) 進(jìn)階操作高級(jí)操作
# extra # 在QuerySet的基礎(chǔ)上繼續(xù)執(zhí)行子語句 # extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)# select和select_params是一組,where和params是一組,tables用來設(shè)置from哪個(gè)表 # Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,)) # Entry.objects.extra(where=['headline=%s'], params=['Lennon']) # Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"]) # Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid']) 舉個(gè)例子: models.UserInfo.objects.extra(select={'newid':'select count(1) from app01_usertype where id>%s'},select_params=[1,],where = ['age>%s'],params=[18,],order_by=['-age'],tables=['app01_usertype'])"""select app01_userinfo.id,(select count(1) from app01_usertype where id>1) as newidfrom app01_userinfo,app01_usertypewhere app01_userinfo.age > 18order by app01_userinfo.age desc"""# 執(zhí)行原生SQL # 更高靈活度的方式執(zhí)行原生SQL語句 # from django.db import connection, connections # cursor = connection.cursor() # cursor = connections['default'].cursor() # cursor.execute("""SELECT * from auth_user where id = %s""", [1]) # row = cursor.fetchone() 高級(jí)操作QuerySet相關(guān)方法
################################################################## # PUBLIC METHODS THAT ALTER ATTRIBUTES AND RETURN A NEW QUERYSET # ##################################################################def all(self)# 獲取所有的數(shù)據(jù)對(duì)象def filter(self, *args, **kwargs)# 條件查詢# 條件可以是:參數(shù),字典,Qdef exclude(self, *args, **kwargs)# 條件查詢# 條件可以是:參數(shù),字典,Qdef select_related(self, *fields)性能相關(guān):表之間進(jìn)行join連表操作,一次性獲取關(guān)聯(lián)的數(shù)據(jù)。總結(jié):1. select_related主要針一對(duì)一和多對(duì)一關(guān)系進(jìn)行優(yōu)化。2. select_related使用SQL的JOIN語句進(jìn)行優(yōu)化,通過減少SQL查詢的次數(shù)來進(jìn)行優(yōu)化、提高性能。def prefetch_related(self, *lookups)性能相關(guān):多表連表操作時(shí)速度會(huì)慢,使用其執(zhí)行多次SQL查詢?cè)赑ython代碼中實(shí)現(xiàn)連表操作。總結(jié):1. 對(duì)于多對(duì)多字段(ManyToManyField)和一對(duì)多字段,可以使用prefetch_related()來進(jìn)行優(yōu)化。2. prefetch_related()的優(yōu)化方式是分別查詢每個(gè)表,然后用Python處理他們之間的關(guān)系。def annotate(self, *args, **kwargs)# 用于實(shí)現(xiàn)聚合group by查詢from django.db.models import Count, Avg, Max, Min, Sumv = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))# SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)# SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1 v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)# SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1def distinct(self, *field_names)# 用于distinct去重models.UserInfo.objects.values('nid').distinct()# select distinct nid from userinfo 注:只有在PostgreSQL中才能使用distinct進(jìn)行去重def order_by(self, *field_names)# 用于排序models.UserInfo.objects.all().order_by('-id','age')def extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)# 構(gòu)造額外的查詢條件或者映射,如:子查詢 Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))Entry.objects.extra(where=['headline=%s'], params=['Lennon'])Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])def reverse(self):# 倒序models.UserInfo.objects.all().order_by('-nid').reverse()# 注:如果存在order_by,reverse則是倒序,如果多個(gè)排序則一一倒序def defer(self, *fields):models.UserInfo.objects.defer('username','id')或models.UserInfo.objects.filter(...).defer('username','id')#映射中排除某列數(shù)據(jù)def only(self, *fields):#僅取某個(gè)表中的數(shù)據(jù)models.UserInfo.objects.only('username','id')或models.UserInfo.objects.filter(...).only('username','id')def using(self, alias):指定使用的數(shù)據(jù)庫,參數(shù)為別名(setting中的設(shè)置)################################################## # PUBLIC METHODS THAT RETURN A QUERYSET SUBCLASS # ##################################################def raw(self, raw_query, params=None, translations=None, using=None):# 執(zhí)行原生SQLmodels.UserInfo.objects.raw('select * from userinfo')# 如果SQL是其他表時(shí),必須將名字設(shè)置為當(dāng)前UserInfo對(duì)象的主鍵列名models.UserInfo.objects.raw('select id as nid from 其他表')# 為原生SQL設(shè)置參數(shù)models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])# 將獲取的到列名轉(zhuǎn)換為指定列名name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)# 指定數(shù)據(jù)庫models.UserInfo.objects.raw('select * from userinfo', using="default")################### 原生SQL ###################from django.db import connection, connectionscursor = connection.cursor() # cursor = connections['default'].cursor()cursor.execute("""SELECT * from auth_user where id = %s""", [1])row = cursor.fetchone() # fetchall()/fetchmany(..)def values(self, *fields):# 獲取每行數(shù)據(jù)為字典格式def values_list(self, *fields, **kwargs):# 獲取每行數(shù)據(jù)為元祖def dates(self, field_name, kind, order='ASC'):# 根據(jù)時(shí)間進(jìn)行某一部分進(jìn)行去重查找并截取指定內(nèi)容# kind只能是:"year"(年), "month"(年-月), "day"(年-月-日)# order只能是:"ASC" "DESC"# 并獲取轉(zhuǎn)換后的時(shí)間- year : 年-01-01- month: 年-月-01- day : 年-月-日models.DatePlus.objects.dates('ctime','day','DESC')def datetimes(self, field_name, kind, order='ASC', tzinfo=None):# 根據(jù)時(shí)間進(jìn)行某一部分進(jìn)行去重查找并截取指定內(nèi)容,將時(shí)間轉(zhuǎn)換為指定時(shí)區(qū)時(shí)間# kind只能是 "year", "month", "day", "hour", "minute", "second"# order只能是:"ASC" "DESC"# tzinfo時(shí)區(qū)對(duì)象models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.UTC)models.DDD.objects.datetimes('ctime','hour',tzinfo=pytz.timezone('Asia/Shanghai'))"""pip3 install pytzimport pytzpytz.all_timezonespytz.timezone(‘Asia/Shanghai’)"""def none(self):# 空QuerySet對(duì)象#################################### # METHODS THAT DO DATABASE QUERIES # ####################################def aggregate(self, *args, **kwargs):# 聚合函數(shù),獲取字典類型聚合結(jié)果from django.db.models import Count, Avg, Max, Min, Sumresult = models.UserInfo.objects.aggregate(k=Count('u_id', distinct=True), n=Count('nid'))===> {'k': 3, 'n': 4}def count(self):# 獲取個(gè)數(shù)def get(self, *args, **kwargs):# 獲取單個(gè)對(duì)象def create(self, **kwargs):# 創(chuàng)建對(duì)象def bulk_create(self, objs, batch_size=None):# 批量插入# batch_size表示一次插入的個(gè)數(shù)objs = [models.DDD(name='r11'),models.DDD(name='r22')]models.DDD.objects.bulk_create(objs, 10)def get_or_create(self, defaults=None, **kwargs):# 如果存在,則獲取,否則,創(chuàng)建# defaults 指定創(chuàng)建時(shí),其他字段的值obj, created = models.UserInfo.objects.get_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 2})def update_or_create(self, defaults=None, **kwargs):# 如果存在,則更新,否則,創(chuàng)建# defaults 指定創(chuàng)建時(shí)或更新時(shí)的其他字段obj, created = models.UserInfo.objects.update_or_create(username='root1', defaults={'email': '1111111','u_id': 2, 't_id': 1})def first(self):# 獲取第一個(gè)def last(self):# 獲取最后一個(gè)def in_bulk(self, id_list=None):# 根據(jù)主鍵ID進(jìn)行查找id_list = [11,21,31]models.DDD.objects.in_bulk(id_list)def delete(self):# 刪除def update(self, **kwargs):# 更新def exists(self):# 是否有結(jié)果 其他操作 QuerySet方法大全?
轉(zhuǎn)載于:https://www.cnblogs.com/xubohua/p/8651959.html
總結(jié)
以上是生活随笔為你收集整理的Django之ORM的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 九点标定进行仿射变换halcon仿真代码
- 下一篇: 模拟查找晶元的位置