模型(二)
在第一部分中,主要是关于如何创建更好数据模型用来存储数据。而在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?