真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Django_模型詳解

Django_模型ORM

Django中內(nèi)嵌了ORM框架,不需要直接編寫(xiě)SQL語(yǔ)句進(jìn)行數(shù)據(jù)庫(kù)操作,而是通過(guò)定義模型類,操作模型類來(lái)完成對(duì)數(shù)據(jù)庫(kù)中表的增刪改查和創(chuàng)建等操作。

在天水等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì) 網(wǎng)站設(shè)計(jì)制作按需求定制設(shè)計(jì),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計(jì),營(yíng)銷型網(wǎng)站,成都外貿(mào)網(wǎng)站建設(shè)公司,天水網(wǎng)站建設(shè)費(fèi)用合理。

O是object,也就類對(duì)象的意思。

R是relation,翻譯成中文是關(guān)系,也就是關(guān)系數(shù)據(jù)庫(kù)中數(shù)據(jù)表的意思。

M是mapping,是映射的意思。

映射:

類:sql語(yǔ)句table表

類成員變量:table表中的字段、類型和約束

類對(duì)象:sql表的表記錄

ORM的優(yōu)點(diǎn)

  • 數(shù)據(jù)模型類都在一個(gè)地方定義,更容易更新和維護(hù),也利于重用代碼。

  • ORM 有現(xiàn)成的工具,很多功能都可以自動(dòng)完成,比如數(shù)據(jù)消除、預(yù)處理、事務(wù)等等。

  • 它迫使你使用 MVC 架構(gòu),ORM 就是天然的 Model,最終使代碼更清晰。

  • 基于 ORM 的業(yè)務(wù)代碼比較簡(jiǎn)單,代碼量少,語(yǔ)義性好,容易理解。

  • 新手對(duì)于復(fù)雜業(yè)務(wù)容易寫(xiě)出性能不佳的 SQL,有了ORM不必編寫(xiě)復(fù)雜的SQL語(yǔ)句, 只需要通過(guò)操作模型對(duì)象即可同步修改數(shù)據(jù)表中的數(shù)據(jù).

  • 開(kāi)發(fā)中應(yīng)用ORM將來(lái)如果要切換數(shù)據(jù)庫(kù).只需要切換ORM底層對(duì)接數(shù)據(jù)庫(kù)的驅(qū)動(dòng)【修改配置文件的連接地址即可】

ORM 也有缺點(diǎn)

  • ORM 庫(kù)不是輕量級(jí)工具,需要花很多精力學(xué)習(xí)和設(shè)置,甚至不同的框架,會(huì)存在不同操作的ORM。
  • 對(duì)于復(fù)雜的業(yè)務(wù)查詢,ORM表達(dá)起來(lái)比原生的SQL要更加困難和復(fù)雜。
  • ORM操作數(shù)據(jù)庫(kù)的性能要比使用原生的SQL差。
  • ORM 抽象掉了數(shù)據(jù)庫(kù)層,開(kāi)發(fā)者無(wú)法了解底層的數(shù)據(jù)庫(kù)操作,也無(wú)法定制一些特殊的 SQL?!咀约菏褂胮ymysql另外操作即可,用了ORM并不表示當(dāng)前項(xiàng)目不能使用別的數(shù)據(jù)庫(kù)操作工具了?!?/li>

我們可以通過(guò)以下步驟來(lái)使用django的數(shù)據(jù)庫(kù)操作

1. 配置數(shù)據(jù)庫(kù)連接信息
2. 在models.py中定義模型類
3. 生成數(shù)據(jù)庫(kù)遷移文件并執(zhí)行遷文件[注意:數(shù)據(jù)遷移是一個(gè)獨(dú)立的功能,這個(gè)功能在其他web框架未必和ORM一塊的]
4. 通過(guò)模型類對(duì)象提供的方法或?qū)傩酝瓿蓴?shù)據(jù)表的增刪改查操作

配置數(shù)據(jù)庫(kù)信息

在settings.py中保存了數(shù)據(jù)庫(kù)的連接配置信息,Django默認(rèn)初始配置使用sqlite數(shù)據(jù)庫(kù)。

  1. 使用MySQL數(shù)據(jù)庫(kù)首先需要安裝驅(qū)動(dòng)程序

    pip install PyMySQL
    
  2. 在Django的工程同名子目錄的__init__.py文件中添加如下語(yǔ)句

    from pymysql import install_as_MySQLdb
    install_as_MySQLdb() # 讓pymysql以MySQLDB的運(yùn)行模式和Django的ORM對(duì)接運(yùn)行
    

    作用是讓Django的ORM能以mysqldb的方式來(lái)調(diào)用PyMySQL。

  3. 修改database里面的信息

    原本在setting中默認(rèn)的是sqlite3版本的數(shù)據(jù)庫(kù)引擎,

    現(xiàn)在將其改為mysql數(shù)據(jù)庫(kù)的信息

    DATABASES = {
        "default" : {
            'ENGINE':'django.db.backends.mysql',
            'HOST': '127.0.0.1',  # 數(shù)據(jù)庫(kù)主機(jī)
            'PORT': 3306,  # 數(shù)據(jù)庫(kù)端口
            'USER': 'root',  # 數(shù)據(jù)庫(kù)用戶名
            'PASSWORD': '',  # 數(shù)據(jù)庫(kù)用戶密碼
            'NAME': 'student'  # 數(shù)據(jù)庫(kù)名字
        }
    }
    
  4. 在mysql中創(chuàng)建數(shù)據(jù)庫(kù)

    mysql> create database student default charset=utf8mb4;
    Query OK, 1 row affected (0.00 sec)
    

