Python學習(三十四)—— Django之ORM之單表、聯表操做

1、單表查詢API彙總

<1> all():                 查詢全部結果
 
<2> filter(**kwargs):      它包含了與所給篩選條件相匹配的對象
 
<3> get(**kwargs):         返回與所給篩選條件相匹配的對象,返回結果有且只有一個,若是符合篩選條件的對象超過一個或者沒有都會拋出錯誤。
 
<4> exclude(**kwargs):     它包含了與所給篩選條件不匹配的對象
 
<5> values(*field):        返回一個ValueQuerySet——一個特殊的QuerySet,運行後獲得的並非一系列model的實例化對象,而是一個可迭代的字典序列
 
<6> values_list(*field):   它與values()很是類似,它返回的是一個元組序列,values返回的是一個字典序列
 
<7> order_by(*field):      對查詢結果排序
 
<8> reverse():             對查詢結果反向排序
 
<9> distinct():            從返回結果中剔除重複紀錄,配合values和values_list使用
 
<10> count():              返回數據庫中匹配查詢(QuerySet)的對象數量。
 
<11> first():              返回第一條記錄
 
<12> last():               返回最後一條記錄
 
<13> exists():             若是QuerySet包含數據,就返回True,不然返回False

注意:必定區分Object與QuerySet的區別 !!!數據庫

QuerySet有update方法而Object默認沒有。django

單表查詢之神奇的雙下劃線ide

models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 獲取id大於1 且 小於10的值
 
models.Tb1.objects.filter(id__in=[11, 22, 33])   # 獲取id等於十一、2二、33的數據
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大小寫不敏感
 
models.Tb1.objects.filter(id__range=[1, 3])      # id範圍是1到3的,等價於SQL的bettwen and
 
相似的還有:startswith,istartswith, endswith, iendswith 

date字段還能夠:
models.Class.objects.filter(first_day__year=2017)

備註:ui

在Django的日誌設置中,配置上一個名爲django.db.backends的logger實例便可查看翻譯後的SQL語句。spa

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

Django項目完整版LOGGING配置:翻譯

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
                      '[%(levelname)s][%(message)s]'
        },
        'simple': {
            'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
        },
        'collect': {
            'format': '%(message)s'
        }
    },
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'filters': ['require_debug_true'],  # 只有在Django debug爲True時纔在屏幕打印日誌
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'default': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自動切
            'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"),  # 日誌文件
            'maxBytes': 1024 * 1024 * 50,  # 日誌大小 50M
            'backupCount': 3,
            'formatter': 'standard',
            'encoding': 'utf-8',
        },
        'error': {
            'level': 'ERROR',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自動切
            'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"),  # 日誌文件
            'maxBytes': 1024 * 1024 * 50,  # 日誌大小 50M
            'backupCount': 5,
            'formatter': 'standard',
            'encoding': 'utf-8',
        },
        'collect': {
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自動切
            'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"),
            'maxBytes': 1024 * 1024 * 50,  # 日誌大小 50M
            'backupCount': 5,
            'formatter': 'collect',
            'encoding': "utf-8"
        }
    },
    'loggers': {
       # 默認的logger應用以下配置
        '': {
            'handlers': ['default', 'console', 'error'],  # 上線以後能夠把'console'移除
            'level': 'DEBUG',
            'propagate': True,
        },
        # 名爲 'collect'的logger還單獨處理
        'collect': {
            'handlers': ['console', 'collect'],
            'level': 'INFO',
        }
    },
}
Django項目經常使用LOGGING配置

 

2、基於對象的跨表查詢

一對多查詢(班級表和學生表)

正向查詢(由學生表查詢班級表)debug

查詢學生的班級信息設計

>>> student_obj = models.Student.objects.first()
>>> student_obj.cid  # 經過model類中的屬性查找到對應的外鍵數據對象
<Class: Class object>
>>> student_obj.cid.cname
'1班'
>>> student_obj.cid_id  # 獲取實際外鍵的值
1

反向查詢(由班級表查詢學生表)日誌

查詢班級的學生信息code

>>> class_obj = models.Class.objects.first()  # 獲取第一個班級對象
>>> class_obj.student_set.all()  # 經過表名_set反向查詢出全部的學生
<QuerySet [<Student: Student object>, <Student: Student object>]>

注意:

若是不在外鍵的字段中設置related_name的話,默認就用表名_set。

若是設置了related_name="students",反向查詢時可直接使用students進行反向查詢。

>>> class_obj.students.all() 

一對一查詢

表結構設計

class Student(models.Model):
    sname = models.CharField(max_length=32, verbose_name="學生姓名")
    the_class = models.ForeignKey(to=Class, to_field="id", on_delete=models.CASCADE, related_name="students")
    detail = models.OneToOneField(to="StudentDetail", null=True)


class StudentDetail(models.Model):
    height = models.PositiveIntegerField()
    weight = models.PositiveIntegerField()
    email = models.EmailField()

正向查詢(由學生信息表查詢學生詳情表)

