模型(二)

在第一部分中,主要是关于如何创建更好数据模型用来存储数据。而在django中,还有一个部分也很重要。那就是关于提取和使用数据,而这就涉及到这些模型类的方法。

参考资料:https://docs.djangoproject.com/zh-hans/2.0/topics/db/queries/

一旦建立好数据模型之后,django会自动给你一个数据库抽象api来让你创建、撤回、更新和删除这些对象。

范例

from django.db import models

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=200)
    email = models.EmailField()

    def __str__(self):
        return self.name

class Entry(models.Model):
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
    headline = models.CharField(max_length=255)
    body_text = models.TextField()
    pub_date = models.DateField()
    mod_date = models.DateField()
    authors = models.ManyToManyField(Author)
    n_comments = models.IntegerField()
    n_pingbacks = models.IntegerField()
    rating = models.IntegerField()

    def __str__(self):
        return self.headline

一、创建对象

使用save()方法

只有执行了save()方法,所有对对象做的操作才会保存到数据库层次。

使用create()可以完成创建和保存的操作。

二、修改对象

1、普通字段类型

同样使用save()方法

2、外键字段

外键与普通的完全一致

哇,还真的是很简单呢

3、多对多类型的字段

之前也提到过,普通的方法不适用于使用了关系表的多对多模型,但是这里好像还是可以使用add方法,是不是因为没有使用关系表呢?确实没有!

三、检索对象

为了检索对象,需要通过Manager构造QuerySet。一个QuerySet代表着多个数据库记录的对象,他可以有零个或多个筛选条件,类似于sql中的select语句。

QuerySet是通过manager得到的,每一个模型至少有一个Manager,默认为objects。

Manger是模型QuerySet的主要来源,比如Blog.objects.all(),这个会返回所有Blog模型中的对象。

1、检索所有对象

2、检索特定对象

两种方式:

  • filter(**kwargs):返回所有符合条件的对象

  • exclude(**kwargs):返回所有不符合条件 对象

示例:

我终于明白了。前面的是模型中的字段,而双下划线后面的是这个字段的属性!慢着,不是还有一个get吗?

这是错误的理解。

3、链式筛选

这个可能跟我们想的不一样。。。

4、懒惰的QuerySet

大部分queryset筛选操作不会涉及到数据库,如下

1、gt:大于某个时间

now = datetime.datetime.now()

#前一天

start = now – datetime.timedelta(hours=23, minutes=59, seconds=59)

a=yourobject.objects .filter(youdatetimcolumn__gt=start)

2、gte:大于等于某个时间:

a=yourobject.objects .filter(youdatetimcolumn__gte=start)

3、lt:小于

a=yourobject.objects .filter(youdatetimcolumn__lt=start)

4、lte:小于等于

a=yourobject.objects .filter(youdatetimcolumn__lte=start)

5、range:查询时间段

start_date = datetime.date(2005, 1, 1)

end_date = datetime.date(2005, 3, 31)

Entry.objects.filter(pub_date__range=(start_date, end_date))

qs.filter(name__contains="e")

qs.filter(name__icontains="e")

对应sql

'contains': 'LIKE BINARY %s', 其中的BINARY是 精确大小写

'icontains': 'LIKE %s', 而’icontains’中的’i’表示忽略大小写

其中只有最后一步print涉及到数据库,

5、用get获取单个对象

filter永远都会返回一个QuerySet,即使只有一个符合条件的对象。而get()方法可以保证回复一个对象

值得注意的是,符合筛选条件的对象只能有一个,如果没有或者多个,都会导致报错。

Note that there is a difference between using get(), and using filter() with a slice of [0].

这是什么意思?

6、其他的查询方式

除了get、all、filter、exclude等,django中还有很多很多查询方式。

7、使用分片限制查询结果

一般来说,切片不会影响原本的查询结果,但是有一个例外,那就是使用跳步的方式切片,这样的话query中会 修改部分来得到这个结果

然后这个分片只能执行一次,为了避免歧义。

四、字段查询

基本的格式是field__lookuptype=value

一般来说,查询的字段名必须与模型属性名一致,但是有一个例外情况,那就是外键,它可以以id为后缀,但是也只能在主键没有设置,默认为id的情况下才可以吧?

1、exact

当然这也是默认的情况,如果不加后面的exact,直接相等也是一样的

2、iexact

忽略大小写

3、contains

也就是匹配包含这个字符串的

icontains忽略大小写

4、startswith,endwith

之前我以为是调用的是字符串的方法,但是看到这里才知道不是。

istartwith, iendwith忽略大小写

五、跨关系查找

django这种跨关系查找的功能确实很让人吃惊。

上面的例子是沿着外键去查外键连接的数据表,django甚至还可以反过来查询,这时只需要把表名小写放在前面即可。

如果全部查完之后,没有找到一个值,django也不会报错,只是返回空的对象。哪怕查的字段在表中都不存在(假如headline不存在entry),也不会报错。

1、多值查询

先看两个例子

我之前一直以为第二个是指同时满足两个条件的查询,但现在看起来并不是,方式一才是同时满足两个条件查询,而方式是指满足条件一和满足条件二的结果的返回。那假如我把满足条件一的queryset保存为q,再对q做filter操作,那算是什么呢?应该是在q的结果中继续筛选吧?

2、比较操作

有时候我们并不是想直接与一个常量比较,而希望跟同一个模型中的另一个字段的值作比较,这s时候可以使用F expression

或者

靠,居然还支持位操作!

3、pk快速查找

pk也就是primary key,使用pk快速查找可以实现快速查找对象

4、缓存queryset

每当新建一个queryset的时候,缓存其实是空的,当它真的查询数据库的时候,才会将结果缓存起来。

如果这样操作的话,会进行两次数据库的查询,因为是两次,所以在这期间,数据库可能会被修改,也因此,对应的数据可能会发生改变。

为了避免上面的情况,保证取出的数据是同一个数据,这时候就可以执行缓存。

5、使用Q来实现复杂的查询

之前的查询主要用到的查询条件是“and”,如果需要使用其他的查询条件的话,可以使用Q 对象。

目前我看到就是可以使用or,应该还有很多类型。

六、删除对象

简单使用实例对象的delete方法即可

这里值得注意的是,如果你已经自定义了delete方法,就不能使用第二方方法来删除多个实例对象,只能通过循环一个一个地调用实例对象的delete方法来实现。还有就是,django默认的是ON DELETE CASCADE,也就是说当在数据库中删除一个记录时,它会自动删除所有连接到它的外键记录。而这个可以在设置外键的时候修改。

同时,delete也是唯一一个queryset有但是manager没有的方法,这是为了避免意外删除所有对象,如果想要删除全部的对象,可以

七、一次更新多个对象

使用update()方法

只有非关系型字段和外键字段可以使用这个方法,如果是菲关系型,就设置为对应的数据类型常量即可,如果是外键,可以设置为某个模型的实例。这个方法会返回修改的记录数。唯一一个麻烦一点的是一个模型的主键,等会

The only restriction on the QuerySet being updated is that it can only access one database table: the model's main table. You can filter based on related fields, but you can only update columns in the model's main table.

不对吧,前面的pub_date并不是主键啊,为什么它说只能通过主键才能找到?而且主键往往是唯一值,也不可能对应多个值,这样update不就没有意义了吗?

这里并不是主键,看一下例子就明白了,是外键的问题

当它想要找所有外键连接到某个特定的记录时,才会用这就related的方式。

另外,update不需要save,它会直接执行到数据库上。

八、相关对象或者反转manager

相关对象的额外操作

Last updated

Was this helpful?