如果想打印orm轉(zhuǎn)換過(guò)程中的sql,需要在settings中進(jìn)行如下配置:


LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

定義模型類

定義模型類

  • 模型類被定義在"子應(yīng)用/models.py"文件中。
  • 模型類必須直接或者間接繼承自django.db.models.Model類。

class Information(models.Model):

    choices =(
        (0,"單身"),
        (1,"有對(duì)象"),
        (2,"已婚")
    )

    name = models.CharField(max_length=20, db_index=True, verbose_name="姓名")
    age = models.SmallIntegerField(verbose_name="年齡")
    is_married = models.SmallIntegerField(choices=choices, default=0)
    profess = models.CharField(db_column="faculty", max_length=5, db_index=True,verbose_name="專業(yè)")
    description = models.TextField(default="", verbose_name="個(gè)性簽名")

    class Meta:
        db_table = 'Regina_information'

(1) 數(shù)據(jù)庫(kù)表名

模型類如果未指明表名db_table,Django默認(rèn)以 小寫(xiě)app應(yīng)用名_小寫(xiě)模型類名 為數(shù)據(jù)庫(kù)表名。

可通過(guò)db_table 指明數(shù)據(jù)庫(kù)表名。

(2) 關(guān)于主鍵

django會(huì)為表創(chuàng)建自動(dòng)增長(zhǎng)的主鍵列,每個(gè)模型只能有一個(gè)主鍵列。

如果使用選項(xiàng)設(shè)置某個(gè)字段的約束屬性為主鍵列(primary_key)后,django不會(huì)再創(chuàng)建自動(dòng)增長(zhǎng)的主鍵列。

class Student(models.Model):
    # django會(huì)自動(dòng)在創(chuàng)建數(shù)據(jù)表的時(shí)候生成id主鍵/還設(shè)置了一個(gè)調(diào)用別名 pk
    id = models.AutoField(primary_key=True, null=False, verbose_name="主鍵") # 設(shè)置主鍵

默認(rèn)創(chuàng)建的主鍵列屬性為id,可以使用pk代替,pk全拼為primary key。

(3) 屬性命名限制

  • 不能是python的保留關(guān)鍵字。

  • 不允許使用連續(xù)的2個(gè)下劃線,這是由django的查詢方式?jīng)Q定的。__ 是關(guān)鍵字來(lái)的,不能使用!??!

  • 定義屬性時(shí)需要指定字段類型,通過(guò)字段類型的參數(shù)指定選項(xiàng),語(yǔ)法如下:

    屬性名 = models.字段類型(約束選項(xiàng), verbose_name="注釋")
    

(4)字段類型

類型 說(shuō)明
AutoField 自動(dòng)增長(zhǎng)的IntegerField,通常不用指定,不指定時(shí)Django會(huì)自動(dòng)創(chuàng)建屬性名為id的自動(dòng)增長(zhǎng)屬性
BooleanField 布爾字段,值為True或False
NullBooleanField 支持Null、True、False三種值
CharField 字符串,參數(shù)max_length表示最大字符個(gè)數(shù),對(duì)應(yīng)mysql中的varchar
TextField 大文本字段,一般大段文本(超過(guò)4000個(gè)字符)才使用。
IntegerField 整數(shù)
DecimalField 十進(jìn)制浮點(diǎn)數(shù), 參數(shù)max_digits表示總位數(shù), 參數(shù)decimal_places表示小數(shù)位數(shù),常用于表示分?jǐn)?shù)和價(jià)格 Decimal(max_digits=7, decimal_places=2) ==> .99~ 0.00
FloatField 浮點(diǎn)數(shù)
DateField 日期
參數(shù)auto_now表示每次保存對(duì)象時(shí),自動(dòng)設(shè)置該字段為當(dāng)前時(shí)間。
參數(shù)auto_now_add表示當(dāng)對(duì)象第一次被創(chuàng)建時(shí)自動(dòng)設(shè)置當(dāng)前。
參數(shù)auto_now_add和auto_now是相互排斥的,一起使用會(huì)發(fā)生錯(cuò)誤。
TimeField 時(shí)間,參數(shù)同DateField
DateTimeField 日期時(shí)間,參數(shù)同DateField
FileField 上傳文件字段,django在文件字段中內(nèi)置了文件上傳保存類, django可以通過(guò)模型的字段存儲(chǔ)自動(dòng)保存上傳文件, 但是, 在數(shù)據(jù)庫(kù)中本質(zhì)上保存的僅僅是文件在項(xiàng)目中的存儲(chǔ)路徑!!
ImageField 繼承于FileField,對(duì)上傳的內(nèi)容進(jìn)行校驗(yàn),確保是有效的圖片

(5)約束選項(xiàng)

