【python版】leanCloud的使用
参考
文章目录
通过凭证连接leanCloud
先配置leanCloud环境
pip install leancloud
首先进入 云服务控制台 > 设置 > 应用凭证,来获取 App ID,App Key 以及服务器地址,接着导入 leancloud
,并调用 init
方法进行初始化:
# 参考 https://leancloud.cn/docs/sdk_setup-python.html, https://leancloud.github.io/python-sdk/
import leancloud
appId = 'Your appId'
appKey = 'Your appKey'
masterkey = "Your masterkey"
'''初始化'''
# lean_initialization = leancloud.init(appId, appKey)
lean_initialization = leancloud.init(appId, master_key=masterkey)
print(lean_initialization) #None
'''开启调试日志'''
# 调试日志开启后,SDK 会把网络请求、错误消息等信息输出到 IDE 的日志窗口,
# 或是浏览器 Console 或是云引擎日志(如果在云引擎下运行 SDK)。
import logging
logging.basicConfig(level=logging.DEBUG)
'''验证'''
TestObject = leancloud.Object.extend('TestObject') #派生一个新的 leancloud.Object 子类 TestObject
test_object = TestObject()
test_object.set('words', "Hello world!") #在当前对象此字段(words)上赋值(Hello world!)
test_object.save() #将对象数据保存至服务器
leanCloud的免费数据存储空间为1G,每天的API请求数 < 3万次,支持三个客户端同时在线
leanCloud对象(Object)
1、数据类型
- leancloud.Object 支持的数据类型包括 String、Number、Boolean、Object、Array、Date 等等。你可以通过嵌套的方式在 Object 或 Array 里面存储更加结构化的数据。
- leancloud.Object 还支持两种特殊的数据类型 Pointer 和 File,可以分别用来存储指向其他 leancloud.Object 的指针以及二进制数据。
- leancloud.Object 同时支持 GeoPoint,可以用来存储地理位置信息。参见 GeoPoint。
bool = True
number = 2018
string = 'Top Hit Songs'
date = datetime.now()
list = [string, number]
dictionary = {
'number': number,
'string': string
}
比如对于下面这个对象信息,每个字段有着自己的数据类型:
2、构建并保存对象
构建对象:
- 在构建对象时,为了使云端知道对象属于哪个 class,需要将 class 的名字作为参数传入。
- 你可以将云服务里面的 class 比作关系型数据库里面的表。一个 class 的名字必须以字母开头,且只能包含数字、字母和下划线。
保存对象:
-
以下是一些对象的内置属性,会在对象保存时自动创建,无需手动指定:
内置属性 类型 描述 objectId str 该对象唯一的 ID 标识 ACL leancloud.ACL 该对象的权限控制,实际上是一个 JSON 对象,控制台做了展现优化。 createdAt datetime.datetime 该对象被创建的时间。 updatedAt datetime.datetime 该对象最后一次被修改的时间。 -
我们不推荐通过 byte[] 在 leancloud.Object 里面存储图片、文档等大型二进制数据。
每个 leancloud.Object 的大小不应超过 128 KB。如需存储大型文件,可创建 leancloud.File 实例并将将其关联到 leancloud.Object 的某个属性上。
代码整合如下:
class MyTest(unittest.TestCase):
''''''
'''构建并保存对象'''
def test_objectConstruct(self):
''''''
'''
Step3: 构建对象
'''
LoginUser = leancloud.Object.extend('LoginUser') # 创建一个Object类((感觉)类似于rpc远程调用类对象,包装成代理类)
loginUser = LoginUser() # 实例化对象
'''
Step4: 保存对象
'''
loginUser.set("name", "wangxiaoxi") # 为字段user赋值为wangxiaoxi
loginUser.set("age", 25)
loginUser.set("sex", "male")
loginUser.set("marriaged", False)
loginUser.save() # 将对象数据保存至服务器
创建的LoginUser用户信息如下:
json格式如下(下面我都用json来展示数据效果):
3、获取对象(从创建到获取有时延)
通过objectId获取云端leanCloud对象,这里我们可以通过下面代码观察leanCloud对象各字段的返回类型。
还有要注意一点,对象从创建到获取存在时延,因此并不适合于实时性较强的任务,但可适用于即时通讯或者多人游戏作战。
'''获取对象'''
def test_getObject(self):
'''
Step5: 获取对象
通过objectId获取云端leanCloud对象
'''
loginUser = leancloud.Object.extend('LoginUser')
query = loginUser.query
loginUser = query.get('62891f57033caa54ba63b1d6')
# loginUser 就是 objectId 为 6288fda75e07a13788dcdbfd 的 LoginUser 实例
name = loginUser.get('name')
age = loginUser.get('age')
sex = loginUser.get('sex')
marriaged = loginUser.get('marriaged')
# 获取内置属性
object_id = loginUser.id
update_at = loginUser.updated_at
created_at = loginUser.created_at
print(f"name = {name}, type = {type(name)}")
print(f"age = {age}, type = {type(age)}")
print(f"sex = {sex}, type = {type(sex)}")
print(f"marriaged = {marriaged}, type = {type(marriaged)}")
print(f"object_id = {object_id}, type = {type(object_id)}")
print(f"update_at = {update_at}, type = {type(update_at)}")
print(f"created_at = {created_at}, type = {type(created_at)}")
输出结果:
name = wangxiaoxi, type = <class 'str'>
age = 25, type = <class 'int'>
sex = male, type = <class 'str'>
marriaged = False, type = <class 'bool'>
object_id = 62891f57033caa54ba63b1d6, type = <class 'str'>
update_at = 2022-05-22 01:20:23.447000+08:00, type = <class 'datetime.datetime'>
created_at = 2022-05-22 01:20:23.447000+08:00, type = <class 'datetime.datetime'>
4、同步对象
'''同步对象'''
def test_synchronize_object(self):
LoginUser = leancloud.Object.extend('LoginUser')
loginUser = LoginUser.create_without_data('62891f57033caa54ba63b1d6') #创建只封装ObjectId的对象
loginUser.fetch() #同步对象
print(f'name = {loginUser.get("name")}')
print(f'marriaged = {loginUser.get("marriaged")}')
输出结果:
name = wangxiaoxi
Ran 1 test in 0.264s
OK
marriaged = False
5、更新对象(可以创建新字段)
云服务会自动识别需要更新的属性并将对应的数据发往云端,未更新的属性会保持原样
'''更新对象'''
def test_update_object(self):
''''''
LoginUser = leancloud.Object.extend('LoginUser')
loginUser = LoginUser.create_without_data('62891f57033caa54ba63b1d6') #创建只封装ObjectId的对象
loginUser.set('marriaged', True) #修改原有字段
loginUser.set('balance', 1000) #增加余额字段,余额1000元
loginUser.set('friends', ['Ben']) #增加friends字段,初始朋友有[Ben]
loginUser.save()
以json格式保存的数据如下:
6、有条件更新对象(带where条件的save)
-
通过传入 query 选项,可以按照指定条件去更新对象——当条件满足时,执行更新(save);条件不满足时,不执行更新并返回 305 错误。
-
在统计一条微博的点赞转发次数时,由于赞和转发的操作可能由多个客户端同时进行,直接在本地更新数字并保存到云端的做法极有可能导致差错。为保证计数的准确性,可以通过 原子操作 来增加或减少一个属性内保存的数字(此过程并没有更新到云端):
loginUser.increment('balance', amount)
-
注意,虽然原子增减支持浮点数,但因为底层数据库的浮点数存储格式限制,会有舍入误差。
因此,需要原子增减的字段建议使用整数以避免误差,例如 3.14 可以存储为 314,然后在客户端进行相应的转换。
否则,以比较大小为条件查询对象的时候,需要特殊处理, < a 需改查 < a + e,> a 需改查 > a - e,== a 需改查 > a - e 且 < a + e,其中 e 为误差范围,据所需精度取值,比如 0.0001。
-
在使用query创建where条件**时,要注意的是:
query 选项只对已存在的对象有效,不适用于尚未存入云端的对象。
当多个客户端需要更新同一属性,相比于通过 leancloud.Query 查询 leancloud.Object 再对其进行更新的方法,这样做更加简洁,并且能够避免出现差错。 -
一开始想用多线程来模拟多个客户端进行余额支出操作的,但是官网说:
leancloud.Object 目前不是线程安全的,因此请避免多个线程修改同一个 leancloud.Object 实例的操作。如果遇到必须多线程操作的情况,需要根据情况加锁。
具体代码如下:
def test_update_object_withCondition(self):
'''
通过传入 query 选项,可以按照指定条件去更新对象——当条件满足时,执行更新;条件不满足时,不执行更新并返回 305 错误。
'''
LoginUser = leancloud.Object.extend("LoginUser")
loginUser = LoginUser.create_without_data('6288fda75e07a13788dcdbfd') #创建只封装ObjectId的对象
# print(f'name = {loginUser.get("name")}') #None
# print(f'marriaged = {loginUser.get("marriaged")}') #None
amount = -300 # 支出300元
loginUser.increment('balance', amount) # 更新计时器,该操作 为原子操作
# 设置条件:只有当查询的balance比消费金额大时,才可以完成消费
where = loginUser.query.greater_than_or_equal_to('balance', -amount)
'''
@object.query
'''
# 操作结束后,返回最新数据。
# 如果是新对象,则所有属性都会被返回,
# 否则只有更新的属性会被返回。
loginUser.fetch_when_save = True
try:
loginUser.save(where=where) #在保存对象前加入条件
print('当前余额为:', loginUser.get('balance'))
except leancloud.LeanCloudError as e:
if e.code == 305:
print('余额不足,操作失败!')
else:
raise
数据修改如下:
7、更新数组
更新数组也是原子操作。使用以下方法可以方便地维护数组类型的数据
- add(): 将指定对象附加到数组末尾。
- add_unique(): 如果数组中不包含指定对象,则将该对象加入数组。对象的插入位置是随机的。
- remove(): 从数组字段中删除指定对象的所有实例。
'''更新数组'''
def test_update_array(self):
# 更新数组也是原子操作。使用以下方法可以方便地维护数组类型的数据
friend1 = "Sarah"
friend2 = "Lily"
friend3 = "Lala"
'''
add(): 将指定对象附加到数组末尾
add_unique(): 如果数组中不包含指定对象,则将该对象加入数组。对象的插入位置是随机的
remove(): 从数组字段中删除指定对象的所有实例
'''
LoginUser = leancloud.Object.extend("LoginUser")
loginUser = LoginUser.create_without_data('62891f57033caa54ba63b1d6')
loginUser.add_unique('friends', friend1)
loginUser.add_unique('friends', friend2)
loginUser.add_unique('friends', friend3)
loginUser.save()
效果如下:
8、删除对象
'''删除对象'''
def test_delete_object(self):
LoginUser = leancloud.Object.extend('LoginUser')
loginUser = LoginUser.create_without_data('62891f57033caa54ba63b1d6')
loginUser.destroy()
9、批量操作
1)批量保存
leancloud.Object.save_all(list_of_objects)
'''批量save操作'''
def test_batch_save(self):
''''''
LoginUser = leancloud.Object.extend("LoginUser")
loginUser1 = LoginUser()
loginUser2 = LoginUser()
loginUser3 = LoginUser()
loginUser1.set("name","Ben")
loginUser2.set("name","Sarah")
loginUser3.set("name","Lily")
LoginUser.save_all([loginUser1,loginUser2,loginUser3])
2)批量删除
leancloud.Object.destroy_all(list_of_objects)
'''批量save操作'''
def test_batch_destroy(self):
''''''
LoginUser = leancloud.Object.extend("LoginUser")
loginUser1 = LoginUser.create_without_data("62890fec033caa54ba63ae7a")
loginUser2 = LoginUser.create_without_data("62890fec033caa54ba63ae79")
loginUser3 = LoginUser.create_without_data("62890fec033caa54ba63ae78")
LoginUser.destroy_all([loginUser1, loginUser2, loginUser3])
10、对象关系
1)一对一、一对多关系
- 一对一、一对多关系可以通过将 leancloud.Object 保存为另一个对象的属性值的方式产生。比如说,让博客应用中的一个 Comment 指向一个 Post (comment和post为多对一的关系)
- 关于一对多数据的删除:并不需要进行级联删除,即如果删除掉post之后,comment虽然有Point属性指向该post,但是不会被删除。
'''数据类型:一对一,一对多关系'''
def test_relation1(self):
''''''
'''
一对一、一对多关系可以通过将 leancloud.Object 保存为另一个对象的属性值的方式产生。
比如说,让博客应用中的一个 Comment 指向一个 Post (comment和post为多对一的关系)。
'''
# 创建 post
Post = leancloud.Object.extend('Post')
post = Post()
post.set('title', '饿了……')
post.set('content', '中午去哪吃呢?')
# 创建 comment
Comment = leancloud.Object.extend('Comment')
comment = Comment()
comment1 = Comment()
comment.set('content', '当然是肯德基啦!')
comment1.set('content', '当然是必胜客啦!')
# 将 post 设为 comment 的一个属性值
comment.set('parent', post) #云端存储时,会将被指向的对象用 Pointer 的形式存起来。
comment1.set('parent', post)
# 保存 comment 会同时保存 post
# Comment.save_all([comment,comment1]) #会报错:leancloud.errors.LeanCloudError: LeanCloudError: [106] Malformed pointer. Pointers must be maps of a classname and an object id.
comment.save()
comment1.save()
多对一对象创建效果如下:
删除代码如下:
'''关于一对多数据的删除'''
def test_relation1_destroy(self):
Post = leancloud.Object.extend("Post")
post = Post.create_without_data("62892f095e07a13788dce68a")
post.destroy() #删除post之后,与其绑定的comment并没有删除
删除效果演示:
2)多对多关系
- 想要建立多对多关系,最简单的办法就是使用 数组。在大多数情况下,使用数组可以有效减少查询的次数,提升程序的运行效率。但如果有额外的属性需要附着于两个 class 之间的关联,那么使用 中间表 可能是更好的方式。
注意这里说到的额外的属性是用来描述 class 之间的关系的,而不是任何单一的 class 的。 - 我们建议你在任何一个 class 的对象数量超出 100 的时候考虑使用中间表。
leancloud.Object 目前不是线程安全的
leanCloud对象查询(Query)
下面这两种写法是一样的,都是创建关于Comment表的leanCloud.query.Query对象
#写法1
query = leanCloud.Query("Comment")
#写法2
Comment = leanCloud.Object.extend("Comment")
query = Comment.query()
创建***Object.query()查询对象,用query.equal_to()等设置查询条件,用find()***进行查询
假设现在的LoginUser数据是这样的,共7条:
Comment数据,Post数据分别如下:
Comment:
Post:
1、基础查询
- 构建 leancloud.Query;
- 向其添加查询条件;
- 执行查询并获取包含满足条件的对象的数组。
def repr(loginUser):
print(f'loginUser:id = {loginUser.get("objectId")}, '
f'name = {loginUser.get("name")}, '
f'age = {loginUser.get("age")}, '
f'marriaged = {loginUser.get("marriaged")}, '
f'balance = {loginUser.get("balance")}, '
f'friends = {loginUser.get("friends")}')
class MyTest(unittest.TestCase):
'''基础查询'''
def test_basic_query(self):
''''''
'''
基础查询: 创建Object.query查询对象,用equal_to设置查询条件,用find进行查询
构建 leancloud.Query;
向其添加查询条件;
执行查询并获取包含满足条件的对象的数组。
'''
LoginUser = leancloud.Object.extend('LoginUser')
query = LoginUser.query
# 以上两行等价于 query = leancloud.Query('Student')
query.equal_to('name', 'wangxiaoxi')
loginUser_list = query.find()
for loginUser in loginUser_list:
repr(loginUser)
输出结果如下:
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True
loginUser:id = 6289e839033caa54ba63d5f3, name = wangxiaoxi, age = 25, marriaged = False
loginUser:id = 6289e83b033caa54ba63d5f5, name = wangxiaoxi, age = 25, marriaged = False
2、按条件查询
1)基本条件查询
-
not_equal_to: 不等于
-
less_than: 小于
-
less_than_or_equal_to: 不大于
-
greater_than: 大于
-
greater_than_or_equal_to: 不小于
2)设置多条件
在同一个查询中设置多个条件,这样可以获取满足所有条件的结果。可以理解为所有的条件是 AND 的关系。
LoginUser = leancloud.Object.extend("LoginUser")
query = LoginUser.query
query.equal_to("name", 'wangxiaoxi')
query.equal_to('marriaged', True) #已经结婚
query.greater_than_or_equal_to('balance', 1000) #存款大于1000
print(repr(query.first()))
输出结果:
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True, balance = 1000
3)获取n条结果(limit)
由于性能原因,limit 最大只能设为 1000。即使将其设为大于 1000 的数,云端也只会返回 1,000 条结果。
#最多获取2条结果
query = leancloud.Query("LoginUser")
query.limit(2)
loginUsers = query.find()
print("limit find: ")
for loginUser in loginUsers:
repr(loginUser)
输出结果:
limit find:
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True, balance = 1000
loginUser:id = 6289e839033caa54ba63d5f3, name = wanghaoxi, age = 25, marriaged = False, balance = None
4)只获得第一条结果(first)
query = leancloud.Query("LoginUser")
loginUser = query.first()
print("first find: ")
repr(loginUser)
输出结果:
first find:
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True, balance = 1000
5)跳过一定数量的结果(skip)
- 把 skip 和 limit 结合起来,就能实现翻页功能
- 需要注意的是,skip 的值越高,查询所需的时间就越长。作为替代方案,可以通过设置 createdAt 或 updatedAt 的范围来实现更高效的翻页,因为它们都自带索引。 同理,也可以通过设置自增字段的范围来实现翻页。
# 跳过前 2 条结果
query = leancloud.Query("LoginUser")
query.skip(2)
print("skip find: ")
loginUsers = query.find()
for loginUser in loginUsers:
repr(loginUser)
输出结果:
loginUser:id = 6289e83b033caa54ba63d5f5, name = wangminxi, age = 25, marriaged = False, balance = None
loginUser:id = 6289e83e033caa54ba63d5f6, name = Lily, age = 25, marriaged = False, balance = None
loginUser:id = 6289e8405e07a13788dd0ab0, name = Tom, age = 25, marriaged = False, balance = None
loginUser:id = 6289e843033caa54ba63d5f8, name = Ben, age = 25, marriaged = False, balance = None
loginUser:id = 6289e845033caa54ba63d5fa, name = Sarah, age = 25, marriaged = False, balance = None
6)按属性排序(add_descending)
可以为同一个查询添加多个排序规则:
'''
Step4: 属性排序
'''
query = leancloud.Query("LoginUser")
# # 按 createdAt 升序排列
# query.ascending('createdAt')
#
# # 按 createdAt 降序排列
# query.descending('createdAt')
'''为同一个查询添加多个排序规则;'''
query.add_ascending('marriaged')
query.add_descending('name')
loginUsers = query.find()
for loginUser in loginUsers:
repr(loginUser)
输出结果
loginUser:id = 6289e839033caa54ba63d5f3, name = wanghaoxi, age = 25, marriaged = False, balance = None
loginUser:id = 6289e845033caa54ba63d5fa, name = Sarah, age = 25, marriaged = False, balance = None
loginUser:id = 6289e83e033caa54ba63d5f6, name = Lily, age = 25, marriaged = False, balance = None
loginUser:id = 6289e843033caa54ba63d5f8, name = Ben, age = 25, marriaged = False, balance = None
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True, balance = 1000
loginUser:id = 6289e83b033caa54ba63d5f5, name = wangminxi, age = 25, marriaged = True, balance = None
loginUser:id = 6289e8405e07a13788dd0ab0, name = Tom, age = 25, marriaged = True, balance = None
7)查找包含或不包含某一属性的对象(exist)
- 包含该属性的对象:query.exists()
- 不包含该属性的对象(该属性对象为空):query.does_not_exist()
query = leancloud.Query("LoginUser")
# 查找包含 'friends' 的对象
query.exists('friends')
# 查找不包含 'friends' 的对象
# query.does_not_exist('friends')
loginUsers = query.find()
for loginUser in loginUsers:
repr(loginUser)
输出结果:
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True, balance = 1000
8)返回指定需要的属性(select)
通过 select 指定需要返回的属性。下面的代码只获取每个对象的 name 和 age
(包括内置属性 objectId、createdAt 和 updatedAt)
LoginUser = leancloud.Object.extend('LoginUser')
query = LoginUser.query
query.select('name', 'age')
loginUsers = query.find()
for loginUser in loginUsers:
repr(loginUser)
# title = todo.get('name') # √
# content = todo.get('age') # √
# notes = todo.get('sex') # None
print(repr(loginUser))
输出结果,未指定的属性输出结果为None:
loginUser:id = 6289e83b033caa54ba63d5f5, name = wangminxi, age = 25, marriaged = None, balance = None
loginUser:id = 6289e83e033caa54ba63d5f6, name = Lily, age = 25, marriaged = None, balance = None
loginUser:id = 6289e8405e07a13788dd0ab0, name = Tom, age = 25, marriaged = None, balance = None
loginUser:id = 6289e843033caa54ba63d5f8, name = Ben, age = 25, marriaged = None, balance = None
loginUser:id = 6289e845033caa54ba63d5fa, name = Sarah, age = 25, marriaged = None, balance = None
loginUser:id = 6289e845033caa54ba63d5fa, name = Sarah, age = 25, marriaged = None, balance = None
3、按字符串查询(模糊查询)
1)查询Keyword开头的内容
可以用 startswith 来查找某一属性值以特定字符串开头的对象。和 SQL 中的 LIKE 一样,你可以利用索引带来的优势。
LoginUser = leancloud.Object.extend('LoginUser')
query = LoginUser.query
# 相当于 SQL 中的 name LIKE 'wang%'
query.startswith("name", "wang")
loginUsers = query.find()
for loginUser in loginUsers:
repr(loginUser)
输出结果:
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True, balance = 1000
loginUser:id = 6289e839033caa54ba63d5f3, name = wanghaoxi, age = 25, marriaged = False, balance = None
loginUser:id = 6289e83b033caa54ba63d5f5, name = wangminxi, age = 25, marriaged = True, balance = None
2)查询包含Keyword的内容
- 可以用 contains 来查找某一属性值包含特定字符串的对象
- 与startswith 不同,contains 无法利用索引,因此不建议用于大型数据集。
- 注意 startswith 和 contains 都是 区分大小写 的
LoginUser = leancloud.Object.extend('LoginUser')
query = LoginUser.query
# 相当于 SQL 中的 name LIKE '%wang%'
query.contains("name", "wang")
loginUsers = query.find()
for loginUser in loginUsers:
repr(loginUser)
输出结果
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True, balance = 1000
loginUser:id = 6289e839033caa54ba63d5f3, name = wanghaoxi, age = 25, marriaged = False, balance = None
loginUser:id = 6289e83b033caa54ba63d5f5, name = wangminxi, age = 25, marriaged = True, balance = None
4、数组查询
1)按数组中某个对象进行查询
'''Step1: 下面的代码查找所有数组属性 friends 包含 Ben 的对象'''
LoginUser = leancloud.Object.extend("LoginUser")
query = LoginUser.query #leanCLoud.query.Query对象
query.equal_to("friends",'Ben')
loginUsers = query.find()
for loginUser in loginUsers:
repr(loginUser)
输出结果:
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True, balance = 1000, friends = ['Ben', 'Lily', 'Sarah', 'Lala']
loginUser:id = 6289e843033caa54ba63d5f8, name = Ben, age = 25, marriaged = False, balance = None, friends = ['Ben', 'Lily']
loginUser:id = 6289e845033caa54ba63d5fa, name = Sarah, age = 25, marriaged = False, balance = None, friends = ['Ben']
2)按数组长度进行查询
LoginUser = leancloud.Object.extend("LoginUser")
query = LoginUser.query
query.size_equal_to("friends", 4)
loginUsers = query.find()
for loginUser in loginUsers:
repr(loginUser)
输出结果:
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True, balance = 1000, friends = ['Ben', 'Lily', 'Sarah', 'Lala']
3)按数组中包含的对象列表进行查询
LoginUser = leancloud.Object.extend("LoginUser")
query = LoginUser.query
query.contains_all("friends", ['Ben','Lily'])
loginUsers = query.find()
for loginUser in loginUsers:
repr(loginUser)
输出结果:
loginUser:id = 6289e80c5e07a13788dd0aa5, name = wangxiaoxi, age = 25, marriaged = True, balance = 1000, friends = ['Ben', 'Lily', 'Sarah', 'Lala']
loginUser:id = 6289e843033caa54ba63d5f8, name = Ben, age = 25, marriaged = False, balance = None, friends = ['Ben', 'Lily']
5、关系查询
1)查询某一博客(post)下的所有评论(comment)
def repr_comments(comment):
print(f'comment:id = {comment.get("objectId")}, '
f'content = {comment.get("content")}, '
f'post.content = {comment.get("parent").get("content")}, '
f'post.title = {comment.get("parent").get("title")}, '
f'post.images = {comment.get("parent").get("images")}')
'''关系查询1'''
def test_query_with_relations(self):
''''''
'''
查询关联数据有很多种方式,常见的一种是查询某一属性值为特定 leancloud.Object 的对象,这时可以像其他查询一样直接用 equal_to。
比如说,如果每一条博客评论 Comment 都有一个 post 属性用来存放原文 Post,则可以用下面的方法获取所有与某一 Post 相关联的评论:
'''
Post = leancloud.Object.extend('Post')
post = Post.create_without_data('628a09785e07a13788dd10a4')
query = leancloud.Query('Comment') #获取关于Comment对象的查询, 即leanCLoud.query.Query对象
query.equal_to('parent', post)
comment_list = query.find()
for comment in comment_list:
repr_comments(comment)
输出结果:
comment:id = 628a09785e07a13788dd10a5, content = 当然是肯德基啦!, post.content = None, post.title = None, post.images = None
comment:id = 628a0978033caa54ba63dba9, content = 当然是必胜客啦!, post.content = None, post.title = None, post.images = None
2)查询可以找到所有包含图片的博客(post)文章的评论(comment)
云端使用的并非关系型数据库,无法做到真正的联表查询,所以实际的处理方式是:
- 先执行内嵌/子查询(和普通查询一样,limit 默认为 100,最大 1000),
- 然后将子查询的结果填入主查询的对应位置,再执行主查询。
- 如果子查询匹配到的记录数量超出 limit,且主查询有其他查询条件,那么可能会出现没有结果或结果不全的情况,因为只有 limit 数量以内的结果会被填入主查询。
'''关系查询2'''
def test_query_with_relations1(self):
''''''
'''
如需获取某一属性值为另一查询结果中任一 leancloud.Object 的对象,可以用 matches_query。
下面的代码构建的查询可以找到所有包含图片的博客文章的评论:
'''
inner_query = leancloud.Query('Post')
inner_query.exists('images')
query = leancloud.Query('Comment')
query.matches_query('parent', inner_query) #通过Comment表的leanCLoud.query.Query对象,选择包含images属性的post
comment_list = query.find()
for comment in comment_list:
repr_comments(comment)
输出结果:
comment:id = 628a0cf15e07a13788dd112d, content = 看日出..., post.content = None, post.title = None, post.images = None
comment:id = 628a0cf1033caa54ba63dcab, content = 谁不是个月光族呢, post.content = None, post.title = None, post.images = None
6、统计总数量
'''统计总数量'''
def test_get_count(self):
LoginUser = leancloud.Object.extend('LoginUser')
query = LoginUser.query
query.equal_to('marriaged', True)
count = query.count()
print(f"marriaged count = {count}")
输出结果:
marriaged count = 3