一个由Redis支持的超级快速ORM,支持O(1)搜索的模型和索引,并支持存储原生/复杂类型和对象
项目描述
这是一个支持索引的Redis支持的非常非常快的ORM风格框架。它具有O(1)效率的搜索功能!
您可以将原生Python类型(列表、对象、字符串、整数等)存储和检索。
IndexedRedis支持比较中的“等于”和“不等于”运算符。它还提供对替换整个数据集(基于模型)的完整原子支持,这对于提供快速的SQL前端非常有用。在这种情况下,一个按间隔运行的任务将从一个SQL后端检索/计算数据集,并对前端查询的数据集执行原子替换。
自6.0.0版本起,IndexedRedis还提供了对外部引用(如SQL中的外键一对一、一对多或多对多关系)的支持,这允许您直接将SQL模型转换为Redis模型,从而大大提高性能。
在数据检索后,还提供进一步客户端过滤(如大于、包含等)(请参阅以下“过滤结果”)
我的测试表明,在使用flask/mysql和IndexedRedis之间的等效模型时,性能可以提高600% - 1200%,但如果你直接以IndexedRedis模型设计存储,你将能够实现更高的提升。
它与python 2.7和python 3兼容。它已在python 2.7、3.4、3.5、3.6上进行了测试。
5.0 状态
版本5.0.0将与之前版本略有不兼容,因为它移除了一些旧遗留功能,改进了许多现有功能,并更改了一些行为。
你可以通过转换指南了解转换所需步骤,该指南可在以下位置找到:https://github.com/kata198/indexedredis/blob/5.0branch/CONVERTING_TO_5.0.0
变更的详细信息,以及转换指南中省略的增强和错误修复,可以在5.0.0版本日志中找到:https://github.com/kata198/indexedredis/blob/5.0branch/Changelog
自动和原生类型
从4.0版本开始,IndexedRedis支持定义字段,这些字段将自动转换为/从原生Python类型(如int、float、datetime)转换,以及可以表示为json(字典、列表)或支持pickle的对象。你只需提供其原生格式中的类型,所有的转换都在幕后完成。当获取对象时,返回的对象也包含其原生类型的字段。
IndexedRedis还支持更多高级功能,例如自动pickle/unpickle字段、压缩/解压缩、base64编码/解码,甚至可以通过标准接口定义自己的自定义字段类型。
有关更多信息,请参阅下文的“高级字段”部分。
API参考
并非所有方法和类型都包含在此文档中。
有关完整的pydoc参考,请参阅
https://pythonhosted.org/indexedredis/
或
http://htmlpreview.github.io/?https://github.com/kata198/IndexedRedis/blob/master/doc/IndexedRedis.html?_cache_vers=1
以下是一个快速概述/概览
IndexedRedisModel
你应该扩展此类型来定义你的模型。
示例模型
class Song(IndexedRedisModel)
FIELDS = [ \
IRField(‘artist’),
IRField(‘title’),
IRField(‘album’),
IRField(‘track_number’,valueType=int), # 自动转换为/从int
IRField(‘duration’,defaultValue=’0:00’),
IRField(‘releaseDate’,valueType=datetime.datetime), # 自动转换为/从datetime
IRField(‘description’),
IRField(‘copyright’),
IRRawField(‘mp3_data’), # 不要尝试编码/解码数据
IRCompressedField(‘thumbnail’,compressMode=’gzip’), # 使用“gzip”压缩在存储中压缩此字段
IRField(‘tags’,valueType=list),
# “lyrics”将在对象上是一个utf-8 unicode值,并将其压缩/解压缩到/从存储中 IRFieldChain(‘lyrics’,[ IRUnicodeField(encoding=’utf-8’), IRCompressedField() ]),defaultValue=’No lyrics found’ ),
]
- INDEXED_FIELDS = [ \
‘artist’,
‘title’,
‘track_number’,
]
KEY_NAME = ‘Songs’
模型属性
FIELDS - 必需。一个字符串或IRField对象(或其子类)的列表,这些对象命名了可用于存储的字段。(见下文“高级字段”部分)
示例:[IRField(‘name’), IRField(‘description’), IRField(‘model’), IRFixedPointField(‘Price’,2), IRField(‘timestamp’,valueType=datetime), IRField(‘remainingStock’,valueType=int)]
INDEXED_FIELDS - 包含将进行索引的字段名称的字符串列表。只能过滤索引字段。添加插入/删除时间。此处列出的名称必须与FIELDS中给出的字段名称匹配。
示例:[‘Name’,‘model’]
KEY_NAME - 必需。表示此模型的唯一名称。将其视为表名。
示例:‘StoreItems’
REDIS_CONNECTION_PARAMS - 可选 - 提供传递给“redis.Redis”以构造redis对象的参数。在这里,您可以定义每个模型的默认连接参数的覆盖。
从5.0.0版本开始,仅为此模型定义此字段以使用默认连接之外的连接。您不再需要在每个模型上设置此选项。
有关更多信息,请参阅下面的“连接到Redis”部分。
如果未定义或为空,将使用默认参数。如果存在任何字段,它们将覆盖继承的默认连接参数。
示例:{'host' : '192.168.1.1'}
高级字段
从版本4.0开始,IndexedRedis允许您在FIELDS元素中传递类型为IRField(扩展str)的元素。
从5.0.0版本开始,所有字段必须以某种方式扩展IRField。那些不扩展的将生成弃用警告,并且字段将被转换为IRClassicField(与IRField相同,但默认为空字符串而不是irNull)。
这样做可以指定有关字段的某些属性。
示例
FIELDS = [ IRField('name'), IRField('age', valueType=int), IRField('birthday', valueType=datetime.datetime) ]
字段名称
第一个参数是字段名称的字符串。
类型
您可以通过传递“valueType”将值自动转换为特定类型(IRField或使用几种扩展字段之一)
(例如,IRField('age', valueType=int))
如果使用“bool”,则值0和大小写不敏感的字符串“false”将结果为False,而1或“true”将结果为True。
当使用浮点数时,请考虑使用IRFixedPointField,它支持索引,并且与平台无关的相同表示形式(与“float”不同)。
浮点数以跨平台工作。使用定点数字作为字符串类型(例如,myFixedPoint = '%2.5f' % (10.12345))
IRField支持“valueType”,大多数其他字段类型处理特定类型,因此没有此类参数。
空值
空值由一个静态单例表示,称为“irNull”(类型为IRNullType)。
对于除IRClassicField之外的所有类型(IRClassicField默认为空字符串),字段的默认值(当未设置时)为irNull。可以通过将“defaultValue=somethingElse”传递给IRField构造函数来更改此值。
irNull不等于空字符串,或除了另一个irNull之外的所有内容。这是为了区分,例如,没有分配的int与int(0)
您可以使用在IndexedRedis或IndexedRedis.fields中找到的“irNull”变量来检查类型化的字段。
例如。
from IndexedRedis import irNull
# 可以直接在模型过滤中使用,notDangerFive = MyModel.objects.filter(dangerLevel__ne=irNull).filter(dangerLevel__ne=5).all()
# 或在可查询列表中,或直接比较(未显示)myResults = MyModel.objects.filter(something='value').all()
notDangerFive = myResults.filter(dangerLevel__ne=irNull).filter(dangerLevel__ne=5)
默认值
所有字段(除IRClassicField外)支持在构造IRField对象时提供的“defaultValue”参数。
对于所有字段(除IRClassicField外),此参数的默认值是“irNull”(见下文)。对于IRClassicField,默认值保持为空字符串,并且不能更改(以与5.0.0之前的普通字符串字段兼容)。
高级类型
以下是在FIELDS数组中使用可能的字段类型,可以像“from IndexedRedis.fields import NAME”一样导入
IRField - 标准字段,接受一个名称和一个“valueType”,这是一个本地Python类型,或任何实现__new__的单参数类型,返回对象。有关datetime和json的实现示例,请参阅IndexedRedis/fields/FieldValueTypes。
如果没有定义valueType,则类型为str/unicode(与4.0之前相同),并使用默认编码(请参阅set/getDefaultIREncoding函数)
除非类型是json类型或浮点数(使用IRFixedPointField在浮点数上建立索引)否则可索引。
IRBase64Field - 在Base64编码和解码之间转换。
可索引。
IRCompressedField - 在存储前自动压缩,在检索后自动解压缩。参数“compressMode”目前支持“zlib”(默认)、“bz2”或“lzma”。
可索引。
IRFixedPointField - 带有固定小数位数的浮点数。此类类型支持使用浮点数进行索引,而IRField(…valueType=float)不支持,因为不同平台有不同的精度、舍入等。通过参数decimalPlaces(默认为5)定义小数点后的精度。
可索引。
IRPickleField - 在存储前自动将给定的对象序列化,在检索后反序列化。
不可索引,因为Python 2和3之间的表示不同,以及系统相关的repr变化。
IRUnicodeField - 带有参数“encoding”的字段,用于定义此字段的编码。使用此字段来支持具有任意编码的字段,因为IRField将使用默认编码来处理字符串。
可索引
IRBytesField - 强制数据为“bytes”,Python 2和Python 3兼容。如果您需要Python 3专用,可以使用IRField(valueType=bytes)。对于完全不进行编码/解码,请参阅IRRawField。
可索引
IRClassicField - 模仿FIELDS 5.0.0之前的普通字符串条目行为的字段。此字段默认为空字符串,并且始终使用默认IREncoding进行编码/解码。
可索引
IRRawField - 不在Redis中转换的字段。在检索时,它始终是“bytes”类型(或Python 2中的str)。在Python 3中,它与IRField(…valueType=None)非常相似,但Python 2需要此字段来存储二进制数据而不会遇到编码问题。
不可索引 - 无解码
IRForeignLinkField - 提供对另一个模型的引用(在SQL中想到“外键”)。使用此功能来引用模型中的其他模型。该字段链接到单个外对象或irNull。
使用“foreignKey”参数接受链接的模型。
有关更多信息,请参阅“外部链接”部分。
可索引
IRForeignMultiLinkField - 提供对另一个模型的引用(在SQL中想到“外键”)。使用此功能来引用模型中的多个其他模型。该模型链接到一个或多个外对象,或irNull。
使用“foreignKey”参数接受链接的模型。
有关更多信息,请参阅“外部链接”部分。
可索引。注意,过滤器必须包含完整列表(pks、objs或它们的组合)。必须客户端执行“包含项目”式过滤器。
IRFieldChain - 将多个字段类型链接在一起。例如,使用此功能压缩值的Base64表示形式或压缩utf-16数据。有关更多详细信息,请参阅下面的部分。
如果所有链接的字段都是可索引的,则可索引。
链式连接多个类型
“链式连接”允许您对单个字段应用多个类型。例如,假设您有一些需要压缩以进行存储的utf-16数据。
示例
FIELDS = [
…
IRFieldChain(‘longData’,[IRUnicodeField(encoding='utf-16'), IRCompressedField()])
]
IRFieldChain类似于常规IRField,第一个参数是字段名称,它有一个可选的“defaultValue”参数。
不同之处在于第二个参数chainedFields接受一个其他字段类型的列表。
在存储时,将值通过列表中的每个类型从左到右传递。
在检索时,检索到的值将逆向通过这些链接字段,从右到左。
最左侧元素(第一个元素)的输出定义了访问对象时将找到的数据类型。
因此,在上面的示例中,“myObj.longData”将是一个utf-16字符串。在访问数据库时,该utf-16字符串将被解码然后压缩以进行存储。在检索时,它将被解压缩然后转换回utf-16。
您可以在IRFieldChain上指定一个defaultValue,通过将“defaultValue=X”作为构造函数的参数来实现。但是,如果在链中的任何字段上提供了“defaultValue”,则将被忽略。
哈希查找(性能)
如果您想要在非常大的字符串/字节(如基因组)上进行索引/搜索,IndexedRedis支持对键进行哈希处理,即值将作为本身存储,但用于查找的键引用将是该字符串的哈希。
这提高了性能,节省了网络流量,并减少了存储需求。
为此,将IRField的“hashIndex”属性设置为True。
FIELDS = [ \
…
IRField('genomeStr', hashIndex=True)
]
就这样!过滤和检索等所有操作保持不变(即您直接使用值,就像“hashIndex”为False一样),但在幕后,所有查找都将使用值的MD5哈希来完成。
将现有模型转换为/从哈希索引
IndexedRedis提供了辅助方法来自动将现有的未哈希键转换为哈希,并将哈希键转换回未哈希。
为此,相应地更改您的IndexedRedisModel,然后调用(对于名为MyModel的模型类)
MyModel.objects.compat_convertHashedIndexes()
这将删除任何支持“hashIndex”属性的IRField的哈希和非哈希键值。如果您仅调用“reindex”并且更改了任何字段的“hashIndex”属性,则将留下持久的关键值。
默认情况下(fetchAll=True),此函数将检索此特定模型的全部记录,并对它们逐个操作。这更有效,但如果内存限制是问题,则可以传递fetchAll=False,这将检索一个对象,转换索引,保存,然后检索下一个对象。这较慢,但使用的内存较少。
在此函数调用期间,不应使用任何模型(在更改模式时使用它本来就没有意义)。
连接到Redis
您的Redis连接应由调用“setDefaultRedisConnectionParams”并传递一个字典{‘host’:‘hostname’,‘port’:6379,‘db’:0}来定义。
默认连接将连接到主机127.0.0.1,端口6379,数据库名为0。如果您没有明确定义这些字段中的任何一个,则将使用这些值用于相应的字段。
这些默认参数将用于所有模型,除非您在模型上定义了非空的REDIS_CONNECTION_PARAMS,则该模型将继承默认连接参数,覆盖任何在模型上定义的值。
如果您需要相同的模型连接到不同的Redis实例,可以调用“MyModel.connectAlt”(其中MyModel是您的模型类)并传递一个包含备用连接参数的字典。该函数将返回一个使用提供的备用连接的类的副本。
模型验证
该模型将在第一次实例化该类型的对象时进行验证。如果它的定义中有任何无效之处,将引发“InvalidModelException”。
用法
用法与Django或Flask非常相似。
查询
调用.filter或.filterInline构建一个查询/过滤集。使用下面描述的任何一种Fetch方法来执行查询。
objects = SomeModel.objects.filter(param1=val).filter(param2=val).all()
数据库支持从等于和不等于的检索类型。要使用不等于表达式,将“__ne”追加到字段名的末尾。
objects = SomeModel.objects.filter(param1=val, param2__ne=val2).all()
所有过滤器都在Redis服务器上使用哈希查找应用。同一类型的所有过滤器(等于或不等于)在Redis上使用一个命令应用。因此,应用过滤器,无论有多少个过滤器,总共是1到2个命令。
过滤结果/客户端过滤
.all操作的结果是一个[QueryableList](https://pypi.python.org/pypi/QueryableList),包含了所有匹配的对象。每个对象类型与模型相同。你可以像使用普通列表一样使用QueryableList,但它可能更强大。
一旦从Redis中获取了结果,QueryableList允许你使用QueryableList支持的方式(例如gt、contains、in)进行进一步客户端过滤。
示例
mathTeachers = People.objects.filter(job='Math Teacher').all()
experiencedMathTeachers = mathTeachers.filter(experienceYears__gte=10) # 获取具有10年或以上经验的数学教师
cheeseLovingMathTeachers = matchTeachers.filter(likes__splitcontains=(' ', 'cheese')) # 检查空格分隔的列表字段'likes'是否包含'cheese'
更多信息请见 https://github.com/kata198/QueryableList。
保存
obj = SomeModel(field1='value', field2='value') obj.save()
使用过滤器删除
SomeModel.objects.filter(name='Bad Man').delete()
删除单个对象
obj.delete()
原子数据集替换
还有一个名为“reset”的强大方法,可以原子性地替换属于该模型的所有元素。这对于缓存替换等非常有用。
lst = [SomeModel(…), SomeModel(..)]
SomeModel.reset(lst)
例如,你可以有一个SQL后端和cron作业,执行复杂查询(或仅获取相同的模型),并每5分钟进行一次原子替换,以在应用中获得巨大的性能提升。
通过SomeModel.objects.filter(key=val, key2=val2)过滤对象并使用.all获取对象
示例:SomeModel.objects.filter(name='Tim', colour='purple').filter(number=5).all()
获取主键
有时你可能想要通过外键关系引用单个对象,或者为了更快/更独特地检索,而不是过滤。
每个保存的对象都有一个唯一的唯一主键(每个模型都是唯一的),可以通过“getPk”方法检索。然后你可以使用此值在exists、get、getMultiple等方法中使用。
获取函数:
构建过滤器集不会实际获取任何数据,直到调用以下其中一个(请参阅API以获取完整列表)。所有这些函数都作用于当前的过滤器集。
示例:matchingObjects = SomeModel.objects.filter(…).all()
all - 返回匹配此过滤器的所有对象
allOnlyFields - 接受字段列表,并仅使用当前过滤器集获取这些字段
allByAge - 返回匹配此过滤器的对象,按从旧到新的顺序排列
delete - 删除匹配此过滤器的对象
count - 获取匹配此过滤器的对象数量
first - 获取当前过滤器下的最旧记录
last - 获取当前过滤器下的最新记录
random - 获取当前过滤器下的随机元素
getPrimaryKeys - 获取与当前过滤器关联的主键
过滤器函数
这些函数向当前集添加过滤器。“filter”返回一个副本,“filterInline”作用于该对象。
filter - 添加额外的过滤器,返回过滤器对象的副本(moreFiltered = filtered.filter(key2=val2))
filterInline - 向当前过滤器对象添加额外的过滤器。
全局获取函数
这些函数在SomeModel.objects上可用,不使用任何过滤器(它们获取特定对象)
get - 通过pk获取单个对象
getMultiple - 通过pk列表获取多个对象
exists - 测试给定pk下是否存在对象
模型函数
实际对象包含包括
save - 保存此对象(如果不存在则创建,否则更新)
delete - 删除此对象
getUpdatedFields - 查看上次获取后的更改
更新索引
随着模型的变化,你可能需要向INDEXED_FIELDS数组中添加字段。如果这是一个已存在的字段,你可以通过以下方式重新索引模型:
MyModel.objects.reindex()
然而,如果你更改了可索引字段的字段类型,你应该使用“reset”方法。
MyModel.objects.reset(MyModel.objects.all())
连接到多个Redis实例
您可能想在多个Redis实例上使用相同的模型。要做到这一点,请在IndexedRedisModel上使用.connectAlt方法。
AltConnectionMyModel = MyModel.connectAlt({'host' : 'althost', 'db' : 4})
“connectAlt”方法接受一个Redis连接参数的字典,并返回一个指向备用Redis的Model的副本。
您可以使用AltConnectionMyModel就像使用MyModel一样。
客户端过滤/方法
在从redis检索了一组对象之后(例如通过调用.all()),您将获得一个已检索对象的IRQueryableList。
这是一个智能列表,它封装了QueryableList(https://github.com/kata198/QueryableList)并允许使用多种更高级的过滤(包含、不区分大小写的比较、分割过滤等)。有关所有可用操作的详细信息,请参阅QueryableList文档。
这些操作将在获取后作用于对象,但有时您需要过滤超出简单的等于或不等于,这是Redis后端的当前限制。
您可以使用链式调用
# 从Redis获取所有field1等于“something”的对象。
# 然后,在客户端,过滤出csvData不为空且以逗号分割包含“someItem”作为元素的对象。
# 然后,仍然在客户端,过滤出(状态为“pending”或“saved”)或lastUpdated小于或等于700秒前的对象。
#(请注意,确保lastUpdated是IRField(..valueType=int)或float,否则您将比较字符串)
myObjects = MyModel.objects.filter(field1='something').all().filter(csvData__isnull=False, csvData__splitcontains=("," , "someItem")).filterOr(status__in=('pending', 'saved'), lastUpdated__lte(time.time() - 700))
IRQueryableList上的其他方法包括
getModel - 返回与这些对象关联的模型
delete - 删除此列表中的所有对象。
注意:这样做更有效率
MyModel.objects.filter(…).delete()
而不是这样做
MyModel.objects.filter(…).all().delete()
因为后者实际上检索了完整对象,然后删除它们,而前者只删除匹配项。
然而,有时您可能希望在删除之前在客户端进行额外的过滤,这支持这一点。
save - 保存此列表中的所有对象。如果是所有现有对象,则仅更新自获取以来已更改的字段。
reload - 逐个重新加载此列表中的所有对象。这将从Redis获取最新数据并将其应用到项目上。
此函数的返回将是一个与IRQueryableList相同索引的列表。项目将是KeyError异常(如果项目在Redis端被删除),或包含字段更新字典,键为字段名称,值为(旧值,新值)元组。
refetch - 再次检索此列表中的所有对象,并返回一个新的IRQueryableList。请注意,这不会再次执行过滤,而是基于每个项目的内部主键检索每个项目。
外键链接
从IndexedRedis 6.0.0版本开始,您可以从另一个模型引用模型实例。这些在SQL世界中类似于“外键”。
两种字段类型提供此功能
IRForeignLinkField - 链接到另一个模型的单个实例。这接受一个值irNull(对于没有链接的对象)、一个对象的主键或一个对象本身。解析始终到对象本身。
IRForeignMultiLinkField - 链接到另一个模型的多个实例。与SQL不同,IndexedRedis可以直接使用字段执行此操作,而无需中间表。这接受一个值irNull(对于没有链接的对象),或包含主键和/或对象的列表。解析是引用对象列表。
分配引用
您可以分配与字段关联的外部模型类型匹配的对象或pk。
因此,如果你在FIELDS中有一个类似条目
IRForeignLinkField( 'other', foreignModel=OtherModel)
则你可以分配一个引用,例如
myOtherModel = OtherModel( … )
myObj.other = myOtherModel # 如果使用IRForeignMultiLinkField,这应该是一个列表。
或者
myOtherModel = OtherModel.objects.filter ( … ).first()
myObj.other = myOtherModel.getPk()
获取引用
默认情况下,当你获取模型时,任何外键关系的主键(们)都会与之一起获取。
外键对象本身是在访问时获取的,所以如果你这样做
myObj = MyModel.objects.filter ( … ).all()[0] # myObj仅获取OtherModel的主键
otherModel = myObj.other # 在这个点上(访问时),会获取整个OtherModel(使用主键)
这是推荐的默认行为,因为对于你可能不需要使用的每个对象,你可以节省一些时间和内存。
此外,如果你的应用程序不使用锁定,并且多个东西可能正在接触引用模型,那么如果你在获取时而不是在获取时获取,意外覆盖或使用过时实例的机会会更小。
然而,如果你想在同一个事务中获取外键链接(以及链接上的任何外键等,即获取所有相关内容),你可以在任何获取函数(如all、first、last、allOnlyFields等)中传递cascadeFetch=True。这将导致在获取时完全解析,而不是在访问时。
移除引用
可以通过将字段值设置为“irNull”来移除IRForeignLinkField的引用。例如:
myObj.other = irNull
将移除引用。
对于IRForeignMultiLinkField,你可以通过将字段设置为“irNull”来移除所有引用。你可以通过将字段值分配给一个列表(从中减去你不想包含的对象/主键)来移除单个引用。
注意:你必须分配这个列表。你不能获取列表,删除一个条目,然后保存对象。你必须这样做
myRefs = myObj.others
myRefs.remove( objToRemove ) # 或者splice,或者del
myObj.others = myRefs # 你必须分配属性。仅更改之前的结果列表将没有任何效果。
myObj.save()
级联
对于几个操作(与获取、保存、检查更改、比较值相关),有两个模式可以考虑。
第一个是非级联。这将导致操作仅处理当前对象,包括对 foreign objects 的引用,但不处理这些对象本身。
第二个是级联。这将导致操作级联,即它们将处理当前对象、任何 foreign objects、任何它们的 foreign objects 等。
对于获取方法(如.all),有一个参数cascadeFetch,默认为False,它将导致所有对象在一个事务中一次性解析,而不是默认的按访问。
对于保存方法(如.save),有一个参数cascadeSave,默认为True,它将导致任何未保存的外键对象也被保存。这意味着如果你通过IRForeignLinkField附加一个未保存的对象,并在父对象上调用.save(cascadeSave=True),那么两个都将被插入。此外,如果你在引用对象上进行了任何更改,并在.save(cascadeSave=True)上调用,这些更改也将被保存。
如果你显式调用myOBj.save(cascadeSave=False),那么只有“myObj”会被保存。如果你将引用分配给一个已经保存的外键对象(因此有一个主键),那么这个主键将被链接。如果你将引用分配给一个尚未保存的外键对象,那么你将不会有一个链接。你需要显式先保存子对象。此外,如果子外键对象发生了更改,那么在cascadeSave=False的情况下,它们将不会与“myOBj”一起保存。
对于重载功能,有一个参数,cascadeObjects,默认为True。这将控制是否重新加载具有本地更改的任何外部模型。如果为True,任何具有本地更改的任意级别的外部模型都将被重新加载(并反映在返回值中)。如果为False,则仅检查pk字段。
对于比较函数(hasSameValues、hasUnsavedChanges、getUpdatedFields),有一个参数,cascadeObjects,默认为False,它会导致任何外部链接对象(以及这些对象可能包含的任何链接等)被包含在结果中。
例如,考虑以下内容
myObj = MyModel.objects.first()
myObj2 = myObj
myObj.other.someKey = 'someValue'
当使用cascadeObjects=False调用hasSameValues时,将返回True,因为两个对象在直接引用的对象上具有相同的值。然而,当cascadeObjects=True时,将返回False。
hasUnsavedChanges的情况相同。
当使用cascadeObjects=False调用getUpdatedFields时,将返回一个空字典,因为“other”的pk没有更改。然而,当cascadeObjects=True时,结果中将包含键“other”,映射到值(myObj.other更改前的值,myObj.other更改后的值)。
但请注意,更改外部对象引用本身也被认为是主对象上的更改。所以,例如
myObj = MyModel.objects.first()
myObj2 = myObj
myObj.other = OtherModel.objects.filter(…).first() # 更改“other”指向的位置
在上面的示例中,当使用cascadeObjects=False调用hasSameValues、hasUnsavedChanges和getUpdatedFields时,都会显示“other”发生了变化,因为与“myObj”关联的pk发生了变化。
排序
在获取结果后,您可以通过在IRQueryableList上调用.sort_by来对它们进行排序。
示例
myObjs = MyModel.objects.filter(blah='something').all().sort_by('startDate')
编码
IndexedRedis默认使用系统默认编码(sys.getdefaultencoding),除非它是ascii,在这种情况下将默认使用utf-8。
您可以通过IndexedRedis.setDefaultIREncoding来更改此设置。
要获取当前默认编码,请使用IndexedRedis.getDefaultIREncoding。
要按字段使用不同的编码,请使用IRUnicodeField或IRBytesField,这两个类在构造时都接受一个“encoding”参数,允许您使数据遵循该编码。
更改
请参阅https://raw.githubusercontent.com/kata198/indexedredis/master/Changelog
示例
请参阅https://raw.githubusercontent.com/kata198/indexedredis/master/example.py
还可以查看
https://github.com/kata198/indexedredis/tree/master/tests
以了解各种独立和单元测试,这些测试将展示各种使用模式
联系我
请通过电子邮件与我联系,提出任何问题、错误,或者只是告诉我您在使用它!kata198@gmail.com