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 为止。

相关文章
相关标签/搜索