選項(xiàng) 說(shuō)明
null 如果為True,表示允許為空,默認(rèn)值是False。相當(dāng)于python的None
blank 如果為True,則該字段允許為空白,默認(rèn)值是False。 相當(dāng)于python的空字符串,“”
db_column 字段的名稱,如果未指定,則使用屬性的名稱。
db_index 若值為True, 則在表中會(huì)為此字段創(chuàng)建索引,默認(rèn)值是False。 相當(dāng)于SQL語(yǔ)句中的key
default 默認(rèn)值,當(dāng)不填寫(xiě)數(shù)據(jù)時(shí),使用該選項(xiàng)的值作為數(shù)據(jù)的默認(rèn)值。
primary_key 如果為True,則該字段會(huì)成為模型的主鍵,默認(rèn)值是False,一般不用設(shè)置,系統(tǒng)默認(rèn)設(shè)置。
unique 如果為True,則該字段在表中必須有唯一值,默認(rèn)值是False。相當(dāng)于SQL語(yǔ)句中的unique

(6) 外鍵

在設(shè)置外鍵時(shí),需要通過(guò)on_delete選項(xiàng)指明主表刪除數(shù)據(jù)時(shí),對(duì)于外鍵引用表數(shù)據(jù)如何處理,在django.db.models中包含了可選常量:

  • CASCADE 級(jí)聯(lián),刪除主表數(shù)據(jù)時(shí)連通一起刪除外鍵表中數(shù)據(jù)

  • PROTECT 保護(hù),通過(guò)拋出ProtectedError異常,來(lái)阻止刪除主表中被外鍵應(yīng)用的數(shù)據(jù)

  • SET_NULL 設(shè)置為NULL,僅在該字段null=True允許為null時(shí)可用

  • SET_DEFAULT 設(shè)置為默認(rèn)值,僅在該字段設(shè)置了默認(rèn)值時(shí)可用

  • SET() 設(shè)置為特定值或者調(diào)用特定方法,例如:

    from django.conf import settings
    from django.contrib.auth import get_user_model
    from django.db import models
    
    def get_sentinel_user():
        return get_user_model().objects.get_or_create(username='deleted')[0]
    
    class UserModel(models.Model):
        user = models.ForeignKey(
            settings.AUTH_USER_MODEL,
            on_delete=models.SET(get_sentinel_user),
        )
    
  • DO_NOTHING 不做任何操作,如果數(shù)據(jù)庫(kù)前置指明級(jí)聯(lián)性,此選項(xiàng)會(huì)拋出IntegrityError異常

數(shù)據(jù)遷移

將模型類定義表架構(gòu)的代碼轉(zhuǎn)換成SQL同步到數(shù)據(jù)庫(kù)中,這個(gè)過(guò)程就是數(shù)據(jù)遷移。django中的數(shù)據(jù)遷移,就是一個(gè)類,這個(gè)類提供了一系列的終端命令,幫我們完成數(shù)據(jù)遷移的工作。

(1)生成遷移文件

所謂的遷移文件, 是類似模型類的遷移類,主要是描述了數(shù)據(jù)表結(jié)構(gòu)的類文件.

python manage.py makemigrations

在app目錄下有一個(gè)migrations的文件夾,運(yùn)行這個(gè)命令之后,可能會(huì)發(fā)生報(bào)錯(cuò)

這是因?yàn)樵趕etting文件中沒(méi)有添加這個(gè)子應(yīng)用的配置信息,需要手動(dòng)補(bǔ)上

這樣的話,數(shù)據(jù)遷移就算成功了,同時(shí)migrations文件夾下會(huì)新生成一個(gè)文件0001_initial.py,但注意此時(shí)的數(shù)據(jù)庫(kù)是沒(méi)有參加這個(gè)操作的,所以里面還是空的

# Generated by Django 3.2 on 2022-09-15 11:59

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Information',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(db_index=True, max_length=20, verbose_name='姓名')),
                ('age', models.SmallIntegerField(verbose_name='年齡')),
                ('is_married', models.SmallIntegerField(choices=[(0, '單身'), (1, '有對(duì)象'), (2, '已婚')], default=0)),
                ('profess', models.CharField(db_column='faculty', db_index=True, max_length=5, verbose_name='專業(yè)')),
                ('description', models.TextField(default='', verbose_name='個(gè)性簽名')),
            ],
            options={
                'db_table': 'Regina_information',
            },
        ),
    ]

(2)同步到數(shù)據(jù)庫(kù)中

python manage.py migrate

這個(gè)主鍵就是自動(dòng)生成的,其他的和我們最開(kāi)始定義的一樣。

補(bǔ)充:在django內(nèi)部提供了一系列的功能,這些功能也會(huì)使用到數(shù)據(jù)庫(kù),所以在項(xiàng)目搭建以后第一次數(shù)據(jù)遷移的時(shí)候,會(huì)看到django項(xiàng)目中其他的數(shù)據(jù)表被創(chuàng)建了,但除了Regina_information,其他的并不重要。

在建立好數(shù)據(jù)之后,如果我們對(duì)數(shù)據(jù)庫(kù)結(jié)構(gòu)有想法,比如將原有對(duì)faculty那一列刪掉,再加上一個(gè)新的省份的表

 #profess = models.CharField(db_column="faculty", max_length=5, db_index=True,verbose_name="專業(yè)")
  province = models.CharField(max_length=20, verbose_name="籍貫")

然后我們?cè)偃ミ\(yùn)行前兩個(gè)命令

會(huì)發(fā)生這樣一個(gè)問(wèn)題:新的province列需要添加一個(gè)默認(rèn)值,這里還給出了兩個(gè)修改的方法,一個(gè)是直接在命令行里添加,一個(gè)是退出運(yùn)行在文件里添加

