• Django单表操作


    Django之单表操作

    一、 ORM简介

    img

    我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增、删、改、查),而一旦谈到数据的管理操作,就需要用到数据库管理软件,例如mysql、oracle、Microsoft SQL Server等。

    如果应用程序需要操作数据(比如将用户注册信息永久存放起来),那么我们需要在应用程序中编写原生sql语句,然后使用pymysql模块远程操作mysql数据库,详见图1

    但是直接编写原生sql语句会存在两方面的问题,严重影响开发效率,如下:

    • sql语句的执行效率:应用开发程序员需要耗费一大部分精力去优化sql语句
    • 数据库迁移:针对mysql开发的sql语句无法直接应用到oracle数据库上,一旦需要迁移数据库,便需要考虑跨平台问题

    为了解决上述问题,django引入了ORM的概念,ORM全称Object Relational Mapping,即对象关系映射,是在pymysq之上又进行了一层封装,对于数据的操作,我们无需再去编写原生sql,取而代之的是基于面向对象的思想去编写类、对象、调用相应的方法等,ORM会将其转换/映射成原生SQL然后交给pymysql执行,详见图

    插图1

    原生SQL与ORM的对应关系示例如下

    插图2

    如此,开发人员既不用再去考虑原生SQL的优化问题,也不用考虑数据库迁移的问题,ORM都帮我们做了优化且支持多种数据库,这极大地提升了我们的开发效率,下面就让我们来详细学习ORM的使用吧

    二 、单表操作

    2.1 按步骤创建表

    2.1.1 创建django项目,新建名为app01的app,在app01的models.py中创建模型
    class Employee(models.Model): # 必须是models.Model的子类
        id=models.AutoField(primary_key=True)
    
        name=models.CharField(max_length=16)
    
        gender=models.BooleanField(default=1)
    
        birth=models.DateField()
    
        department=models.CharField(max_length=30)
    
        salary=models.DecimalField(max_digits=10,decimal_places=1)
    
    2.1.2 django的orm支持多种数据库,如果想将上述模型转为mysql数据库中的表,需要settings.py中
    # 删除注释掉原来的DATABASES配置项,新增下述配置
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql', # 使用mysql数据库
            'NAME': 'db1',          # 要连接的数据库
            'USER': 'root',         # 链接数据库的用于名
            'PASSWORD': '',         # 链接数据库的用于名                  
            'HOST': '127.0.0.1',    # mysql服务监听的ip  
            'PORT': 3306,           # mysql服务监听的端口  
            'ATOMIC_REQUEST': True, #设置为True代表同一个http请求所对应的所有sql都放在一个事务中执行 
                                    #(要么所有都成功,要么所有都失败),这是全局性的配置,如果要对某个
                                    #http请求放水(然后自定义事务),可以用non_atomic_requests修饰器 
            'OPTIONS': {
                "init_command": "SET storage_engine=INNODB", #设置创建表的存储引擎为INNODB
            }
        }
    }
    
    2.1.3 在链接mysql数据库前,必须事先创建好数据库
    mysql> create database db1; # 数据库名必须与settings.py中指定的名字对应上
    
    2.1.4 操作数据库模块配置

    其实python解释器在运行django程序时,django的orm底层操作数据库的python模块默认是mysqldb而非pymysql,然而对于解释器而言,python2.x解释器支持的操作数据库的模块是mysqldb,而python3.x解释器支持的操作数据库的模块则是pymysql,,毫无疑问,目前我们的django程序都是运行于python3.x解释器下,于是我们需要修改django的orm默认操作数据库的模块为pymysql,具体做法如下

    插图3

    2.1.5 确保配置文件settings.py中的INSTALLED_APPS中添加我们创建的app名称,django2.x与django1.x处理添加方式不同
    # django1.x版本,在下述列表中新增我们的app名字即可
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01',
        # 'app02' # 若有新增的app,依次添加即可
    ]
    
    # django2.x版本,可能会帮我们自动添加app,只是换了一种添加方式
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01.apps.App01Config', # 如果默认已经添加了,则无需重复添加
        # 'app02.apps.App02Config', # 若有新增的app,按照规律依次添加即可
    ]
    
    2.1.6 如果想打印orm转换过程中的sql,需要在settings中进行配置日志:
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }
    
    2.1.7 最后在命令行中执行两条数据库迁移命令,即可在指定的数据库db1中创建表 :
    $ python manage.py makemigrations
    $ python manage.py migrate
    
    # 注意:
    # 1、makemigrations只是生成一个数据库迁移记录的文件,而migrate才是将更改真正提交到数据库执行
    # 2、数据库迁移记录的文件存放于app01下的migrations文件夹里
    # 3、了解:使用命令python manage.py showmigrations可以查看没有执行migrate的文件
    

    注意1:在使用的是django1.x版本时,如果报如下错误

    django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required; you have 0.7.11.None
    

    那是因为MySQLclient目前只支持到python3.4,如果使用的更高版本的python,需要找到文件C:ProgramsPythonPython36-32Libsite-packagesDjango-2.0-py3.6.eggdjangodbackendsmysql
    这个路径里的文件

    # 注释下述两行内容即可
    if version < (1, 3, 3):
         raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
    

    注意2:当我们直接去数据库里查看生成的表时,会发现数据库中的表与orm规定的并不一致,这完全是正常的,事实上,orm的字段约束就是不会全部体现在数据库的表中,比如我们为字段gender设置的默认值default=1,去数据库中查看会发现该字段的default部分为null

    mysql> desc app01_employee; # 数据库中标签前会带有前缀app01_
    +------------+---------------+------+-----+---------+----------------+
    | Field      | Type          | Null | Key | Default | Extra          |
    +------------+---------------+------+-----+---------+----------------+
    | id         | int(11)       | NO   | PRI | NULL    | auto_increment |
    | name       | varchar(16)   | NO   |     | NULL    |                |
    | gender     | tinyint(1)    | NO   |     | NULL    |                |
    | birth      | date          | NO   |     | NULL    |                |
    | department | varchar(30)   | NO   |     | NULL    |                |
    | salary     | decimal(10,1) | NO   |     | NULL    |                |
    +------------+---------------+------+-----+---------+----------------+
    

    虽然数据库没有增加默认值,但是我们在使用orm插入值时,完全为gender字段插入空,orm会按照自己的约束将空转换成默认值后,再提交给数据库执行

    2.1.8 在表生成之后,如果需要增加、删除、修改表中字段,需要这么做

    1.增加字段

    • 在模型类Employee里直接新增字段,强调:对于orm来说,新增的字段必须用default指定默认值
      publish = models.CharField(max_length=12,default='人民出版社',null=True)
    • 重新执行那两条数据库迁移命令

    2.删除字段

    • 直接注释掉字段
    • 重新执行那两条数据库迁移命令

    3.修改字段

    • 将模型类中字段修改
    • 重新执行那两条数据库迁移命令

    2.2 添加记录

    方式一:

    • 用模型类创建一个对象,一个对象对应数据库表中的一条记录
      obj = Employee(name="json", gender=0, birth='1997-01-27', department="财务部", salary=100.1)
    • 调用对象下的save方法,即可以将一条记录插入数据库
    • obj.save()

    方式二:

    • 每个模型表下都有一个objects管理器,用于对该表中的记录进行增删改查操作,其中增加操作如下所示
    • obj = Employee.objects.create(name="Egon", gender=0, birth='1997-01-27', department="财务部", salary=100.1)

    2.3 查询记录

    2.3.1 查询API

    模型Employee对应表app01_employee,表app01_employee中的每条记录都对应类Employee的一个对象,我们以该表为例,来介绍查询API,读者可以自行添加下述记录,然后配置url、编写视图测试下述API

    mysql> select * from app01_employee;
    +----+-------+--------+------------+------------+--------+
    | id | name  | gender | birth      | department | salary |
    +----+-------+--------+------------+------------+--------+
    |  1 | Egon  |      0 | 1997-01-27 | 财务部     |  100.1 |
    |  2 | Kevin |      1 | 1998-02-27 | 技术部     |   10.1 |
    |  3 | Lili  |      0 | 1990-02-27 | 运营部     |   20.1 |
    |  4 | Tom   |      1 | 1991-02-27 | 运营部     |   30.1 |
    |  5 | Jack  |      1 | 1992-02-27 | 技术部     |   11.2 |
    |  6 | Robin |      1 | 1988-02-27 | 技术部     |  200.3 |
    |  7 | Rose  |      0 | 1989-02-27 | 财务部     |   35.1 |
    |  8 | Egon  |      0 | 1997-01-27 | 财务部     |  100.1 |
    |  9 | Egon  |      0 | 1997-01-27 | 财务部     |  100.1 |
    +----+-------+--------+------------+------------+--------+
    

    每个模型表下都有一个objects管理器,用于对该表中的记录进行增删改查操作,其中查询操作如下所示

    Part1:

    !!!强调!!!:下述方法(除了count外)的返回值都是一个模型类Employee的对象,为了后续描述方便,我们统一将模型类的对象称为"记录对象",每一个”记录对象“都唯一对应表中的一条记录,

    # 1. get(**kwargs)
    # 1.1: 有参,参数为筛选条件
    # 1.2: 返回值为一个符合筛选条件的记录对象(有且只有一个),如果符合筛选条件的对象超过一个或者没有都会抛出错误。
    obj=Employee.objects.get(id=1)
    print(obj.name,obj.birth,obj.salary) #输出:Egon 1997-01-27 100.1
    
    # 2、first()
    # 2.1:无参
    # 2.2:返回查询出的第一个记录对象
    obj=Employee.objects.first() # 在表所有记录中取第一个
    print(obj.id,obj.name) # 输出:1 Egon
    
    # 3、last()
    # 3.1: 无参
    # 3.2: 返回查询出的最后一个记录对象
    obj = Employee.objects.last() # 在表所有记录中取最后一个
    print(obj.id, obj.name)  # 输出:9 Egon
    
    # 4、count():
    # 4.1:无参
    # 4.2:返回包含记录对象的总数量
    res = Employee.objects.count() # 统计表所有记录的个数
    print(res) # 输出:9
    
    # 注意:如果我们直接打印Employee的对象将没有任何有用的提示信息,我们可以在模型类中定义__str__来进行定制
    class Employee(models.Model):
        ......
        # 在原有的基础上新增代码如下
        def __str__(self):
            return "<%s:%s>" %(self.id,self.name)
    # 此时我们print(obj)显示的结果就是: <本条记录中id字段的值:本条记录中name字段的值>
    

    Part2:

    !!!强调!!!:下述方法查询的结果都有可能包含多个记录对象,为了存放查询出的多个记录对象,django的ORM自定义了一种数据类型Queryeset,所以下述方法的返回值均为QuerySet类型的对象,QuerySet对象中包含了查询出的多个记录对象

    # 1、filter(**kwargs):
    # 1.1:有参,参数为过滤条件
    # 1.2:返回值为QuerySet对象,QuerySet对象中包含了符合过滤条件的多个记录对象
    queryset_res=Employee.objects.filter(department='技术部')
    # print(queryset_res) # 输出: <QuerySet [<Employee: <2:Kevin>>, <Employee: <5:Jack>>, <Employee: <6:Robin>>]>
    
    # 2、exclude(**kwargs)
    # 2.1: 有参,参数为过滤条件
    # 2.2: 返回值为QuerySet对象,QuerySet对象中包含了不符合过滤条件的多个记录对象
    queryset_res=Employee.objects.exclude(department='技术部')
    
    # 3、all()
    # 3.1:无参
    # 3.2:返回值为QuerySet对象,QuerySet对象中包含了查询出的所有记录对象
    queryset_res = Employee.objects.all() # 查询出表中所有的记录对象
    
    # 4、order_by(*field):
    # 4.1:有参,参数为排序字段,可以指定多个字段,在字段1相同的情况下,可以按照字段2进行排序,以此类推,默认升序排列,在字段前加横杆代表降序排(如"-id")
    # 4.2:返回值为QuerySet对象,QuerySet对象中包含了排序好的记录对象
    queryset_res = Employee.objects.order_by("salary","-id") # 先按照salary字段升序排,如果salary相同则按照id字段降序排
    
    # 5、values(*field)
    # 5.1:有参,参数为字段名,可以指定多个字段
    # 5.2:返回值为QuerySet对象,QuerySet对象中包含的并不是一个个的记录对象,而上多个字典,字典的key即我们传入的字段名
    queryset_res = Employee.objects.values('id','name')
    print(queryset_res) # 输出:<QuerySet [{'id': 1, 'name': 'Egon'}, {'id': 2, 'name': 'Kevin'}, ......]>
    print(queryset_res[0]['name']) # 输出:Egon
    
    # 6、values_list(*field):
    # 6.1:有参,参数为字段名,可以指定多个字段
    # 6.2:返回值为QuerySet对象,QuerySet对象中包含的并不是一个个的记录对象,而上多个小元组,字典的key即我们传入的字段名
    queryset_res = Employee.objects.values_list('id','name')
    print(queryset_res) # 输出:<QuerySet [(1, 'Egon'), (2, 'Kevin'),), ......]>
    print(queryset_res[0][1]) # 输出:Egon
    

    Part3:

    Part2中所示查询API的返回值都是QuerySet类型的对象,QuerySet类型是django ORM自定义的一种数据类型,专门用来存放查询出的多个记录对象,该类型的特殊之处在于
    1、queryset类型类似于python中的列表,支持索引操作

    # 过滤出符合条件的多个记录对象,然后存放到QuerySet对象中
    queryset_res=Employee.objects.filter(department='技术部') 
    # 按照索引从QuerySet对象中取出第一个记录对象
    obj=queryset_res[0]
    print(obj.name,obj.birth,obj.salary)
    

    2、管理器objects下的方法queryset下同样可以调用,并且django的ORM支持链式操作,于是我们可以像下面这样使用

    # 简单示范:
    res=Employee.objects.filter(gender=1).order_by('-id').values_list('id','name')
    print(res) # 输出:<QuerySet [(6, 'Robin'), (5, 'Jack'), (4, 'Tom'), (2, 'Kevin')]>
    

    Part4:

    其他查询API

    # 1、reverse():
    # 1.1:无参
    # 1.2:对排序的结果取反,返回值为QuerySet对象
    queryset_res = Employee.objects.order_by("salary", "-id").reverse()
    
    # 2、exists():
    # 2.1:无参
    # 2.2:返回值为布尔值,如果QuerySet包含数据,就返回True,否则返回False
    res = Employee.objects.filter(id=100).exists()
    print(res)  # 输出:False
    
    # 3、distinct():
    # 3.1:如果使用的是Mysql数据库,那么distinct()无需传入任何参数
    # 3.2:从values或values_list的返回结果中剔除重复的记录对象,返回值为QuerySet对象
    res = Employee.objects.filter(name='Egon').values('name', 'salary').distinct()
    print(res) # 输出:<QuerySet [{'name': 'Egon', 'salary': Decimal('100.1')}]>
    
    res1 = Employee.objects.filter(name='Egon').values_list('name', 'salary').distinct()
    print(res1) # 输出:<QuerySet [('Egon', Decimal('100.1'))]>
    

    2.3.2 基于双下划线的模糊查询

    插图4

    插图4

    2.3.3 F与Q查询

    F查询

    在上面所有的例子中,我们在进行条件过滤时,都只是用某个字段与某个具体的值做比较。如果我们要对两个字段的值做比较,那该怎么做呢?

    Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较两个不同字段的值,如下

    # 一张书籍表中包含字段:评论数commentNum、收藏数keepNum,要求查询:评论数大于收藏数的书籍
    from django.db.models import F
    Book.objects.filter(commnetNum__lt=F('keepNum'))
    

    Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作

    # 查询评论数大于收藏数2倍的书籍
    from django.db.models import F
    Book.objects.filter(commnetNum__lt=F('keepNum')*2)
    

    修改操作也可以使用F函数,比如将每一本书的价格提高30元:

    Book.objects.all().update(price=F("price")+30) 
    

    Q查询

    img

    filter() 等方法中逗号分隔开的多个关键字参数都是逻辑与(AND) 的关系。 如果我们需要使用逻辑或(OR)来连接多个条件,就用到了Django的Q对象

    可以将条件传给类Q来实例化出一个对象,Q的对象可以使用&| 操作符组合起来,&等同于and,|等同于or

    from django.db.models import Q
    Employee.objects.filter(Q(id__gt=5) | Q(name="Egon"))
    
    # 等同于sql:select * from app01_employee where id < 5 or name = 'Egon';
    

    Q 对象可以使用~ 操作符取反,相当于NOT

    from django.db.models import Q
    Employee.objects.filter(~Q(id__gt=5) | Q(name="Egon"))
    
    # 等同于sql:select * from app01_employee where not (id < 5) or name = 'Egon';
    

    当我们的过滤条件中既有or又有and,则需要混用Q对象与关键字参数,但Q 对象必须位于所有关键字参数的前面

    from django.db.models import Q
    Employee.objects.filter(Q(id__gt=5) | Q(name="Egon"),salary__lt=100)
    
    # 等同于sql:select * from app01_employee where (id < 5 or name = 'Egon') and salary < 100;
    

    1554205249918

    2.3.4 聚合查询

    聚合查询aggregate()是把所有查询出的记录对象整体当做一个组,我们可以搭配聚合函数来对整体进行一个聚合操作

    from django.db.models import Avg, Max, Sum, Min, Max, Count # 导入聚合函数
    
    # 1. 调用objects下的aggregate()方法,会把表中所有记录对象整体当做一组进行聚合
    res1=Employee.objects.aggregate(Avg("salary")) # select avg(salary) as salary__avg from app01_employee;
    print(res1) # 输出:{'salary__avg': 70.73}
    
    # 2、aggregate()会把QuerySet对象中包含的所有记录对象当成一组进行聚合
    res2=Employee.objects.all().aggregate(Avg("salary")) # select avg(salary) as salary__avg from app01_employee;
    print(res2) # 输出:{'salary__avg': 70.73}
    
    res3=Employee.objects.filter(id__gt=3).aggregate(Avg("salary")) # select avg(salary) as salary__avg from app01_employee where id > 3;
    print(res3) # 输出:{'salary__avg': 71.0}
    

    aggregate()的返回值为字典类型,字典的key是由”聚合字段的名称___聚合函数的名称”合成的,例如

    Avg("salary") 合成的名字为 'salary__avg'
    

    若我们想定制字典的key名,我们可以指定关键参数,如下

    res1=Employee.objects.all().aggregate(avg_sal=Avg('salary')) # select avg(salary) as avg_sal from app01_employee;
    
    print(res1) # 输出:{'avg_sal': 70.73} # 关键字参数名就会被当做字典的key
    

    如果我们想得到多个聚合结果,那就需要为aggregate传入多个参数

    res1=Employee.objects.all().aggregate(nums=Count('id'),avg_sal=Avg('salary'),max_sal=Max('salary')) 
    # 相当于SQL:select count(id) as nums,avg(salary) as avg_sal,max(salary) as max_sal from app01_employee;
    
    print(res1) # 输出:{'nums': 10, 'avg_sal': 70.73, 'max_sal': Decimal('200.3')}
    

    2.3.5 分组查询

    分组查询annotate()相当于sql语句中的group by,是在分组后,对每个组进行单独的聚合,需要强调的是,在进行单表查询时,annotate()必须搭配values()使用:values("分组字段").annotate(聚合函数),如下

    # 表中记录
    mysql> select * from app01_employee;
    +----+-------+--------+------------+------------+--------+
    | id | name  | gender | birth      | department | salary |
    +----+-------+--------+------------+------------+--------+
    |  1 | Egon  |      0 | 1997-01-27 | 财务部     |  100.1 |
    |  2 | Kevin |      1 | 1998-02-27 | 技术部     |   10.1 |
    |  3 | Lili  |      0 | 1990-02-27 | 运营部     |   20.1 |
    |  4 | Tom   |      1 | 1991-02-27 | 运营部     |   30.1 |
    |  5 | Jack  |      1 | 1992-02-27 | 技术部     |   11.2 |
    |  6 | Robin |      1 | 1988-02-27 | 技术部     |  200.3 |
    |  7 | Rose  |      0 | 1989-02-27 | 财务部     |   35.1 |
    +----+-------+--------+------------+------------+--------+
    
    # 查询每个部门下的员工数
    res=Employee.objects.values('department').annotate(num=Count('id')) 
    # 相当于sql:
    # select department,count(id) as num from app01_employee group by department;
    
    print(res) 
    # 输出:<QuerySet [{'department': '财务部', 'num': 2}, {'department': '技术部', 'num': 3}, {'department': '运营部', 'num': 2}]>
    

    跟在annotate前的values方法,是用来指定分组字段(因为values是获取条件中那个字段的结果,然后在进行排序),即group by后的字段,而跟在annotate后的values方法,则是用来指定分组后要查询的字段,即select 后跟的字段

    res=Employee.objects.values('department').annotate(num=Count('id')).values('num')
    # 相当于sql:
    # select count(id) as num from app01_employee group by department;
    
    print(res)
    # 输出:<QuerySet [{'num': 2}, {'num': 3}, {'num': 2}]>
    

    跟在annotate前的filter方法表示where条件,跟在annotate后的filter方法表示having条件,如下

    # 查询男员工数超过2人的部门名
    res=Employee.objects.filter(gender=1).values('department').annotate(male_count=Count("id")).filter(male_count__gt=2).values('department')
    
    print(res) # 输出:<QuerySet [{'department': '技术部'}]>
    
    # 解析:
    # 1、跟在annotate前的filter(gender=1) 相当于 where gender = 1,先过滤出所有男员工信息
    # 2、values('department').annotate(male_count=Count("id")) 相当于group by department,对过滤出的男员工按照部门分组,然后聚合出每个部门内的男员工数赋值给字段male_count
    # 3、跟在annotate后的filter(male_count__gt=2) 相当于 having male_count > 2,会过滤出男员工数超过2人的部门
    # 4、最后的values('department')代表从最终的结果中只取部门名
    

    总结:

    1、values()在annotate()前表示group by的字段,在后表示取值
    1、filter()在annotate()前表示where条件,在后表示having
    

    需要注意的是,如果我们在annotate前没有指定values(),那默认用表中的id字段作为分组依据,而id各不相同,如此分组是没有意义的,如下

    res=Employee.objects.annotate(Count('name')) # 每条记录都是一个分组
    res=Employee.objects.all().annotate(Count('name')) # 同上
    

    2.4 修改记录

    2.5.1 直接修改单条记录

    可以修改记录对象属性的值,然后执行save方法从而完成对单条记录的直接修改

    # 1、获取记录对象
    obj=Employee.objects.filter(name='Egon')[0]
    # 2、修改记录对象属性的值
    obj.name='EGON'
    obj.gender=1
    # 3、重新保存
    obj.save()
    

    2.5.2 修改QuerySet中的所有记录对象

    QuerySet对象下的update()方法可以更QuerySet中包含的所有对象,该方法会返回一个整型数值,表示受影响的记录条数(相当于sql语句执行结果的rows)

    queryset_obj=Employee.objects.filter(id__gt=5)
    rows=queryset_obj.update(name='EGON',gender=1)
    

    2.5 删除记录

    img

    2.5.1 直接删除单条记录

    可以直接调用记录对象下的delete方法,该方法运行时立即删除本条记录而不返回任何值,如下

    obj=Employee.objects.first()
    obj.delete()
    

    2.5.2 删除QuerySet中的所有记录对象

    每个 QuerySet下也都有一个 delete() 方法,它一次性删除 QuerySet 中所有的对象(如果QuerySet对象中只有一个记录对象,那也就只删一条),如下

    queryset_obj=Employee.objects.filter(id__gt=5)
    rows=queryset_obj.delete()
    

    需要强调的是管理objects下并没有delete方法,这是一种保护机制,是为了避免意外地调用 Employee.objects.delete() 方法导致所有的记录被误删除从而跑路。但如果你确认要删除所有的记录,那么你必须显式地调用管理器下的all方法,拿到一个QuerySet对象后才能调用delete方法删除所有

    Employee.objects.all().delete()
    
    在当下的阶段,必将由程序员来主导,甚至比以往更甚。
  • 相关阅读:
    C. Shaass and Lights 解析(思維、組合)
    D. Binary String To Subsequences(队列)(贪心)
    CodeForces 1384B2. Koa and the Beach (Hard Version)(贪心)
    CodeForces 1384B1. Koa and the Beach (Easy Version)(搜索)
    CodeForces 1384C. String Transformation 1(贪心)(并查集)
    CodeForces 1384A. Common Prefixes
    POJ-2516 Minimum Cost(最小费用最大流)
    POJ3261-Milk Patterns(后缀数组)
    HDU-1300 Pearls(斜率DP)
    HDU-4528 小明系列故事-捉迷藏(BFS)
  • 原文地址:https://www.cnblogs.com/randysun/p/11747428.html
Copyright © 2020-2023  润新知