django之ORM操作

Django 中有一个强大的功能,就是ORM,他可以不写sql语句,使用python语法,即可操作数据库。当然也有自己的书写规则。大概看一下django中的ORM的使用规则。

前奏

  • 在settings中配置,可显示sql语句:
    # 显示SQL语句
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level': 'DEBUG',
            },
        }
    }
    
  • 加载环境,以单文件运行
    import os
    
    if __name__ == '__main__':
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")  # mysite为自己的项目中settings的父级目录
        import django
        django.setup()
    

一、单个表的增删改查

表:
class User(models.Model):
    username=models.charFiled(max_lenth=255)
    password=models.charFiled(max_lenth=255)
创建:User.objects.create(username='zhangsan',password='123')
查询:objs = User.objects.all()
删除:objs = bjects.filter('id=1')
      objs.delete()
更新:obj = objs[0]
      obj.username = "new_name"
      obj.save()

接下来看一下ORM中其他的一些查询语句。

为什么查询那么重要?
操作数据库,简单来说就是对数据进行增删改查,在数据的增删改查四步操作中,只有增加不用查询,删除、更改 都是在查询出结果的前提下才能进行,所以ORM查询尤为重要。

举个简单的例子,来练习一下 django的ORM查询语句 。

二、常见的单表查询(13种)

QuerySet 对象的形成:
按照需求执行sql语句,从数据库查询出一个表,
表里的每个记录封装成对象,每个字段封装成属性,
而这个表就可以看成是QuerySet对象。