選擇1在命令行里添加好了之后提示數(shù)據(jù)遷移文件生成成功了

然后再遷移到數(shù)據(jù)庫(kù)里

(3)添加記錄

首先建立好路由,然后視圖函數(shù)需要添加一個(gè)Information的類對(duì)象

def add(request):

    stu = Information("ivanlee",23,1,"nothing","shanxi")
    stu.save()

    return HttpResponse("success")

本身id值是自動(dòng)產(chǎn)生的,但是如果類對(duì)象里不添加這個(gè)值,并且不寫(xiě)清楚具體對(duì)應(yīng)的參數(shù)名稱,就會(huì)造成找不到id值

所以要把參數(shù)寫(xiě)全

stu = Information(name="ivanlee", age=23,is_married = 1,description = "nothing",province = "shanxi")

此時(shí)再去數(shù)據(jù)庫(kù)查看

此時(shí)代碼中也可以進(jìn)行打印,說(shuō)明這些內(nèi)容數(shù)據(jù)可以進(jìn)行調(diào)用。

查詢數(shù)據(jù)

1. 基礎(chǔ)查詢

ORM中針對(duì)查詢結(jié)果的限制,提供了一個(gè)查詢集[QuerySet].這個(gè)QuerySet,是ORM中針對(duì)查詢結(jié)果進(jìn)行保存數(shù)據(jù)的一個(gè)類型,我們可以通過(guò)了解這個(gè)QuerySet進(jìn)行使用,達(dá)到查詢優(yōu)化,或者限制查詢結(jié)果數(shù)量的作用。

1)all()

查詢所有對(duì)象,返回queryset對(duì)象。查詢集,也稱查詢結(jié)果集、QuerySet,表示從數(shù)據(jù)庫(kù)中獲取的對(duì)象集合。

  # 1. all(): 返回一個(gè)queryset對(duì)象
    res = Test.objects.all()
    return HttpResponse(res)

此時(shí)返回了100個(gè)類對(duì)象,這種對(duì)象的名字叫做,此時(shí)看不到所有內(nèi)容和信息,所以在models文件里添加

    def __str__(self):
        return str(self.id)+": "+self.name + " "+str(self.age)+"\n"

這個(gè)內(nèi)容是自定義的,方便返回值

2) first()&&last()
stu1 = Test.objects.first()
print(stu1.name)
stu2 = Test.objects.last()
print(stu2.age)
3) filter()

這個(gè)函數(shù)等同于SQL語(yǔ)句中的where函數(shù),括號(hào)中添加條件

 stu = Test.objects.filter( id =12)
    print(stu)
    
>>>
(0.001) SELECT `db_student`.`id`, `db_student`.`name`, `db_student`.`sex`, `db_student`.`class`, `db_student`.`age`, `db_student`.`description`, `db_student`.`create_time`, `db_student`.`update_time` FROM `db_student` WHERE `db_student`.`id` = 12 LIMIT 21; args=(12,)

>]>

雖然這里只返回了一個(gè)數(shù)據(jù),但返回類型依然是queryset對(duì)象

這里過(guò)濾還有一個(gè)邏輯與的操作,不允許使用大于小于號(hào)或者邏輯或操作。例如

    stu = Test.objects.filter(id = 7, name="李藝帆")
    print(stu)
4) exclude()

這個(gè)方法與filter方法相反

stu = Test.objects.exclude( age = 20)

取到的值均為年齡不是20歲的信息

5)get()

返回與所給篩選條件相匹配的對(duì)象,返回結(jié)果有且只有一個(gè), 如果符合篩選條件的對(duì)象超過(guò)一個(gè)或者沒(méi)有都會(huì)拋出錯(cuò)誤。

student = Student.objects.get(pk=1)
print(student)
print(student.description)
get使用過(guò)程中的注意點(diǎn):get是根據(jù)條件返回多個(gè)結(jié)果或者沒(méi)有結(jié)果,都會(huì)報(bào)錯(cuò)
try:
    student = Student.objects.get(name="劉德華")
    print(student)
    print(student.description)
except Student.MultipleObjectsReturned:
    print("查詢得到多個(gè)結(jié)果!")
except Student.DoesNotExist:
    print("查詢結(jié)果不存在!")
6) order_by()

order_by("字段") # 按指定字段正序顯示,相當(dāng)于asc從小到大

stu = Test.objects.all()
return HttpResponse(stu.order_by("age"))

order_by("-字段") # 按字段倒序排列,相當(dāng)于 desc 從大到小

stu = Test.objects.all()
return HttpResponse(stu.order_by("-id"))

order_by("第一排序","第二排序",...)

stu = Test.objects.all()
return HttpResponse(stu.order_by("id","-clas"))
7)count()

查詢集中對(duì)象的個(gè)數(shù),返回一個(gè)個(gè)數(shù)

count = Student.objects.filter(sex=1).count()
print(count)
8)exists()

判斷查詢集中是否有數(shù)據(jù),如果有則返回True,沒(méi)有則返回False

# 查詢Student表中是否存在學(xué)生
print(Student.objects.exists())
9)values()、values_list()
  • value()把結(jié)果集中的模型對(duì)象轉(zhuǎn)換成字典,并可以設(shè)置轉(zhuǎn)換的字段列表,達(dá)到減少內(nèi)存損耗,提高性能

  • values_list(): 把結(jié)果集中的模型對(duì)象轉(zhuǎn)換成列表,并可以設(shè)置轉(zhuǎn)換的字段列表(元祖),達(dá)到減少內(nèi)存損耗,提高性能

