python框架之Django(5)-O/RM

字段&参数

字段与db类型的对应关系

字段DB Type
AutoField integer AUTO_INCREMENT
BigAutoField bigint AUTO_INCREMENT
BinaryField longblob
BooleanField bool
CharField varchar
CommaSeparatedIntegerField varchar
DateField date
DateTimeField datetime
DecimalField numeric
DurationField bigint
FileField varchar
FilePathField varchar
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
SmallIntegerField smallint
TextField longtext
TimeField time
UUIDField char(32)

非关系字段

  • 内置字段

    字段说明
    AutoField int自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
    IntegerField 一个整数类型,范围在 -2147483648 to 2147483647。
    CharField 字符类型,必须提供max_length参数, max_length表示字符长度。
    DateField 日期字段,日期格式 YYYY-MM-DD,相当于Python中的datetime.date()实例。
    DateTimeField 日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例。
    BigAutoField bigint自增列,必须填入参数 primary_key=True。当model中如果没有自增列,则自动会创建一个列名为id的列。
    SmallIntegerField 小整数 -32768 ~ 32767
    PositiveSmallIntegerField 正小整数 0 ~ 32767
    PositiveIntegerField 正整数 0 ~ 2147483647
    BigIntegerField 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807
    BooleanField 布尔值类型
    NullBooleanField 可以为空的布尔值
    TextField 文本类型
    EmailField 字符串类型,Django Admin以及ModelForm中提供验证机制
    IPAddressField 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制
    GenericIPAddressField 字符串类型,Django Admin以及ModelForm中提供验证 Ipv4和Ipv6
    URLField 字符串类型,Django Admin以及ModelForm中提供验证 URL
    SlugField 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)
    CommaSeparatedIntegerField 字符串类型,格式必须为逗号分割的数字
    UUIDField 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证
    FilePathField 字符串,路径保存在数据库,文件上传到指定目录
    ImageField 字符串,路径保存在数据库,文件上传到指定目录
    TimeField 时间格式 HH:MM[:ss[.uuuuuu]]
    DurationField 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型
    FloatField 浮点型
    DecimalField 10进制小数
    BinaryField 二进制类型
  • 自定义字段

    此处示例为创建一个对应db中char类型的字段

    • 创建自定义类型
       1 class FixedCharField(models.Field):
       2     """
       3     自定义的char类型的字段类
       4     """
       5     def __init__(self, max_length, *args, **kwargs):
       6         self.max_length = max_length
       7         super(FixedCharField, self).__init__(max_length=max_length, *args, **kwargs)
       8 
       9     def db_type(self, connection):
      10         """
      11         限定生成数据库表的字段类型为char,长度为max_length指定的值
      12         """
      13         return 'char(%s)' % self.max_length
      Code
    • 使用
      1 class Class(models.Model):
      2     id = models.AutoField(primary_key=True)
      3     # 使用自定义的char类型的字段
      4     name= FixedCharField(max_length=25)
      Code
  • 字段参数

    参数说明可用字段
    null 用于表示某个字段可以为空。 all
    unique 如果设置为unique=True 则该字段在此表中必须是唯一的 。 all
    db_index 如果db_index=True 则代表着为此字段设置索引。 all
    default 为该字段设置默认值。 all
    auto_now_add 配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库 DateField和DateTimeField
    auto_now 配置上auto_now=True,每次更新数据记录的时候会更新该字段。 DateField和DateTimeField