>>> student_obj = models.Student.objects.first()
>>> student_obj.detail.email
'1@1.com'

反向查詢(由學生詳情表反向查詢學生信息表)

>>> detail_obj = models.StudentDetail.objects.get(id=1)
>>> detail_obj.student.sname
'a'

 

3、多對多關係

三種方式建立多對多外鍵方式及其優缺點

經過外鍵建立

class Class(models.Model):
    id = models.AutoField(primary_key=True)  # 主鍵
    cname = models.CharField(max_length=32)  # 班級名稱
    first_day = models.DateField()  # 開班時間


class Teacher(models.Model):
    tname = models.CharField(max_length=32)


# 自定義第三張表,經過外鍵關聯上面兩張表
class Teacher2Class(models.Model):
    teacher = models.ForeignKey(to="Teacher")
    the_class = models.ForeignKey(to="Class")

    class Meta:
        unique_together = ("teacher", "the_class")

經過ManyToManyField建立

class Class(models.Model):
    id = models.AutoField(primary_key=True)  # 主鍵
    cname = models.CharField(max_length=32)  # 班級名稱
    first_day = models.DateField()  # 開班時間


class Teacher(models.Model):
    tname = models.CharField(max_length=32)
    # 經過ManyToManyField自動建立第三張表
    cid = models.ManyToManyField(to="Class", related_name="teachers")

經過外鍵和ManyToManyField建立

class Class(models.Model):
    id = models.AutoField(primary_key=True)  # 主鍵
    cname = models.CharField(max_length=32)  # 班級名稱
    first_day = models.DateField()  # 開班時間


class Teacher(models.Model):
    tname = models.CharField(max_length=32)
    # 經過ManyToManyField和手動建立第三張表
    cid = models.ManyToManyField(to="Class", through="Teacher2Class", through_fields=("teacher", "the_class"))


class Teacher2Class(models.Model):
    teacher = models.ForeignKey(to="Teacher")
    the_class = models.ForeignKey(to="Class")

    class Meta:
        unique_together = ("teacher", "the_class")

 

4、多對多操做

正向查詢(由老師表查詢班級表)

>>> teacher_obj = models.Teacher.objects.first()
>>> teacher_obj.cid.all()  # 查詢該老師授課的全部班級
<QuerySet [<Class: Class object>, <Class: Class object>]>

反向查詢(由班級表反向查詢老師表)

>>> class_obj = models.Class.objects.first()
>>> class_obj.teachers.all()  # 此處用到的是related_name,若是不設置的話就用默認的表名_set
<QuerySet [<Teacher: Teacher object>, <Teacher: Teacher object>, <Teacher: Teacher object>]>

 

5、class RelatedManager

"關聯管理器"是在一對多或者多對多的關聯上下文中使用的管理器。

它存在於下面兩種狀況:

  1. 外鍵關係的反向查詢
  2. 多對多關聯關係

經常使用方法

create()

建立一個新的對象,保存對象,並將它添加到關聯對象集之中,返回新建立的對象。

>>> import datetime
>>> teacher_obj.cid.create(cname="9班", first_day=datetime.datetime.now())

建立一個新的班級對象,保存對象,並將它添加到關聯對象集之中。返回新建立的對象:

>>> class_obj = models.Class.objects.first()
>>> class_obj.student_set.create(sname="小明")

上面的寫法等價於下面的寫法,可是比下面的這種寫法更簡單。

>>> class_obj = models.Class.objects.first()
>>> models.Student.objects.create(sname="小明", cid=class_obj)

add()

把指定的model

對象添加到關聯對象集中。

添加對象

>>> class_objs = models.Class.objects.filter(id__lt=3)
>>> models.Teacher.objects.first().cid.add(*class_objs)

添加id

>>> models.Teacher.objects.first().cid.add(*[1, 2])

set()

更新model對象的關聯對象。

>>> teacher_obj = models.Teacher.objects.first()
>>> teacher_obj.cid.set([2, 3])

remove()

從關聯對象集中移除執行的model對象

>>> teacher_obj = models.Teacher.objects.first()
>>> teacher_obj.cid.remove(3)

對於ForeignKey對象,這個方法僅在null=True時存在。

clear()

從關聯對象集中移除一切對象。

>>> teacher_obj = models.Teacher.objects.first()
>>> teacher_obj.cid.clear()

同理,對於ForeignKey對象,這個方法僅在null=True時存在。

注意:

  1. 對於全部類型的關聯字段,add()、create()、remove()和clear(),set()都會立刻更新數據庫。換句話說,在關聯的任何一端,都不須要再調用save()方法。

了不得的雙下劃線

在這以前咱們全部的跨表查詢都是基於對象的查詢。

好比:

Django還提供了一種直觀而高效的方式在查詢中表示數據表之間的關聯關係,它能自動確認 SQL JOIN 關係。

須要作跨關係查詢時,就可使用兩個下劃線來連接模型(model)間關聯字段的名稱,直到最終連接到你想要的 model 爲止。

相關文章
相關標籤/搜索