# values 把查詢結(jié)果中模型對(duì)象轉(zhuǎn)換成字典
stu = Test.objects.filter(age = 23)
print(stu.values())
print(stu.values("name","clas"))

這里返回的全部都是queryset集合,但是得到這個(gè)字典集合就可以進(jìn)行序列化

print(json.dumps(list(stu.values("name","clas")),ensure_ascii=False))
stu = Test.objects.filter(age = 23)
print(stu.values_list("name","clas"))
10) distinct()

如果查詢到的數(shù)據(jù)里有重復(fù)的值,使用這個(gè)方法可以進(jìn)行去重,最簡(jiǎn)單的來(lái)說(shuō),我們用1和2來(lái)區(qū)分性別,一共100條信息,那么就會(huì)有100個(gè)數(shù)據(jù),運(yùn)用去重就得到了兩個(gè)值

 stu = Test.objects.values("sex")
  print(stu)
  print(stu.distinct())

2. 模糊查詢

在基礎(chǔ)查詢中,我們只能使用age = 23或者id = 7這種全等匹配,導(dǎo)致我們無(wú)法去條件查詢獲取更多的數(shù)據(jù)。模糊查詢就可以彌補(bǔ)這一點(diǎn)

1)包含

說(shuō)明:如果要包含%無(wú)需轉(zhuǎn)義,直接寫(xiě)即可。這個(gè)和SQL語(yǔ)句中的like關(guān)鍵字功能一致

使用filter方法完成這一功能

    stu = Test.objects.filter(name__startswith = "張")
    stu = Test.objects.filter(name__endswith="帆")
    stu = Test.objects.filter(name__contains = "嘉")
WHERE `db_student`.`name` LIKE BINARY '張%' LIMIT 21; args=('張%',)
WHERE `db_student`.`name` LIKE BINARY '%帆' LIMIT 21; args=('%帆',)
WHERE `db_student`.`name` LIKE BINARY '%嘉%' LIMIT 21; args=('%嘉%',)
2)isnull()

判斷所選項(xiàng)是否為空

stu = Test.objects.filter(description__isnull = False)
3) 比較查詢
  • gt 大于 (greater then)
  • gte 大于等于 (greater then equal)
  • lt 小于 (less then)
  • lte 小于等于 (less then equal)
stu = Test.objects.filter(id__gte = 7, id__lte = 12)
stu = Test.objects.filter(age__gt = 22).order_by("id")

上述的區(qū)域查詢也可以通過(guò)另一個(gè)參數(shù)range完成

stu = Test.objects.filter(id__range = (7,12))  #這里都是閉區(qū)間
4)in()

表示一個(gè)或的關(guān)系,滿足一個(gè)就會(huì)獲取

stu = Test.objects.filter(id__in = [7,12])
5) 日期
stu = Test.objects.filter(create_time__year = 2020)
stu = Test.objects.filter(create_time__month = 11)

3. 高階查詢

1) F查詢

之前的查詢都是對(duì)象的屬性與常量值比較,兩個(gè)屬性怎么比較呢? 答:使用F對(duì)象,被定義在django.db.models中。

查詢登記時(shí)間和更新時(shí)間不同的數(shù)據(jù)
stu = Test.objects.exclude(create_time = F("update_time"))

發(fā)現(xiàn)這兩個(gè)數(shù)據(jù)不一樣

2)Q查詢

多個(gè)過(guò)濾器逐個(gè)調(diào)用表示邏輯與關(guān)系,同sql語(yǔ)句中where部分的and關(guān)鍵字。

與:&

或:|

非:~

stu = Test.objects.filter(Q(id__gt = 10) | Q(age__gt = 20))  年齡大于20或者序號(hào)大于10
stu = Test.objects.filter(~Q(id__gt = 10) )  序號(hào)不大于10
3)聚合查詢

使用aggregate()過(guò)濾器調(diào)用聚合函數(shù)。聚合函數(shù)包括:Avg 平均,Count 數(shù)量,Max 最大,Min 最小,Sum 求和,被定義在django.db.models中。

res = Test.objects.aggregate(Avg("age"))
>>>{'age__avg': 20.47}
原生SQL語(yǔ)句為:SELECT AVG(`db_student`.`age`) AS `age__avg` FROM `db_student`; args=();

如果我們想按照自己的需求來(lái)起名,也可以修改為:

res = Test.objects.aggregate(DIY_avg = Avg("age"))

查看最大的年齡和最小年齡

stu = Test.objects.aggregate(MAxage = Max("age"))
    stu = Test.objects.aggregate(minage=Min("age"))
4) 分組查詢
QuerySet對(duì)象.annotate()
# annotate() 進(jìn)行分組統(tǒng)計(jì),按前面select 的字段進(jìn)行 group by
# annotate() 返回值依然是 queryset對(duì)象,增加了分組統(tǒng)計(jì)后的鍵值對(duì)
模型對(duì)象.objects.values("id").annotate(course=Count('course__sid')).values('id','course')
# 查詢指定模型, 按id分組 , 將course下的sid字段計(jì)數(shù),返回結(jié)果是 name字段 和 course計(jì)數(shù)結(jié)果 