关系字段

  • ForeignKey

    外键类型在ORM中用来表示外键关联关系,一般把ForeignKey字段设置在 '一对多'中'多'的一方。ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系。

    • to

      设置要关联的表

    • to_field

      设置要关联的表的字段

    • related_name

      反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。

       1 # 班级
       2 class Classes(models.Model):
       3     name = models.CharField(max_length=32)
       4 # 学生
       5 class Student(models.Model):
       6     name = models.CharField(max_length=32)
       7     theclass = models.ForeignKey(to="Classes")
       8 
       9 # 当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:
      10 models.Classes.objects.first().student_set.all()
      11 
      12 # 当我们在ForeignKey字段中添加了参数related_name后:
      13 class Student(models.Model):
      14     name = models.CharField(max_length=32)
      15     theclass = models.ForeignKey(to="Classes", related_name="students")
      16 
      17 # 当我们要查询某个班级关联的所有学生(反向查询)时,我们会这么写:
      18 models.Classes.objects.first().students.all()
      例:
    • related_query_name

      反向查询操作时,使用的连接前缀,用于替换表名。

    • on_delete

      当删除关联表中的数据时,当前表与其关联的行的行为。

      说明
      models.CASCADE 删除关联数据,与之关联也删除
      models.DO_NOTHING 删除关联数据,引发错误IntegrityError
      models.PROTECT 删除关联数据,引发错误ProtectedError
      models.SET_NULL 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空)
      models.SET_DEFAULT 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值)
      models.SET

      删除关联数据,

      a. 与之关联的值设置为指定值,设置:models.SET(值)。

      b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)。

       1 def func():
       2     return 10
       3 
       4 
       5 class MyModel(models.Model):
       6     user = models.ForeignKey(
       7         to="User",
       8         to_field="id" 9     on_delete = models.SET(func)
      10     )
      例:
    • db_constraint

      是否在数据库中创建外键约束,默认为True。

  • OneToOneField

    一对一字段。通常用来扩展已有字段。

    一对一的关联关系多用在当一张表的不同字段查询频次差距过大的情况下,将本可以存储在一张表的字段拆开放置在两张表中,然后将两张表建立一对一的关联关系。

    1 class Author(models.Model):
    2     name = models.CharField(max_length=32)
    3     info = models.OneToOneField(to='AuthorInfo')
    4     
    5 
    6 class AuthorInfo(models.Model):
    7     phone = models.CharField(max_length=11)
    8     email = models.EmailField()
    例:
    • to

      设置要关联的表。

    • to_field

      设置要关联的字段。

    • on_delete

      同ForeignKey字段。

  • ManyToManyField

    用于表示多对多的关联关系。在数据库中通过第三张表来建立关联关系。

    • to

      设置要关联的表。

    • related_name

      同ForeignKey字段。

    • related_query_name

      同ForeignKey字段。

    • symmetrical

      仅用于多对多自关联时,指定内部是否不创建反向操作的属性(表名_set)。默认为True(不创建)。

      1 class Person(models.Model):
      2     name = models.CharField(max_length=16)
      3     friends = models.ManyToManyField("self")
      4 # 此时,person对象就没有person_set属性。
      5 
      6 class Person(models.Model):
      7     name = models.CharField(max_length=16)
      8     friends = models.ManyToManyField("self", symmetrical=False)
      9 # 此时,person对象现在就可以使用person_set属性进行反向查询。
      例:
    • through

      在使用ManyToManyField字段时,Django将自动生成一张表来管理多对多的关联关系。但我们也可以手动创建第三张表来管理多对多关系,此时就需要通过through来指定第三张表的表名。

    • through_fields

      设置关联的字段。

    • db_table

      默认创建第三张表时,数据库中表的名称。

    • 创建多对多关系的三种方式
       1 class Book(models.Model):
       2     title = models.CharField(max_length=32, verbose_name="书名")
       3 
       4 
       5 class Author(models.Model):
       6     name = models.CharField(max_length=32, verbose_name="作者姓名")
       7 
       8 
       9 # 自己创建第三张表,分别通过外键关联书和作者
      10 class Author2Book(models.Model):
      11     author = models.ForeignKey(to="Author")
      12     book = models.ForeignKey(to="Book")
      13 
      14     class Meta:
      15         unique_together = ("author", "book")
      方式一:自行创建第三张表
      1 class Book(models.Model):
      2     title = models.CharField(max_length=32, verbose_name="书名")
      3 
      4 
      5 # 通过ORM自带的ManyToManyField自动创建第三张表
      6 class Author(models.Model):
      7     name = models.CharField(max_length=32, verbose_name="作者姓名")
      8     books = models.ManyToManyField(to="Book", related_name="authors")
      方式二:通过ManyToManyField自动创建第三张表
       1 class Book(models.Model):
       2     title = models.CharField(max_length=32, verbose_name="书名")
       3 
       4 
       5 # 自己创建第三张表,并通过ManyToManyField指定关联
       6 class Author(models.Model):
       7     name = models.CharField(max_length=32, verbose_name="作者姓名")
       8     books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
       9     # through_fields接受一个2元组('field1','field2'):
      10     # 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。
      11 
      12 
      13 class Author2Book(models.Model):
      14     author = models.ForeignKey(to="Author")
      15     book = models.ForeignKey(to="Book")
      16 
      17     class Meta:
      18         unique_together = ("author", "book")
      方式三:设置ManyTomanyField并指定自行创建的第三张表

      注意: 当我们需要在第三张关系表中存储额外的字段时,就要使用第三种方式。 但是当我们使用第三种方式创建多对多关联关系时,就无法使用set、add、remove、clear方法来管理多对多的关系了,需要通过第三张表的model来管理多对多关系。