class Person(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    birth = models.DateField(auto_now=True)

    def __str__(self):
        return '<Person obj:{}--{}>'.format(self.name,self.id)

    # class Meta:
    #     ordering = ('id',)
    # 为此类指定默认排序方式。
  • 【1】all():返回QuerySet对像,类似于列表的东西,查询所有。
    ret = models.Person.objects.all()
    print(ret)  # 【此刻执行了sql语句】
    # <QuerySet [<Person: <Person obj:赵昭昭--1>>, <Person: <Person obj:钱芊芊--2>>,
    #            <Person: <Person obj:孙笋笋--3>>, <Person: <Person obj:李莉莉--4>]>
    
  • 【2】get():返回一个对象,找不到或找到多个报错。
    ret = models.Person.objects.get(id=3)  # 【此刻执行了sql语句】
    print(ret)
    # (0.001) SELECT `app01_person`.`id`, `app01_person`.`name`, `app01_person`.`age`, `app01_person`.`birth` FROM `app01_person` WHERE `app01_person`.`id` = 3; args=(3,)
    # <Person obj:孙笋笋--3>
    
  • 【2.1】 only():【使用only可以降低查询压力,增加查询速度】
    ret = models.Person.objects.only('name').get(id=3)  # 【此刻执行了sql语句】
    print(ret)
    # (0.001) SELECT `app01_person`.`id`, `app01_person`.`name` FROM `app01_person` WHERE `app01_person`.`id` = 3; args=(3,)
    # <Person obj:孙笋笋--3>
    
  • 【3】filter():返回QuerySet,包含符合条件的所有对象,查不到就是空的QuerySet对象<QuerySet []>
    ret = models.Person.objects.filter(id=3)
    print(ret)  # 【此刻执行了sql语句】
    # <QuerySet [<Person: <Person obj:孙笋笋--3>>]>
    # ret = models.Person.objects.filter(id=3)[0]    # filter的时候没有执行sql语句,filter[0]的时候,执行了sql
    
  • 【4】exclude():返回QuerySet,和filter相反。
    ret = models.Person.objects.exclude(id=3)
    print(ret)  # 【此刻执行了sql语句】
    # <QuerySet [<Person: <Person obj:赵昭昭--1>>, <Person: <Person obj:钱芊芊--2>>,<Person: <Person obj:李莉莉--4>]>,
    
  • 【5】values():返回QuerySet,里面是字典
    ret = models.Person.objects.values()
    print(ret)  # 【此刻执行了sql语句】
    # <QuerySet [{'id': 1, 'name': '赵昭昭', 'age': 20, 'birth': datetime.date(1998, 8, 5)},
    #            {'id': 2, 'name': '钱芊芊', 'age': 18, 'birth': datetime.date(2000, 8, 6)},
    #            {'id': 3, 'name': '孙笋笋', 'age': 16, 'birth': datetime.date(2002, 8, 6)},
    #            {'id': 4, 'name': '李莉莉', 'age': 22, 'birth': datetime.date(1996, 6, 8)} ]>
    
    ret = models.Person.objects.values('name', 'age')  # 指定字段就只显示字段的内容,找不到指定字段报错。
    print(ret)
    # <QuerySet [{'name': '赵昭昭', 'age': 20}, {'name': '钱芊芊', 'age': 18},
    #            {'name': '孙笋笋', 'age': 16}, {'name': '李莉莉', 'age': 22}]>
    
  • 【6】value_list():返回QuerySet,里面是元组,不包括健
    ret = models.Person.objects.values_list()
    print(ret)  # 【此刻执行了sql语句】
    # <QuerySet [(1, '赵昭昭', 20, datetime.date(1998, 8, 5)),
    #            (2, '钱芊芊', 18, datetime.date(2000, 8, 6)),
    #            (3, '孙笋笋', 16, datetime.date(2002, 8, 6)),
    #            (4, '李莉莉', 22, datetime.date(1996, 6, 8))]>
    
    ret = models.Person.objects.values_list('age', 'name')
    print(ret)
    # <QuerySet [(20, '赵昭昭'), (18, '钱芊芊'), (16, '孙笋笋'), (22, '李莉莉')]>
    
    ret = models.Person.objects.values_list('age')
    print(ret)
    # <QuerySet[(20,), (18,), (16,), (22,)]>
    
    【flat=True】:将单个字段的数据直接放到列表里面(只有一个字段时才可用)
    ret = models.Person.objects.values_list('age', flat=True)
    print(ret)
    # <QuerySet [20, 18, 16, 22]>
    
  • 【7】order_by():按某字段排序,可反序,可按多字段排序
    ret = models.Person.objects.all().order_by('-id')
    print(ret)  # 【此刻执行了sql语句】
    # <QuerySet [<Person: <Person obj:李莉莉--4>>, <Person: <Person obj:孙笋笋--3>>,
    #            <Person: <Person obj:钱芊芊--2>>, <Person: <Person obj:赵昭昭--1>>]>
    
  • 【8】reverse():对排序后(使用了order_by)的QuerySet进行反转。(类中设置了默认排序也可以用)
    ret = models.Person.objects.all().order_by('-age').reverse()
    print(ret)  # 【此刻执行了sql语句】
    # <QuerySet [<Person: <Person obj:孙笋笋--3>>, <Person: <Person obj:钱芊芊--2>>,
    #            <Person: <Person obj:赵昭昭--1>>, <Person: <Person obj:李莉莉--4>>]>      
    #  年龄:16,18,20,22
    
  • 【9】distinct():去重
  • 【10】count():对QuerySet对象进行计数。
    ret = models.Person.objects.all().count()  # 【此刻执行了sql语句】
    print(ret)
    # 4
    
  • 【11】first():取QuerySet中的第一个元素。
    ret = models.Person.objects.all().first()  # 【此刻执行了sql语句】
    #  ret = models.Person.objects.first() 可不写,默认全部
    print(ret)
    # <Person obj:赵昭昭--1>
    
  • 【12】last():取QuerySet中的最后一个元素。
  • 【13】exists():如果QuerySet包含数据,就返回True,否则返回False
    ret = models.Person.objects.filter(id=1).exists()  # 【此刻执行了sql语句】
    print(ret)
    # True
    ret = models.Person.objects.filter(id=10).exists()
    print(ret)
    # False
    
  • 返回QuerySet对象的有 (QuerySet对象有个.query属性,可以查看sql语句。返回 QuerySet对象的方法,都没有真正执行sql语句。当 print QuerySet对象,或者显示QuerySet对象的结果时,才执行了sql):

    1.all()               2.filter()        3.exclude()       4.values()
    5.values_list()       6.order_by()      7.reverse()       8.distinct()
    
  • 返回具体对象的方法有:

    1.get()            2.first()             3.last()
    
  • 返回数字的方法有:

    1.count()
    
  • 返回布尔值的方法有:

    1.exists()
    

三、单表查询的双下划线方法

  • 【查询 id = 1 的】
    ret = models.Person.objects.filter(id=1)
    print(ret)
    """
    <QuerySet [<Person: <Person obj:赵昭昭--1>>]>
    """
    
  • 【查询 id > 1 的】( greater than )
    ret = models.Person.objects.filter(id__gt=1)
    print(ret)
    """
    <QuerySet [<Person: <Person obj:钱芊芊--2>>, <Person: <Person obj:孙笋笋--3>>, <Person: <Person obj:李莉莉--4>>]>
    """
    
  • 【查询 id <3 的】( less than )
    ret = models.Person.objects.filter(id__lt=3)
    print(ret)
    """
    <QuerySet [<Person: <Person obj:赵昭昭--1>>, <Person: <Person obj:钱芊芊--2>>]>
    """
    
  • 【查询 id >=3 的】( equal )
    ret = models.Person.objects.filter(id__gte=3)
    print(ret)
    """
    <QuerySet [<Person: <Person obj:孙笋笋--3>>, <Person: <Person obj:李莉莉--4>>]>
    """
    
  • 【查询 id <=3 的】
    ret = models.Person.objects.filter(id__lte=3)
    print(ret)
    """
    <QuerySet [<Person: <Person obj:赵昭昭--1>>, <Person: <Person obj:钱芊芊--2>>, <Person: <Person obj:孙笋笋--3>>]>
    """
    
  • 【查询 2 <= id <= 4 的】
    ret = models.Person.objects.filter(id__gte=2, id__lte=4)
    print(ret)
    """
    <QuerySet [<Person: <Person obj:钱芊芊--2>>, <Person: <Person obj:孙笋笋--3>>, <Person: <Person obj:李莉莉--4>>]>
    """
    
  • 【查询 id 在 。。。里的】
    ret = models.Person.objects.filter(id__in=[1, 2, 4])
    print(ret)
    """
    <QuerySet [<Person: <Person obj:赵昭昭--1>>, <Person: <Person obj:钱芊芊--2>>, <Person: <Person obj:李莉莉--4>>]>
    """
    
  • 【查询 id 不在。。。里的】
    ret = models.Person.objects.exclude(id__in=[1, 2, 4])
    print(ret)
    """
    <QuerySet [<Person: <Person obj:孙笋笋--3>>]>
    """
    
  • 【查看某字段中包含。。。字眼的】( 找不到为空 )
    ret = models.Person.objects.filter(name__contains='赵')
    # ret = models.Person.objects.filter(name__icontains='h') 此项是英文不区分大小写。
    print(ret)
    """
    <QuerySet [<Person: <Person obj:赵昭昭--1>>]>
    """
    
  • 【查询 id 在。。。范围内】2,3,4
    ret = models.Person.objects.filter(id__range=[2, 4])
    print(ret)
    """
    <QuerySet [<Person: <Person obj:钱芊芊--2>>, <Person: <Person obj:孙笋笋--3>>, <Person: <Person obj:李莉莉--4>>]>
    """
    
  • 【查询 某字段以。。。为开头的】
    ret = models.Person.objects.filter(name__startswith='钱')
    # models.Person.objects.filter(name__istartswith="v") # istartswith大小写不敏感
    print(ret)
    """
    <QuerySet [<Person: <Person obj:钱芊芊--2>>]>
    """
    
  • 【查询 某字段以。。。为结尾的】( iendswith 模糊查询 )
    ret = models.Person.objects.filter(name__endswith='莉')
    print(ret)
    """
    <QuerySet [<Person: <Person obj:李莉莉--4>>]>
    """
    
  • 【查询 关于年,月,日 的】
    ret = models.Person.objects.filter(birth__year=1998)
    ret = models.Person.objects.filter(birth__month=6)
    ret = models.Person.objects.filter(birth__day=10)
    # mysql 数据库可以用这样逗号隔开and的 方式。用django自带的数据库可能不支持。
    ret = models.Person.objects.filter(birth__year=1998, birth__month=6)  
    ret = models.Person.objects.filter(birth__contains='1998-06')
    print(ret)  # 有警告,但是可以查出来。
    

四、有外键关系的查询

  • 先定义三个模型类,出版社 <---1对多---> 书籍 <---多对多---> 作者。
    from django.db import models
    
    class Publisher(models.Model):
        name = models.CharField(max_length=32)
    
    class Book(models.Model):
        title = models.CharField(max_length=32)   
        publisher = models.ForeignKey(to='Publisher')  
        # publisher = models.ForeignKey(to='Publisher',related_name='books')
        # publisher = models.ForeignKey(to='Publisher',related_name='books',related_query_name='xx')
        # 这个related_name 反向查询,基于对象时用 【和下面【↓】的对应】。
        # 这个related_query_name 【反向查询,基于字段】时用。
        price = models.DecimalField(max_digits=5,decimal_places=2,null=True)
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
        books = models.ManyToManyField(to='Book')     
    
  • 查询时先看清楚是正向还是反向,看清是基于对象的查询还是基于字段的查询。


    外键的正反向查询.png

1,【正向查询】---> 从多往1找(一般外键都设在多的一方)

  • 基于对象查询
    book_obj = models.Book.objects.filter(title='北京生活')[0] 
    #【先有一个对象,拿出一本书,再查有关书的一些东西】
    print(book_obj.title)   # 书的名字(没有设外键的字段)
    print(book_obj.publisher)  # Publisher object 出版社对象(设外键的字段)
    print(book_obj.publisher.name)  # 北京出版社(跨表查询)
    
  • 基于字段查询 (跨表查询)(不是本表中的字段,是关联表中的字段)
    ret = models.Book.objects.filter(publisher__name='北京出版社')  
    # 站在书籍的角度,查询'北京出版社'出版的所有书籍
    print(ret)
    

2,【反向查询】---> 从1往多找

  • 基于对象查询
    publisher_obj = models.Publisher.objects.get(name='北京出版社')  # 拿到一个出版社对象
    print(type(publisher_obj.book_set))    # "关联管理器"
    print(publisher_obj.book_set.all())    # "关联管理器".all()查询出版社出版的所有书籍。
    
    # Book表中的:
    # publisher = models.ForeignKey(to='Publisher',related_name='books')
    # print(publisher_obj.books.all()) (【和上面【↑】对应】,如果关联对象的相关字段写了related_name='books',本语句就可这样写。)
    
    # pub_obj = models.Publisher.objects.first()  # 拿到北京出版社
    # pub_obj.book_set.create(title='北京生活')  # 利用管理对象,创建书籍(为本出版社添加书籍,但是书籍没有作者)
    
  • 基于字段查询 (跨表查询)
    ret = models.Publisher.objects.filter(book__title="北京生活")  # 查询"北京生活"的出版社。
    print(ret)
    # 如果上面加了related_name = 'bookssss',那么就得写成(bookssss__title="北京生活"【和上面【↑】对应】)。
    # 如果上面在加了related_name = 'books'之后,又加了 related_query_name='xx',就得写(xx__title="北京生活")。
    # 也就是说:
    #   如果外键字段只定义了 related_name = 'books' ,那么反向查询时,不管基于对象还是基于字段都可以使用 books 名称代替。
    #   如果外键字段定义了 related_name = 'books' ,又定义了 related_query_name='xx' 那么基于字段的反向查询时只能使用 xx__title 名称代替。
    
    '''外键的"关联管理器",在被关联那一边,反向查找时可用,是book_set(表名_set),可起别名'''
    
    # 如果把出版社的所有书籍都删了,也就是删除了有关书籍和这个出版社的对应关系,对于书籍而言,出版社就为空了。
    # 如果想要在多对一的关系中,基于1的一面删除多,就得在多的一面设置可以为空。
    

五、多对多关系的增删改查

1,【正向查询】

  • 基于对象
    多对多的正向查询.png
    author_obj = models.Author.objects.first()
    print(author_obj.name)  # 作者的姓名  李白
    print(author_obj.books)  # "关联管理器"
    
    # print(author_obj.books.all())
    # author_obj.books.create(title='一起来学习',publisher_id=5)   # "关联管理器".create()创建book对象  
    # author_obj.books.add(10,11)  # 给作者添加几本书,之前在出版社创建了几本书,现在是给作者增加几个关联对象
    # author_obj.books.remove(12,13)  # 和add相反,去除几个书籍。
    # author_obj.books.clear()  # 清空
    
    # "关联管理器".add(*args),添加几个关联,(前提是有这几本书)相当于在第三张关联表中,增加了几个关联。
    # 和 author_obj.books.set([]) 不同:
    #        set是创建对象时或者创建对象后,给多对多字段设置属性,可以是id列表,可以是QuerySet
    #        add是有了对象,给对象增加属性,可以是id,可以是对象。如果是QuerySet,必须打散
    
    # booklist = models.Book.objects.filter(author__id=1)
    # print(booklist)
    # print(*booklist)
    # author_obj.books.remove(*booklist)
    
    # publisher_obj = models.Publisher.objects.get(id=1)
    # booklist2 = publisher_obj.book_set.all()
    # print(publisher_obj)
    # print(booklist2)
    # author_obj.books.set(booklist2)
    
    '''多对多的"关联管理器",在关联那一边,名字为,设置了多对多关系的字段名books'''
    

六、聚合与分组

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

1、聚合函数

  • 可自己写名称,默认是以 字段__聚合函数 为名称
    avg = models.Book.objects.aggregate(Avg('price'))
    print(avg)  # {'price__avg': 80.0}
    
    avg = models.Book.objects.aggregate(平均=Avg('price'))
    print(avg)  # {'平均': 80.0}
    
    ret = models.Book.objects.aggregate(Sum('price'),Max('price'),Min('price'),Count('id'))
    print(ret)  # {'price__sum': Decimal('1040.00'), 'price__max': Decimal('140.00'),
                # 'price__min': Decimal('20.00'), 'id__count': 13}
    

2、分组

  • 【统计书的作者个数】 书 <------> 作者

    ret = models.Book.objects.annotate(Count('author')).values()
    for i in ret:
        print(i)
    
  • 【出版社最便宜的书的价格】 出版社 <------> 书

    ret = models.Publisher.objects.annotate(Min('book__price')).values()
    for i in ret :
        print(i)
    
  • 【作者个数大于1的书】 作者 <------> 书

    ret = models.Book.objects.annotate(num=Count('author')).filter(num__gt=1).values()
    for i in ret:
        print(i)
    
  • 【查询各个作者出了几本书】 作者 <------> 书

    ret = models.Author.objects.annotate(Count('books')).values()
    for i in ret:
        print(i)
    
  • 【查询各个作者出的书的总价格】 作者 <------> 书

    ret = models.Author.objects.annotate(Sum('books__price')).values()
    for i in ret:
        print(i)
    
    '''annotate前面是什么就按什么分组,没有默认是以id为准'''
    

七、F查询、Q查询

class Book(models.Model):
    title = models.CharField(max_length=32)
    publisher = models.ForeignKey(to='Publisher') 

    price = models.DecimalField(max_digits=5,decimal_places=2,null=True)
    # 此字段为以后聚合函数使用      最大长度      小数点后长度    可以为空
    # 后加的字段,需要设置默认值,要不就设置可以为空

    kucun = models.IntegerField(default=0)
    sale = models.IntegerField(default=100)
    # 后加字段,为测试 F查询、Q查询使用
from django.db.models import F, Q
  • 【F 查询】

    # 原来查询方法,比较时,符号后面是外界得到的条件,是提前给好的数据。
    ret = models.Book.objects.filter(id__gt=10)  # 过滤条件是跟常量比较。
    print(ret)
    # 想要在表中自己和自己的数据比较就得用 F 查询
    
    # 【查询库存数小于出售数的】
    ret = models.Book.objects.filter(kucun__lt=F('sale'))
    for i in ret:
        print(i)
        print(i.title, i.kucun, i.sale)
    
    # 原来的方法,修改对象的属性时,是这样操作:
    book_obj = models.Book.objects.get(title='红楼梦')
    book_obj.title = '葫芦娃'
    book_obj.save()
    
    # 新的修改方法:QuerySet对象.update(字段=‘’)
    models.Book.objects.filter(title='葫芦娃').update(title='金刚葫芦娃')
    
    #【给所有书的库存增加数量】
    models.Book.objects.all().update(kucun=F('kucun')+100)
    
    #【给书籍名字统一加字符串】
    from django.db.models.functions import Concat
    from django.db.models import Value
    models.Book.objects.all().update(title=Concat(F('title'),Value('(第一版)')))
    
  • 【Q 查询】

    # 原来查询两边的查询:
    ret = models.Book.objects.filter(id__gt=3, id__lt=6)  # 4,5
    print(ret)
    ret = models.Book.objects.exclude(id__gt=3, id__lt=6)  # 没有4,5
    print(ret)
    ret = models.Book.objects.exclude(id=3)  # 没有3
    print(ret)
    
    # 现在查询两边的查询:
    ret = models.Book.objects.filter(Q(id__gt=3) & Q(id__lt=6))  # 4,5,并且
    print(ret)
    ret = models.Book.objects.filter(Q(id__lt=3) | Q(id__gt=6))  # 小于3,大于6,没有3,4,5,6,或
    print(ret)
    ret = models.Book.objects.filter(~Q(id=3))  # 没有3
    print(ret)
    ret = models.Book.objects.filter(~Q(id=3), id__lt=5)  # 小于5,且没有3【注意,Q放前面】
    print(ret)
    
    # Q 查询的另一种用法。
    q = Q()  # 实例出一个对象。
    q.children.append(('title', '西游记'))  # 元组里放字符串
    obj = models.Book.objects.filter(q)
    print(obj)
    
    q1 = Q()  # 空的Q对象,等同于all().
    q1.connector = 'or'  # 将查询条件改成“或”,默认是“与”
    q1.children.append(('title', '西游记'))
    q1.children.append(('price' + '__icontains', 20)) # 可添加多个搜索条件,支持模糊查询。
    ret = models.Book.objects.filter(q1)
    print(ret) 
    

八、面试题

from django.db import models


class WfModel(models.Model):
    """
    工作流
    """
    model_id = models.AutoField(primary_key=True)  # 主键ID
    model_name = models.CharField(max_length=255)  # 工作流名称
    create_time = models.DateTimeField(auto_now_add=True)  # 添加时间

    def __str__(self):
        return "ID为%s的%s号" % (self.model_id, self.model_name)


class WfStep(models.Model):
    """
    工作流步骤
    """
    step_id = models.AutoField(primary_key=True)  # 主键ID
    model = models.ForeignKey(WfModel, models.DO_NOTHING)  # 流程ID
    step_name = models.CharField(max_length=255)  # 步骤名称

    def __str__(self):
        return self.step_name


class WfStepCheck(models.Model):
    """
    工作节流点人员表
    """
    check_id = models.AutoField(primary_key=True)  # 主键
    step = models.ForeignKey(WfStep, models.DO_NOTHING)  # 步骤ID
    check_user_id = models.IntegerField()  # 角色ID或用户ID
    is_design = models.BooleanField(default=1)  # 是否设计;1是;0否;

    def __str__(self):
        return "%s的%s号人员,check_id为%s" % (self.step, self.check_user_id, self.check_id)
  • 【1】、如上3个实体表,其中知道实体 WfModel 的 model_id 值为:[1, 2, 3],要查询 WfStepCheck 中 is_design 的值,请用 django 的 orm 或 sql 写出查询语句
# sql = "select step_id from app_wfstep where model_id in (1,2,3)"
sql = "select is_design from app_wfstepcheck where step_id in(select step_id from app_wfstep where model_id in (1,2,3))"

from django.db import connection

cursor = connection.cursor()
cursor.execute(sql)
row = cursor.fetchall()
print(row)

或者使用以下的orm查询语句↓ (执行一次数据库查询)
objects = WfStepCheck.objects.select_related('step').filter(step__model__model_id__in=[1, 2, 3]).values('is_design')
print(objects)
  • 【2】、实体 WfModel 中 model_id 值为:[1, 2, 3],要更新 WfStepCheck 中 is_design 的值为 False,请用 django 的 orm 或 sql 写出更新语句
objects = WfStepCheck.objects.filter(step__model__model_id__in=[1, 2, 3])
#print(objects)
#如果单独查询,直接print的话会执行多次sql,但是如果使用objects.update()会执行一次sql。
#所以:如果是更新的话,不用使用select_related,但要是查询的时候建议使用select_related,减少数据库查询次数。
objects.update(is_design=0)
  • 【3】、通过 WfModel 的 model_id 为3的条件,查询 WfStepCheck 的信息,函数为 get_wf_check(),此函数是否有问题,为什么?
def get_wf_check():
    """获取步骤的审批人员信息"""
    step_check = []
    for item in WfModel.objects.filter(model_id=3):
        # print("item-->",item)
        for step in WfStep.objects.filter(model=item):
            # print("step-->",step)
            for stepcheck in WfStepCheck.objects.filter(step=step):
                # print("stepcheck-->",stepcheck)
                step_check.append(stepcheck)
    return step_check

ret = get_wf_check()
print(ret)

# for obj in ret:
#     print(obj.check_id, obj.check_user_id, obj.step, obj.is_design)

这样不好,他会多次去查询数据库,增加数据库压力。最好这样,只查询一次:

ret = WfStepCheck.objects.select_related('step').filter(step__model__model_id=3)
print(ret)

1,每一张表在数据库中,都是以app的名字开头
2,外键的字段在数据库中,会自动加上_id
3,__str__中必须返回字符串,如果想要在models类里面显示数字类的信息,需要str一下。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351