当前位置: 首页 > 科技观察

每日一技能:用Python实现链式调用_0

时间:2023-03-17 21:49:58 科技观察

我们在使用Django模型查询数据库时,可以看到这样的写法:formapp.modelsimportXXXquery=XXX.objects.all()query=query.filter(name=123,age=456).filter(salary=999)在这个写法中,查询对象有一个filter方法,这个方法返回的数据可以继续调用filter方法,可以无限调用。这种写法是如何实现的呢?如果我们直接写一个类的方法,看看能不能这样调用:classQuery:deffilter(self):passquery=Query()query.filter().filter()直接查询。如果filter()返回的结果再次调用filter,会报错。这是因为当没有显式写return语句时,方法会返回None,而None对象没有所谓的filter方法。那么什么有过滤方法呢?显然我们的查询对象有一个过滤方法。那么如何让这个方法返回自己的对象呢?这时候我们就不得不看一下我们在定义类方法的时候总是写的第一个参数self。几乎每个类方法都会有它在里面。大家只知道在类中调用类方法时可以使用self.xxx(),调用类属性时可以使用self.yy。你有没有想过如果单独使用这个东西会发生什么?其实self指的是类实例化为对象后的对象本身。而这个对象显然有一个过滤方法。那么我们修改一下filter方法,返回self:classQuery:deffilter(self):returnsselfquery=Query()query.filter().filter()从图中可以看出,现在不会报错了。那么回到最初的问题,Django中的链式调用是如何实现传入查询参数的呢?其实这就涉及到一个惰性查询的问题。当我们不断调用.filter()方法时,Django会缓存所有的查询条件。只有当我们需要获取结果,或者查询有多少条数据满足条件的时候,它才会真正连接数据库进行查询。所以这里我们要模拟这个环境,缓存查询条件。那么为了获取调用方法时传入的参数名,我们需要使用**kwargs参数。这个参数可以接受所有key=value形式的参数:()a=query.filter(name='kingname').filter(age__gt=15,address='yyyyyy').filter(salary=99999)print(query.query_condition)运行效果如下图所示:当真正需要输出结果时,再使用这些缓存的条件去数据库中查询结果。