元信息

ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。主要字段如下:

  • db_table

    ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名。

  • index_together

    联合索引。

  • unique_together

    联合唯一索引。

  • ordering

    指定默认按什么字段排序。 只有设置了该属性,我们查询到的结果才可以被reverse()。

操作

一般操作

  • 常用函数

    函数说明返回值
    all() 查询所有结果。 QuerySet
    filter(**kwargs) 它包含了与所给筛选条件相匹配的对象。 QuerySet
    get(**kwargs) 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。 单个对象
    exclude(**kwargs) 它包含了与所给筛选条件不匹配的对象。 QuerySet
    values(*field) 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列。 特殊的QuerySet
    values_list(*field) 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列。 特殊的QuerySet
    order_by(*field) 对查询结果排序。 QuerySet
    reverse() 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法)。 QuerySet
    distinct() 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。) QuerySet
    count() 返回数据库中匹配查询(QuerySet)的对象数量。 integer
    first() 返回第一条记录。 单个对象
    last() 返回最后一条记录。 单个对象
    exists() 如果QuerySet包含数据,就返回True,否则返回False boolean
  • 双下划线

     1 models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id大于1 且 小于10的值
     2  
     3 models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
     4 models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
     5  
     6 models.Tb1.objects.filter(name__contains="ven")  # 获取name字段包含"ven"的
     7 models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感
     8  
     9 models.Tb1.objects.filter(id__range=[1, 3])      # id范围是1到3的,等价于SQL的bettwen and
    10  
    11 类似的还有:startswith,istartswith, endswith, iendswith 
    12 
    13 date字段还可以:
    14 models.Class.objects.filter(first_day__year=2017)
    Code

ForeignKey操作

  • 正向

    • 查找对象
      1 book_obj = models.Book.objects.first()  # 第一本书对象
      2 print(book_obj.publisher)  # 得到这本书关联的出版社对象
      3 print(book_obj.publisher.name)  # 得到出版社对象的名称
      Code
    • 查找字段
      1 print(models.Book.objects.values_list("publisher__name"))
      Code
  • 反向

    • 查找对象
      1 publisher_obj = models.Publisher.objects.first()  # 找到第一个出版社对象
      2 books = publisher_obj.book_set.all()  # 找到第一个出版社出版的所有书
      3 titles = books.values_list("title")  # 找到第一个出版社出版的所有书的书名
      Code
    • 查找字段
      1 titles = models.Publisher.objects.values_list("book__title")
      Code