# SQL原生語(yǔ)句中分組之后可以使用having過(guò)濾,在django中并沒(méi)有提供having對(duì)應(yīng)的方法,但是可以使用filter對(duì)分組結(jié)果進(jìn)行過(guò)濾
# 所以filter在annotate之前,表示where,在annotate之后代表having
# 同理,values在annotate之前,代表分組的字段,在annotate之后代表數(shù)據(jù)查詢結(jié)果返回的字段
stu = Test.objects.values("sex").annotate(avg_age = Avg("age")) 
5)原生SQl

執(zhí)行原生SQL語(yǔ)句,也可以直接跳過(guò)模型,才通用原生pymysql.

 ret = Student.objects.raw("SELECT id,name,age FROM db_student")  # student 可以是任意一個(gè)模型
 # 這樣執(zhí)行獲取的結(jié)果無(wú)法通過(guò)QuerySet進(jìn)行操作讀取,只能循環(huán)提取
stu = Test.objects.raw("select id,name,class from db_student where id > 6 and id < 13")
    print(stu)
    for item in stu:
        print(item,type(item))

4. 修改記錄

# 1.基于模型類對(duì)象操作save
    stu = Test.objects.get(id = 12)
    print(stu.name, stu.age)
    stu.age = 22
    stu.save()

這種方法確實(shí)可以達(dá)到效果,但是根據(jù)sql語(yǔ)句來(lái)看,他會(huì)更新所有的數(shù)據(jù),這樣會(huì)導(dǎo)致效率很慢

UPDATE `db_student` SET `name` = '張嘉睿', `sex` = 1, `class` = 503, `age` = 22, `description` = '春去秋來(lái),又一年。What did you get ?', `create_time` = '2020-11-20 10:00:00', `update_time` = '2020-12-20 10:00:00' WHERE `db_student`.`id` = 12; args=('張嘉睿', 1, 503, 22, '春去秋來(lái),又一年。What did you get ?', '2020-11-20 10:00:00', '2020-12-20 10:00:00', 12); alias=default
# 2.queryset的update方法
Test.objects.filter(id = 7).update(age = 22, description = "我愛(ài)張嘉睿")
UPDATE `db_student` SET `age` = 22, `description` = '我愛(ài)張嘉睿' WHERE `db_student`.`id` = 7; args=(22, '我愛(ài)張嘉睿', 7); alias=default

這樣sql語(yǔ)句的效率會(huì)很高

現(xiàn)在如果將選中的所有的人的年齡都家三歲,并且修改掉個(gè)性簽名,這里就用到之前所說(shuō)的F函數(shù)和Q函數(shù)

Test.objects.filter(~Q(id = 7) & ~Q(id = 12)).update(age = F('age')+3, description = "張嘉睿嫁給李藝帆")

5. 刪除記錄

# 1. 基于模型類刪除
Test.objects.get(pk = 100).delete()
# 2. 基于queryset刪除
Test.objects.filter(id = 99).delete()

創(chuàng)建關(guān)聯(lián)模型

先創(chuàng)建好幾張表

from django.db import models

# Create your models here.

class Clas(models.Model):
    name = models.CharField(max_length=32, verbose_name="班級(jí)名稱")

class Course(models.Model):
    title = models.CharField(max_length=32, verbose_name="班級(jí)名稱")

class Student(models.Model):

    sex_choices = (
        (0, "女"),
        (1, "男"),
        (2, "保密"),
    )
    name = models.CharField(max_length=32, unique=True, verbose_name="姓名")
    age = models.SmallIntegerField(verbose_name="年齡", default=18)  # 年齡
    sex = models.SmallIntegerField(choices=sex_choices)
    birthday = models.DateField()

    #建立一對(duì)多的關(guān)系: 在數(shù)據(jù)庫(kù)中自動(dòng)創(chuàng)建一個(gè)clas_id字段
    clas = models.ForeignKey(to="Clas", on_delete=models.CASCADE, db_constraint=False)

    #多對(duì)多的關(guān)系:
    stu_course = models.ManyToManyField("Course",db_table="DIY_stu_course")

    #一對(duì)一關(guān)系: 建立關(guān)聯(lián)字段
    stu_detail = models.OneToOneField("StudentDetail", on_delete=models.CASCADE)


class StudentDetail(models.Model):
    tel = models.CharField(max_length=11)
    email = models.CharField(max_length=20)

一定記得要在setting文件同目錄下的init文件里添加字段,不然就會(huì)報(bào)錯(cuò)

由于多對(duì)多關(guān)系會(huì)建立一個(gè)新的表,所以一共有5張表,

mysql> desc DIY_stu_course;
+------------+------------+------+-----+---------+----------------+
| Field      | Type       | Null | Key | Default | Extra          |
+------------+------------+------+-----+---------+----------------+
| id         | bigint(20) | NO   | PRI | NULL    | auto_increment |
| student_id | bigint(20) | NO   | MUL | NULL    |                |
| course_id  | bigint(20) | NO   | MUL | NULL    |                |
+------------+------------+------+-----+---------+----------------+
mysql> desc regina_student;
+---------------+-------------+------+-----+---------+----------------+
| Field         | Type        | Null | Key | Default | Extra          |
+---------------+-------------+------+-----+---------+----------------+
| id            | bigint(20)  | NO   | PRI | NULL    | auto_increment |
| name          | varchar(32) | NO   | UNI | NULL    |                |
| age           | smallint(6) | NO   |     | NULL    |                |
| sex           | smallint(6) | NO   |     | NULL    |                |
| birthday      | date        | NO   |     | NULL    |                |
| clas_id       | bigint(20)  | NO   | MUL | NULL    |                |
| stu_detail_id | bigint(20)  | NO   | UNI | NULL    |                |
+---------------+-------------+------+-----+---------+----------------+

