Django里的ORM操作

ORM

??ORM框架的目的是不再使用SQL語(yǔ)句,讓用戶使用對(duì)象類和對(duì)象的方式和這個(gè)框架內(nèi)部的方法來(lái)進(jìn)行數(shù)據(jù)庫(kù)操作,對(duì)于ORM框架來(lái)說(shuō),把類和對(duì)象轉(zhuǎn)換成SQL語(yǔ)句.
優(yōu)點(diǎn):
?1.ORM提供了對(duì)數(shù)據(jù)庫(kù)的映射,不用直接編寫(xiě)SQL代碼,只需要操作對(duì)象就能對(duì)數(shù)據(jù)庫(kù)操作數(shù)據(jù)
?2.讓軟件開(kāi)發(fā)人員專注于業(yè)務(wù)邏輯的處理,提高了開(kāi)發(fā)的效率
缺點(diǎn):
?1.ORM的缺點(diǎn)是會(huì)在一定程度上犧牲程序的執(zhí)行效率
?2.ORM的操作是有限的,也就是ORM定義好的操作是可以完成的
對(duì)應(yīng)關(guān)系:
?類 ?。尽?shù)據(jù)表
?對(duì)象?。尽?shù)據(jù)行
?屬性 --> 字段

ORM表模型

一對(duì)一(one-to-one)

實(shí)質(zhì)就是在主外鍵的關(guān)系基礎(chǔ)上,給外鍵加了一個(gè)unique=Ture的屬性,方法OneToOnefiled()

一對(duì)多(one-to-many)

什么時(shí)候需要外鍵
??一張表里的數(shù)據(jù)會(huì)在其它多個(gè)表中被使用,這個(gè)數(shù)據(jù)就會(huì)被稱為外鍵
在Django中使用外鍵
publisher = models.Foreignkey(to='類名')
ORM在數(shù)據(jù)庫(kù)中創(chuàng)建該字段的時(shí)候會(huì)默認(rèn)在后面加_id
在ORM中使用外鍵
book_obj.publisher --> 表示的是和書(shū)關(guān)聯(lián)的出版社對(duì)象(ORM幫我們封裝的)
book_obj.publisher_id --> 表示數(shù)據(jù)庫(kù)中真正保存的字段(int)

多對(duì)多(many-to-many)

語(yǔ)法:book = models.ManyToManyField(to='book')
自動(dòng)創(chuàng)建第三張表:實(shí)質(zhì)就是創(chuàng)建了兩個(gè)foreign_key

什么是QuerySet

從數(shù)據(jù)庫(kù)中查詢出來(lái)的結(jié)果一般是一個(gè)集合,這個(gè)集合叫做QuerySet。
注意:
(1)QuerySet是可以迭代的
(2)支持切片
(3)可以用len()和count()函數(shù)測(cè)量數(shù)量。
(4)可以通過(guò)list()函數(shù)強(qiáng)行變成列表。

ORM的增刪查改

類名.objects.all()           --> 查找數(shù)據(jù)庫(kù)中該表的所有數(shù)據(jù)
類名.objects.filter(條件)    --> 根據(jù)給定的條件取數(shù)據(jù)庫(kù)中查找,返回的是列表
類名.objects.get(條件)       --> 根據(jù)條件找到一個(gè)對(duì)象(找到多個(gè)或者找不到都報(bào)錯(cuò)),返回的是對(duì)象

多對(duì)多的查詢:
author_obj.book.all() ---> 返回一個(gè)書(shū)籍的列表

類名.objects.create()

多對(duì)多的增加:
對(duì)象.book.add(id1, id2) --> 多對(duì)多添加關(guān)聯(lián)的數(shù)據(jù)

類名.objects.filter(條件).delete()
類名.objects.get(條件).delete()

多對(duì)多的刪除:
對(duì)象.book.clear()
補(bǔ)充Django2.0以上的版本,外鍵需要手動(dòng)設(shè)置級(jí)聯(lián)操作 on_delete=models.CASCADE

obj = 類名.objects.get(條件)
obj.屬性 = ‘新值’
obj.save()
類名.objects.filter(條件).update(字段=‘新值’)

多對(duì)多的修改:
author_obj.book.set([id1, id2]) --> 多對(duì)多的設(shè)置關(guān)聯(lián)的數(shù)據(jù)

外鍵的增刪查改

Book.objects.all()          --> 返回的是一個(gè)列表(QuerySet)
Book.objects.filter()       --> 返回的是一個(gè)列表(QuerySet)
Book.objects.get()          --> 返回的是一個(gè)具體書(shū)籍對(duì)象
Book.objects.filter().delete()
Book.objects.get().delete()
Book.objects.create(title='', publisher='出版社對(duì)象')
Book.objects.create(title='', publisher_id='出版社id值')