ManyToManyField

  • class RelatedManager

    "关联管理器"是在一对多或者多对多的关联上下文中使用的管理器。

    它存在于下面两种情况:

      外键关系的反向查询

      多对多关联关系

    简单来说就是当点(".")后面的对象可能存在多个的时候就可以使用以下的方法。

  • 方法

    • create()

      创建一个新的对象,保存对象,并将它添加到关联对象集之中,返回新创建的对象。

      1 import datetime
      2 models.Author.objects.first().book_set.create(title="番茄物语", publish_date=datetime.date.today())
      Code
    • add()

      添加对象,把指定的model对象添加到关联对象集中。

      1 author_objs = models.Author.objects.filter(id__lt=3)
      2 models.Book.objects.first().authors.add(*author_objs)
      3 # 直接用id关联
      4 models.Book.objects.first().authors.add(*[1, 2])
      Code
    • set()

      更新model对象的关联对象。

      1 book_obj = models.Book.objects.first()
      2 book_obj.authors.set([2, 3])
      Code
    • remove()

      从关联对象集中移除执行的model对象。

      1 book_obj = models.Book.objects.first()
      2 book_obj.authors.remove(3)
      Code
    • clear()

      从关联对象集中移除一切对象。

      1 book_obj = models.Book.objects.first()
      2 book_obj.authors.clear()
      Code
  • 注意

    1. 对于通过ForeignKey关联的对象,clear()和remove()方法仅在null=True时存在。
    2. 对于所有类型的关联字段,即使不调用save()方法,执行add()、create()、remove()、clear()和set()也会马上更新数据库。

查询

现有模型及其数据信息如下:

 1 from django.db import models
 2 
 3 
 4 class Press(models.Model):
 5     '''
 6     出版社
 7     '''
 8     id = models.AutoField(primary_key=True)
 9     name = models.CharField(max_length=50, unique=True)
10 
11 
12 class Book(models.Model):
13     '''
14     书籍
15     '''
16     id = models.AutoField(primary_key=True)
17     name = models.CharField(max_length=50, unique=True)
18     price = models.DecimalField(max_digits=5, decimal_places=2)
19     stock = models.IntegerField()
20     saleNumber = models.IntegerField()
21     press = models.ForeignKey(Press)
模型
Press表:

Book表:
数据
  • 聚合和分组

    • 聚合

      aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。 键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。

      1 # 聚合
      2 from django.db.models import Avg, Max, Min, Count
      3 
      4 print(models.Book.objects.all().aggregate(Avg('price'), Max('price'), Min('price'),Count('id')))
      5 '''
      6 result:
      7     {'price__avg': 44.713333, 'price__max': Decimal('65.30'), 'price__min': Decimal('32.54'), 'id__count': 3}
      8 '''
      例:
    • 分组

      使用annotate()函数,对应数据库中的'group by'语句。

       1 # 查询每个出版社(Press)拥有的书籍(Book)数量
       2 from django.db.models import Count
       3 press_list = models.Press.objects.all().annotate(book_count=Count('book'))
       4 [print(press_info, '出版社名称:{},书籍数量:{}'.format(press_info.name, press_info.book_count)) for press_info in press_list]
       5 '''
       6 result:
       7     Press object 出版社名称:长江出版社,书籍数量:2
       8     Press object 出版社名称:电子工业出版社,书籍数量:1
       9     Press object 出版社名称:清华大学出版社,书籍数量:0
      10 '''
      11 # values
      12 press_list = models.Press.objects.all().annotate(book_count=Count('book')).values('name', 'book_count')
      13 [print(press_info) for press_info in press_list]
      14 '''
      15 result:
      16     {'name': '长江出版社', 'book_count': 2}
      17     {'name': '电子工业出版社', 'book_count': 1}
      18     {'name': '清华大学出版社', 'book_count': 0}
      19 '''
      20 # value_list
      21 press_list = models.Press.objects.all().annotate(book_count=Count('book')).values_list('name', 'book_count')
      22 [print(press_info) for press_info in press_list]
      23 
      24 '''
      25 result:
      26     ('长江出版社', 2)
      27     ('电子工业出版社', 1)
      28     ('清华大学出版社', 0)
      29 '''
      例:
  • F和Q

    • F查询
      from django.db.models import F

      1、原来的filter只是单个字段和具体值之间的比较,使用F函数可以实现两个字段值之间的比较。

       1 # 查询库存数量大于销售数量的书籍
       2 [print(book.name) for book in models.Book.objects.all().filter(stock__gt=F('saleNumber'))]
       3 '''
       4 result:
       5     django深入解析
       6     spring源码解析
       7 '''
       8 
       9 # 操作字符串
      10 # 给每本书名后加上“当当网出售”
      11 from django.db.models.functions import Concat
      12 from django.db.models import Value
      13 
      14 models.Book.objects.update(name=Concat('F("name")', Value("当当网出售")))
      15 
      16 # result:
      例:

      2、F对象也支持使用算数运算:

      list.filter(bread__gte=F('bcommet') * 2)
      例:

      3、F对象中还可以写作“模型类__列名”进行关联查询:

      list.filter(isDelete=F('heroinfo__isDelete'))
      例:

      4、对于date/time字段,可与timedelta()进行运算:

      list.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))
      例:
    • Q查询
      from django.db.models import Q

      1、filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。

      # 查询卖出数量大于10 或 价格小于50的书籍 且名字里包含‘spring’的书籍
      
      [print(book.name) for book in
       models.Book.objects.filter(Q(saleNumber__gt=10) | Q(price__lt=50), name__contains='spring')]
      '''
      result:
          spring源码解析当当网出售
      '''
      例:
      注意:同时具有字段查询和Q查询时,字段查询必须放在Q查询后面。

      2、Q对象包括AND关系和OR关系,可以用&和|运算符进行连接。当以某个运算符连接两个Q对象时,就会产生一个新的Q 对象。 如:下面这段语句就产生了一个Q,这是用 "OR" 关系连接:

      Q(question__startswith='Who') | Q(question__startswith='What')
      例:

      3、每种查询函式(比如 filter(), exclude(), get())除了能接收关键字参数以外,也能以位置参数的形式接受一个或多个 Q 对象。如果你给查询函式传递了多个 Q 对象,那么它们彼此间都是 "AND" 关系。例如:

      Poll.objects.get(
          Q(question__startswith='Who'),
          Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
      )
      例:

      4、也可以通过Q对象的children属性拼凑查询条件,传入条件进行查询:

      q1 = Q()
      q1.connector = 'OR'              # 连接方式 还有 'AND'
      q1.children.append(('id', 1))
      q1.children.append(('id', 2))
      q1.children.append(('id', 3))
      models.Tb1.objects.filter(q1)
      例:

       5、还可以将多个Q对象合并成一个Q对象进行查询:

      con = Q()
      
      q1 = Q()
      q1.connector = 'OR'
      q1.children.append(('id', 1))
      q1.children.append(('id', 2))
      q1.children.append(('id', 3))
      
      q2 = Q()
      q2.connector = 'OR'
      q2.children.append(('status', '在线'))
      
      con.add(q1, 'AND')
      con.add(q2, 'AND')
      
      models.Tb1.objects.filter(con)
      例:

扩展

事务操作

1 try:
2     from django.db import transaction
3     with transaction.atomic():
4         new_publisher = models.Publisher.objects.create(name="火星出版社")
5         models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10)  # 指定一个不存在的出版社id
6 except Exception as e:
7     print(str(e))
Code