關(guān)聯(lián)添加

1)一對(duì)一和一對(duì)多

因?yàn)檎n程,班級(jí)都是獨(dú)立的數(shù)據(jù),所以可以簡(jiǎn)單手動(dòng)創(chuàng)建,但是學(xué)生表需要關(guān)聯(lián)添加

stu = Student.objects.create(name="regina",age=22,sex=0, birthday="2000-01-27", clas_id = 1, stu_detail_id=1)
    print(stu)
    print(stu.name)

    # stu.clas是一個(gè)模型類
    print(stu.clas)

    #所以想獲取學(xué)生的班級(jí)信息直接調(diào)用stu.clas
    print(stu.clas.name)
>>>
Student object (1)
regina
Clas object (1)
python127

2) 多對(duì)多關(guān)系

 # 多對(duì)多關(guān)聯(lián)記錄的增刪改查
stu = Student.objects.create(name="ivanlee",age=22,sex=1, birthday="1999-07-17", clas_id = 1, stu_detail_id=2)
c1 = Course.objects.get(title="basketball")
c2 = Course.objects.get(title="math")
stu.stu_course.add(c1,c2)

stu2 = Student.objects.get(name="regina")
c3 = Course.objects.get(title="valleyball")
stu2.stu_course.add(c2,c3)

因?yàn)閷W(xué)生與課程是多對(duì)多的關(guān)系,所以一個(gè)學(xué)生可以選擇多門課程,一個(gè)課程也可以被多名學(xué)生選中,因此c2可以被反復(fù)添加

多對(duì)多關(guān)系會(huì)單獨(dú)生成一張表,我給他起了名字叫做DIY_Stu_course

其實(shí)添加方式也可以通過(guò)添加課程id值直接添加,或者是通過(guò)列表傳參的方式

stu2.stu_course.add(4)
stu.stu_course.add(*[3,4])

刪除

刪除操作

stu = Student.objects.get(name="regina")
stu.stu_course.remove()

如果想要?jiǎng)h除某個(gè)同學(xué)的全部選課,可以使用clear函數(shù)

stu.stu_course.clear()

如果想要清空并且重新選新的課,可以直接使用set函數(shù),相當(dāng)于set = clear + add

stu.stu_course.set(1,2)

查找

想要查詢學(xué)生課程的名稱使用all函數(shù)

stu = Student.objects.get(name="regina")
course = stu.stu_course.all()
print(course)

all函數(shù)所對(duì)應(yīng)的sql語(yǔ)句為:

SELECT `regina_course`.`id`, `regina_course`.`title` FROM `regina_course` INNER JOIN `DIY_stu_course` ON (`regina_course`.`id` = `DIY_stu_course`.`course_id`) WHERE `DIY_stu_course`.`student_id` = 1 LIMIT 21; 

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

一對(duì)多

'''
    基于對(duì)象的關(guān)聯(lián)查詢(子查詢)
    '''
    # 查詢學(xué)生的課程名稱
    # 正向查詢:通過(guò)學(xué)生表的關(guān)聯(lián)屬性去查到關(guān)聯(lián)的表字段

    stu = Student.objects.get(name = "regina")
    print(stu.clas.name)

    # 反向查詢方法1:查看某個(gè)班的學(xué)生有哪些
    # 要依賴一個(gè)表名的小寫(xiě)和_set的組合,表示這是一個(gè)集合的形式
    class_ = Clas.objects.get(name = "python127")
    name_ = class_.student_set.all()
    print(name_)  #, ]

上述反向查詢使用的名字是系統(tǒng)默認(rèn)的命名方式,如果想要根據(jù)自己的要求寫(xiě)名字,需要修改models文件

最初就是在建立關(guān)系時(shí)使用的參數(shù)里沒(méi)有添加related_name字段,現(xiàn)在設(shè)置為自己定義的可以直接進(jìn)行查詢

class_ = Clas.objects.get(name = "python127")
name_ = class_.DIY_studetlist.all()

一對(duì)一

# 一對(duì)一的關(guān)聯(lián)查詢
    stu = Student.objects.get(name="regina")
    print(stu.stu_detail.email)

    email_ = StudentDetail.objects.get(tel=155)
    print(email_.student.name)

這里的反向查詢直接輸入小寫(xiě)的原表明即可,因?yàn)檫@是一對(duì)一關(guān)系,只會(huì)搜索到一個(gè)對(duì)象,但同樣可以使用related_name進(jìn)行改寫(xiě)

多對(duì)多

# 多對(duì)多的關(guān)聯(lián)查詢
    stu = Student.objects.get(name="regina")
    print(stu.stu_course.all())

    course_name = Course.objects.get(title="math")
    ret = course_name.student_set.all()
    print(ret)

多對(duì)多的方式基本上和一對(duì)多一樣

現(xiàn)在把數(shù)據(jù)庫(kù)改一下