(1) 基于對(duì)象的修改

book_obj = Book.objects.get(id='id值')
book_obj.title = '書(shū)名'
book_obj.publisher_id = '出版社id值'
book_obj.save()

(2) 基于QuerySet的修改

Book.objects.filter(id='id值').update(title='值',publisher_id='值')

ORM常用字段和參數(shù)

常用字段

AutoField

int自增列,必須填入?yún)?shù)primary_key=Ture.當(dāng)model中如果沒(méi)有自增列的時(shí)候會(huì)自動(dòng)創(chuàng)建

IntegerField

一個(gè)整數(shù)類型,范圍在-2147483648 to 2147483647,只有10位不能表示手機(jī)號(hào)。

CharField

字符類型,必須提供max_length參數(shù), max_length表示字符長(zhǎng)度。

DataField

日期字段,日期格式 YYYY-MM-DD,相當(dāng)于Python中的datetime.date()實(shí)例。

Data TimeField

日期時(shí)間字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相當(dāng)于Python中的datetime.datetime()實(shí)例

DecimalField

小數(shù)字段DecimalField(max_digits=5, decimal_places=2),max_digits定義小數(shù)總長(zhǎng)度,decimal_places`定義小數(shù)位數(shù)

其它字段

BigAutoField(AutoField)
        - bigint自增列,必須填入?yún)?shù) primary_key=True

        注:當(dāng)model中如果沒(méi)有自增列,則自動(dòng)會(huì)創(chuàng)建一個(gè)列名為id的列
        from django.db import models

        class 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 ~ 32767

    PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正小整數(shù) 0 ~ 32767
 PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
        - 正整數(shù) 0 ~ 2147483647

    BigIntegerField(IntegerField):
        - 長(zhǎng)整型(有符號(hào)的) -9223372036854775808 ~ 9223372036854775807

    BooleanField(Field)
        - 布爾值類型

    NullBooleanField(Field):
        - 可以為空的布爾值
  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,開(kāi)啟此功能,需要protocol="both"

    URLField(CharField)
        - 字符串類型,Django Admin以及ModelForm中提供驗(yàn)證 URL

    SlugField(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ù)庫(kù),文件上傳到指定目錄
        - 參數(shù):
            upload_to = ""      上傳文件的保存路徑
            storage = None      存儲(chǔ)組件,默認(rèn)django.core.files.storage.FileSystemStorage

    ImageField(FileField)
        - 字符串,路徑保存在數(shù)據(jù)庫(kù),文件上傳到指定目錄
        - 參數(shù):
            upload_to = ""      上傳文件的保存路徑
            storage = None      存儲(chǔ)組件,默認(rèn)django.core.files.storage.FileSystemStorage
            width_field=None,   上傳圖片的高度保存的數(shù)據(jù)庫(kù)字段名(字符串)
            height_field=None   上傳圖片的寬度保存的數(shù)據(jù)庫(kù)字段名(字符串)
 TimeField(DateTimeCheckMixin, Field)
        - 時(shí)間格式      HH:MM[:ss[.uuuuuu]]

    DurationField(Field)
        - 長(zhǎng)整數(shù),時(shí)間間隔,數(shù)據(jù)庫(kù)中按照bigint存儲(chǔ),ORM中獲取的值為datetime.timedelta類型

    FloatField(Field)
        - 浮點(diǎn)型

    DecimalField(Field)
        - 10進(jìn)制小數(shù)
        - 參數(shù):
            max_digits,小數(shù)總長(zhǎng)度
            decimal_places,小數(shù)位長(zhǎng)度

    BinaryField(Field)
        - 二進(jìn)制類型

自定義字段

class UnsignedIntegerField(models.IntegerField):
    def db_type(self, connection):
        return 'integer UNSIGNED'

自定義char類型字段:

class FixedCharField(models.Field):
    """
    自定義的char類型的字段類
    """
    def __init__(self, max_length, *args, **kwargs):
        super().__init__(max_length=max_length, *args, **kwargs)
        self.length = max_length

    def db_type(self, connection):
        """
        限定生成數(shù)據(jù)庫(kù)表的字段類型為char,長(zhǎng)度為length指定的值
        """
        return 'char(%s)' % self.length


class Class(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=25)
    # 使用上面自定義的char類型的字段
    cname = FixedCharField(max_length=25)

常用的字段參數(shù)

null 數(shù)據(jù)庫(kù)中字段是否可以為空
db_column 數(shù)據(jù)庫(kù)中字段的列名
default 數(shù)據(jù)庫(kù)中字段的默認(rèn)值
primary_key 數(shù)據(jù)庫(kù)中字段是否為主鍵
db_index 數(shù)據(jù)庫(kù)中字段是否可以建立索引
unique 數(shù)據(jù)庫(kù)中字段是否可以建立唯一索引
unique_for_date 數(shù)據(jù)庫(kù)中字段【日期】部分是否可以建立唯一索引
unique_for_month 數(shù)據(jù)庫(kù)中字段【月】部分是否可以建立唯一索引
unique_for_year 數(shù)據(jù)庫(kù)中字段【年】部分是否可以建立唯一索引

DatetimeField和Datefield獨(dú)有:

auto_now_add --> 當(dāng)前數(shù)據(jù)的創(chuàng)建時(shí)間
auto_now --> 當(dāng)前數(shù)據(jù)的最后修改時(shí)間

帶choice參數(shù)的字段

get_字段名_display()

建表的元信息

class Meta:
db_table = '表名'
unique_together = (('ip', 'port'),)
index_together = (("pub_date", "deadline"),)

必知必會(huì)13條

  1. 返回QuerySet列表類型的
    1. filter():篩選條件匹配的對(duì)象
    2. all():查詢所有的結(jié)果
    3. exclude():篩選出與條件不匹配的對(duì)象
    4. order_by():對(duì)查詢的結(jié)果排序
    5. reverse():對(duì)查詢的結(jié)果反向排序
    6. distinct():從返回結(jié)果中剔除重復(fù)紀(jì)錄(如果你查詢跨越多個(gè)表,可能在計(jì)算QuerySet時(shí)得到重復(fù)的結(jié)果。此時(shí)可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。)
    7. values(): 返回一個(gè)ValueQuerySet——一個(gè)特殊的QuerySet,運(yùn)行后得到的并不是一系列model的實(shí)例化對(duì)象,而是一個(gè)可迭代的字典序列
    8. values_list() :它與values()非常相似,它返回的是一個(gè)元組序列,values返回的是一個(gè)字典序列
    2. 返回具體對(duì)象
    1. get():返回與所給篩選條件相匹配的對(duì)象,返回結(jié)果有且只有一個(gè),如果符合篩選條件的對(duì)象超過(guò)一個(gè)或者沒(méi)有都會(huì)拋出錯(cuò)誤。
    2. first():返回第一條記錄
    3. last():返回最后一條記錄
    3. 返回布爾值
    1. exists():如果QuerySet包含數(shù)據(jù),就返回True,否則返回False
    4. 返回?cái)?shù)字的
    1. count():返回?cái)?shù)據(jù)庫(kù)中匹配查詢(QuerySet)的對(duì)象數(shù)量。

神奇的下劃線(單表查詢)

models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大于1 且 小于10的值
 
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
 
models.Tb1.objects.filter(name__contains="ven")  # 獲取name字段包含"ven"的
models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫(xiě)不敏感
 
models.Tb1.objects.filter(id__range=[1, 3])      # id范圍是1到3的,等價(jià)于SQL的bettwen and
 
類似的還有:startswith,istartswith, endswith, iendswith 

date字段還可以:
models.Class.objects.filter(first_day__year=2017)

ORM關(guān)聯(lián)查詢

基于對(duì)象的查詢

正向查詢

對(duì)象.關(guān)聯(lián)字段

反向查詢

1.默認(rèn)不設(shè)置related_name屬性
(1)查找的對(duì)象是多個(gè)的時(shí)候(一對(duì)多或者多對(duì)多)
publisher_obj.book_set.all()
(2)查找一個(gè)對(duì)象時(shí)(一對(duì)一)
author_info_obj.autjor.name
2.設(shè)置related_name=‘books’屬性
publisher_obj.books.all()

基于QuerySet的查詢

正向查詢

Book.objects.filter(id=1).values_list(‘publisher__name’)

反向查詢

1.默認(rèn)不設(shè)置related_name屬性,默認(rèn)就用類名的小寫(xiě)
Publisher.objects.filter(id=1).values_list(‘book__price’) 2.設(shè)置related_name屬性Publisher.objects.filter(id=1).values_list(‘books__price’)

聚合查詢和分組查詢

聚合

Django在django.db.models中提供了許多聚合函數(shù),aggregate()是Queryset的一個(gè)終止子句,意思是它返回一個(gè)包含鍵值對(duì)的字典不能使用values()和value_list()
聚合函數(shù):

from django.db.models import Avg,Sum,Max,Min,Count:

假如要求一個(gè)表中某個(gè)數(shù)值列的平均數(shù)

from django.db.models import Avg,Sum,Max,Min,Count:
表名.objects.all().aggregate(Avg('列名'))

也可以指定一個(gè)名字

表名.objects.all().aggregate(昵稱=Avg('列名'))

也可以使用多個(gè)聚合函數(shù)

表名.objects.all().aggregate(Avg('列名'),Max('列名'))

分組

假設(shè)現(xiàn)在有一張公司職員表:


image

我們使用原生SQL語(yǔ)句,按照部分分組求平均工資:

select dept,AVG(salary) from employee group by dept;

ORM查詢:

from django.db.models import Avg
Employee.objects.values("dept").annotate(avg=Avg("salary").values(dept, "avg")

連表查詢的分組:


image

SQL查詢:

select dept.name,AVG(salary) from employee inner join dept on (employee.dept_id=dept.id) group by dept_id;

ORM查詢:

from django.db.models import Avg
models.Dept.objects.annotate(avg=Avg("employee__salary")).values("name", "avg")

F查詢和 Q查詢

F查詢

當(dāng)我們需要進(jìn)行兩個(gè)字段的值作比較的時(shí)候我們使用F()來(lái)做比較.F() 的實(shí)例可以在查詢中引用字段,來(lái)比較同一個(gè) model 實(shí)例中兩個(gè)不同字段的值。
查詢?cè)u(píng)論數(shù)大于收藏?cái)?shù)的書(shū)籍

from django.db.models import F
models.Book.objects.filter(commnet_num__gt=F('keep_num'))

Django 支持 F() 對(duì)象之間以及 F() 對(duì)象和常數(shù)之間的加減乘除和取模的操作。

models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)

修改操作也可以使用F函數(shù),比如將每一本書(shū)的價(jià)格提高30元

models.Book.objects.all().update(price=F("price")+30)

如果要修改char字段咋辦?

如:把所有書(shū)名后面加上(第一版)

>>> from django.db.models.functions import Concat
>>> from django.db.models import Value
>>> models.Book.objects.all().update(title=Concat(F("title"), Value("("), Value("第一版"), Value(")")))

Q查詢

filter() 等方法中的關(guān)鍵字參數(shù)查詢都是一起進(jìn)行“AND” 的。 如果你需要執(zhí)行更復(fù)雜的查詢(例如OR語(yǔ)句),你可以使用Q對(duì)象。
你可以組合& 和| 操作符以及使用括號(hào)進(jìn)行分組來(lái)編寫(xiě)任意復(fù)雜的Q 對(duì)象。同時(shí),Q 對(duì)象可以使用~ 操作符取反,這允許組合正常的查詢和取反(NOT) 查詢。
示例:查詢作者名字是小仙女并且不是2018年出版的書(shū)的書(shū)名

models.Book.objects.filter(Q(author__name="小仙女") & ~Q(publish_date__year=2018)).values_list("title")

查詢函數(shù)可以混合使用Q 對(duì)象和關(guān)鍵字參數(shù)。所有提供給查詢函數(shù)的參數(shù)(關(guān)鍵字參數(shù)或Q 對(duì)象)都將"AND”在一起。但是,如果出現(xiàn)Q 對(duì)象,它必須位于所有關(guān)鍵字參數(shù)的前面。

例如:查詢出版年份是2017或2018,書(shū)名中帶物語(yǔ)的所有書(shū)。

 models.Book.objects.filter(Q(publish_date__year=2018) | Q(publish_date__year=2017), title__icontains="物語(yǔ)")

在Django終端打印SQL語(yǔ)句

在Django項(xiàng)目的settings.py文件中,在最后復(fù)制粘貼如下代碼:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1 ORM常用操作 1.1 概念 對(duì)象關(guān)系映射(英語(yǔ):Object Relational Mapping,簡(jiǎn)稱OR...
    Spareribs閱讀 724評(píng)論 0 6
  • 關(guān)于Mongodb的全面總結(jié) MongoDB的內(nèi)部構(gòu)造《MongoDB The Definitive Guide》...
    中v中閱讀 32,302評(píng)論 2 89
  • 看@面相與命運(yùn)的微博已經(jīng)兩年了也買過(guò)一套入門面相書(shū)來(lái)看?!耙悦孀R(shí)人,以面識(shí)己”已經(jīng)成為了我習(xí)慣的一種思維方式。當(dāng)然...
    丁叮妹兒Nikki閱讀 2,510評(píng)論 3 7
  • 姓名:劉明正 公司:青州市華松塑業(yè)有限公司 【日精進(jìn)打卡第357天,始于20180420今天是20190421】。...
    LMZ_4d79閱讀 240評(píng)論 0 0
  • 身邊的歷史 | 家之脈 父親的勤勞,母親的努力,爺爺?shù)墓?jié)儉,是我們家?guī)状藗鞒胁粩嗟拿}。(四年級(jí) 唐子涵) 父親的...
    Fenny_官閱讀 230評(píng)論 0 4

友情鏈接更多精彩內(nèi)容