执行原生Sql

  • extra

    结果集修改器,一种提供额外查询参数的机制。

     1 # 查询所有用户,并多查询出年龄是否大于20的一列
     2 list = UserInfo.objects.all().extra(select={'gt20': 'age>20'})
     3 [print(u.gt20) for u in list]
     4 '''
     5 result:
     6     1
     7     1
     8     0
     9 '''
    10 # 查询年龄大于20的用户
    11 list = UserInfo.objects.all().extra(where=['age>20'])
    12 # 等价于
    13 list = UserInfo.objects.filter(age__gt=20)
    例:
  • raw

    执行原始sql并返回模型实例。

    1 list = UserInfo.objects.raw('select * from UserInfo')
    2 [print(i.name) for i in list]
    例:

    惰性查询,返回rawQuerySet,只有在使用时才会真正执行。

  • cursor

    直接执行自定义Sql(这种方式完全不依赖model,前两种还是要依赖于model)。

     1 from django.db import connection
     2 
     3 cursor = connection.cursor()
     4 # 插入操作
     5 cursor.execute("insert into UserInfo(name,age) values('郭敬明','99')")
     6 # 更新操作
     7 cursor.execute("update UserInfo set name='张三' where name='张大三'")
     8 # 删除操作
     9 cursor.execute("delete from UserInfo where name='张三'")
    10 # 查询操作
    11 cursor.execute('select * from UserInfo')
    12 for u in cursor: print(u)
    13 user_list = cursor.fetchall()  # 读取所有
    14 for u in user_list: print(u)
    15 
    16 '''
    17 result:
    18     (1, '张三', 21)
    19     (2, '李四', 23)
    20     (3, '王五', 19)
    21     (4, '赵六', 40)
    22 '''
    例:

查询指定列之only&defer

现有如下模型:

class User(models.Model):
    nick_name = models.CharField(max_length=32)
    age = models.IntegerField()
模型

首先我们是知道 queryset.values 和 queryset.values_list 方法都是查询模型中指定字段,但是它们返回值的数据结构是不同的。如下:

print(models.User.objects.values('nick_name', 'age'))
# <QuerySet [{'nick_name': 'zhangsan', 'age': 12}, {'nick_name': 'lisi', 'age': 32}, {'nick_name': 'wangwu', 'age': 23}]>
print(models.User.objects.values_list('nick_name', 'age'))
# <QuerySet [('zhangsan', 12), ('lisi', 32), ('wangwu', 23)]>

可以看到,前者返回的是放着字典的 queryset ,而后者返回是放着元组的 queryset 。下面再看一下 queryset.only 方法:

  • queryset.only

    print(models.User.objects.only('nick_name'))
    
    # (0.000) SELECT "api_user"."id", "api_user"."nick_name" FROM "api_user"  LIMIT 21; args=()
    # <QuerySet [<User: User object (1)>, <User: User object (2)>, <User: User object (3)>]>

    从 console 打印的 sql 可以看到, queryset.only 除了查询指定列还默认查询了主键,而返回值是对应模型对象。再看下面代码:

    user_set = models.User.objects.only('nick_name')
    for user in user_set:
        print(user.age)
        
    '''
    12
    32
    23
    (0.000) SELECT "api_user"."id", "api_user"."nick_name" FROM "api_user"; args=()
    (0.000) SELECT "api_user"."id", "api_user"."age" FROM "api_user" WHERE "api_user"."id" = 1; args=(1,)
    (0.000) SELECT "api_user"."id", "api_user"."age" FROM "api_user" WHERE "api_user"."id" = 2; args=(2,)
    (0.000) SELECT "api_user"."id", "api_user"."age" FROM "api_user" WHERE "api_user"."id" = 3; args=(3,)
    '''

    可以看到,当我们使用 only 中未指定的列时,这个列会即时加载。

  • queryset.defer

    queryset.defer 与上面的 queryset.only 方法正好相反,它是用来查询除指定列之外的字段。如下:
    user_set = models.User.objects.defer('nick_name')
    for user in user_set:
        print(user.age)
        print(user.nick_name)
            
    '''
    (0.000) SELECT "api_user"."id", "api_user"."age" FROM "api_user"; args=()
    (0.000) SELECT "api_user"."id", "api_user"."nick_name" FROM "api_user" WHERE "api_user"."id" = 1; args=(1,)
    (0.000) SELECT "api_user"."id", "api_user"."nick_name" FROM "api_user" WHERE "api_user"."id" = 2; args=(2,)
    (0.000) SELECT "api_user"."id", "api_user"."nick_name" FROM "api_user" WHERE "api_user"."id" = 3; args=(3,)
    '''
posted @ 2018-05-02 15:40  zze  阅读(308)  评论(0编辑  收藏  举报