stu_course = models.ManyToManyField("Course",related_name="DIY_studentcourse",db_table="DIY_stu_course")
ret = course_name.DIY_studentcourse.all()
    print(ret.values("name","age"))

join查詢

首先復(fù)習(xí)一下sql語(yǔ)句中的join用法

-- 查詢學(xué)生的姓名和所在班級(jí)的名稱

select regina_student.name, regina_clas.name from regina_student inner join regina_clas on regina_student.clas_id = regina_clas.id;

如果通過(guò)多對(duì)多關(guān)聯(lián)表進(jìn)行join

-- 查詢學(xué)生的姓名和選修的課程

select * from regina_student left join DIY_stu_course Dsc on regina_student.id = Dsc.student_id;

這里面并沒(méi)有出現(xiàn)課程的名稱,所以繼續(xù)連接另外一個(gè)表

select name, course_id, regina_course.title from regina_student left join DIY_stu_course on regina_student.id = DIY_stu_course.student_id inner join regina_course on regina_course.id = DIY_stu_course.course_id;

基于雙下劃線查詢

# 正向查詢
    ret1 = Student.objects.filter(age__gt=20).values("name" , "clas__name")
    print(ret1)
    # 反向查詢
    ret2 = Clas.objects.filter(DIY_studetlist__age__gt=20).values("DIY_studetlist__name","name")
    print(ret2)
    
    


多對(duì)多
stu = Student.objects.filter(name = "regina").values("name","stu_course__title")
    print(stu)

#查詢選了數(shù)學(xué)的學(xué)生姓名
    cou = Course.objects.filter(title="math").values("DIY_studentcourse__name")

#查詢所有學(xué)生的姓名和手機(jī)號(hào)
    stu = Student.objects.filter().values("name", "stu_detail__tel")

這些都是有相關(guān)聯(lián)的表都查詢,如果兩個(gè)表之間沒(méi)有直接關(guān)系,就需要借助一個(gè)中間表進(jìn)行聯(lián)系

#查詢手機(jī)號(hào)為110的學(xué)生姓名以及班級(jí)名稱
    stu = StudentDetail.objects.filter(tel="155").values("student__name","student__clas__name")


-------或者---------
stu = Student.objects.filter(stu_detail__tel="155").values("name","clas__name")

以下就是如果碰到關(guān)聯(lián)查詢并且還需要分組:

-- 查詢每個(gè)班的人數(shù)
select regina_clas.name, count(*) as "人數(shù)" from regina_student inner join regina_clas on clas_id = regina_clas.id group by regina_clas.name;
select regina_clas.name, count(regina_student.name) as "人數(shù)" from regina_clas left join regina_student on clas_id = regina_clas.id group by regina_clas.name;

換成ORM模型里的語(yǔ)言:

num = Clas.objects.values("name").annotate(人數(shù) = Count("DIY_studetlist__name"))


# 查詢每一個(gè)學(xué)生的姓名和選的課程數(shù)目
    num = Student.objects.values("name").annotate(數(shù)目 = Count("stu_course__title"))
  

# 查詢每一個(gè)學(xué)生的姓名,年齡和選的課程數(shù)目
num = Student.objects.values("name","age").annotate(數(shù)目 = Count("stu_course__title"))
  ----優(yōu)化后-----
num = Student.objects.all().annotate(no = Count("stu_course__title")) #打印num并不會(huì)生成數(shù)量,但是回會(huì)有新的屬性值no
print(num.values("name","age","no"))
  

# 每一個(gè)課程名稱以及選修學(xué)生的個(gè)數(shù)
    num = Course.objects.all().annotate(人數(shù) = Count("DIY_studentcourse__name"))
    print(num.values("title","人數(shù)"))
    

# 查詢選修課程個(gè)數(shù)大于1的學(xué)生姓名和手機(jī)號(hào)和課程個(gè)數(shù) (sql中的having關(guān)鍵字)

    num = Student.objects.all().annotate(sum = Count("stu_course__title")).filter(sum__gt = 1)
    print(num.values("name","stu_detail__tel","sum"))
    
SELECT `regina_student`.`name`, `regina_studentdetail`.`tel`, COUNT(`regina_course`.`title`) AS `sum` FROM `regina_student` LEFT OUTER JOIN `DIY_stu_course` ON (`regina_student`.`id` = `DIY_stu_course`.`student_id`) LEFT OUTER JOIN `regina_course` ON (`DIY_stu_course`.`course_id` = `regina_course`.`id`) INNER JOIN `regina_studentdetail` ON (`regina_student`.`stu_detail_id` = `regina_studentdetail`.`id`) GROUP BY `regina_student`.`id`, `regina_studentdetail`.`tel` HAVING COUNT(`regina_course`.`title`) > 1 ORDER BY NULL LIMIT 21; args=(1,)


還可以根據(jù)數(shù)據(jù)進(jìn)行排序

# 查詢選修課程個(gè)數(shù)大于1的學(xué)生姓名和課程個(gè)數(shù),并按照課程數(shù)排序

    num = Student.objects.all().annotate(sum = Count("stu_course__title")).order_by("sum")
    print(num.values("name","sum"))
    

按照首字母排序也可以

num = Student.objects.all().annotate(sum = Count("stu_course__title")).order_by("name")
    print(num.values("name","sum"))
 
  

本文標(biāo)題:Django_模型詳解
轉(zhuǎn)載源于:http://weahome.cn/article/dsogsie.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部