Package: redis-limpyd-extensions
redis-limpyd-extensionsSome extensions forredis-limpyd(redisorm (sort of) in python)Where to find it:Github repository:https://github.com/limpyd/redis-limpyd-extensionsPypi package:https://pypi.python.org/pypi/redis-limpyd-extensionsDocumentation:http://documentup.com/limpyd/redis-limpyd-extensionsInstall:Python versions 2.7, and 3.5 to 3.8 are supported (CPython and PyPy).Redis-server versions >= 3 are supported.Redis-py versions >= 3 are supported.Redis-limpyd versions >= 2 are supported.You can still use limpyd-extensions versions < 2 if you need something older than the above requirements.pipinstallredis-limpyd-extensionsList of available extensions:Add/remove related on both sidesDynamic fieldsAdd/remove related on both sidesSay we have the following related models:classPerson(RelatedModel):database=main_databasename=HashableField(indexable=True)classGroup(Relatedmodel):database=main_databasename=HashableField(indexable=True)members=M2MSetField(Person,related_name='membership')And some data:somebody=Person(name='foobar')group_1=Group(name='group 1')group_2=Group(name='group 2')group_3=Group(name='group 3')We can add membership the normal way:group_1.members.sadd(somebody)And retrieving then this way:group_1_members=group_1.members()# somebody !somebody_membership=somebody.membership()# group_1But say that we want to put a person in many groups at ones, we can do:group_2.members.sadd(somebody)group_3.members.sadd(somebody)limpyd_extensionsprovide a way to add/remove relations via the
other side of the relation:somebody.membership.sadd(group2,group3)To use this, simple import the related fields fromlimpyd_extensions.relatedinstead oflimpyd.contrib.related:fromlimpyd_extensions.relatedimport(FKStringField,FKHashableField,M2MSetField,M2MListField,M2MSortedSetField)And use them as usual. (Note that for convenience you can also import
the standardRelatedModelfrom there)The added methods for the reverse side of each related field are:FKStringFieldsadd, to set the reverse relation as the fk of the arguments:Having:classGroup(RelatedModel):parent=FKStringField(self,related_name='children')The standard:child_group.parent.set(main_group)other_child_group.parent.set(main_group)is the same as the new:main_group.children.sadd(child_group,other_child_group)sremworks the same way assaddbut for deleting fk:The standard:child_group.parent.delete(main_group)other_child_group.parent.delete(main_group)is the same as the new:main_group.children.srem(child_group,other_child_group)FKHashableFieldsaddsremBoth work the exact same way as for FKStringField, the only difference
is thatsaddemulates ahset, not aset.M2MSetFieldsaddThe standard:group_2.members.sadd(somebody)group_3.members.sadd(somebody)is the same as the new:somebody.membership.sadd(group2,group3)sremworks the same way assaddbut for removing relations:The standard:group_2.members.srem(somebody)group_3.members.srem(somebody)is the same as the new:somebody.membership.srem(group2,group3)M2MListFieldlpushandrpush, that works forM2MListFieldlikesaddforM2MSetFieldIf in our Person/Group examplemembersis aM2MListFieldinstead
of aM2MSetField,The standard:group_2.members.rpush(somebody)group_3.members.rpush(somebody)is the same as the new:somebody.membership.rpush(group2,group3)lremworks the same way asrpushandlpushbut for
removing relations:The standard:group_2.members.lrem(0,somebody)# 0 for "all occurences"group_3.members.lrem(0,somebody)is the same as the new:somebody.membership.lrem(group2,group3)# the count is forced to 0M2MSortedSetFieldzaddthat works forM2MSortedSetFieldlikesaddforM2MSetField, but managing scores. Arguments can be set the same
way as the normalzaddcommand.If in our Person/Group examplemembersis aM2MSortedSetFieldinstead of aM2MSetField, using the score to save the date of
membershipThe standard:group_2.members.zadd({somebody:sometime})# sometime, a float, can be a call to time.time()group_3.members.zadd({somebody:another_time})is the same as the new:somebody.membership.zadd({group2:sometime,group3:another_time})zremworks the same way aszadd, without the score, but for
removing relations:The standard:group_2.members.zrem(somebody)group_3.members.zrem(somebody)is the same as the new:somebody.membership.zrem(group2,group3)Dynamic fieldsDynamic fields provide a way to add unlimited fields to a model by
defining a (or many) dynamic field, and use it with a dynamic part. ie a
dynamic field name “foo” can be used with as many dynamic parts as you
want to create dynamic variations: “foo_bar” for the dynamic part
“bar”, “foo_baz” for the dynamic part “baz”, and so on.A simple API to use them, and filter on them, is provided.To use a dynamic field, your model must inherit from the following
mixin:ModelWithDynamicFieldMixin, found inlimpyd_extensions.dynamic.model. It’s a mixin, you should use it
with anotherRedisModelclass. Fields are available as field classes
(DynamicStringField,DynamicInstanceHashField,DynamicListField,DynamicSetField,DynamicSortedSetField,DynamicHashField) or as a mixin (DynamicFieldMixin) if you want
to adapt an external field. You can find them inlimpyd_extensions.dynamic.fieldsA short example on how to define a dynamic field on a model:fromlimpyd.modelimportRedisModelfromlimpyd_extension.dynamic.modelimportModelWithDynamicFieldMixinfromlimpyd_extension.dynamic.fieldsimportDynamicSetFieldclassMyModel(ModelWithDynamicFieldMixin,RedisModel):foo=DynamicSetField(indexable=True)As thefoofield is dynamic, you cannot run any command on it, but
only on its dynamic variations. How to do it ?There is two ways:use theget_fieldmethod of the model:foo_bar=myinstance.get_field('foo_bar')use theget_formethod of the field:foo_bar=myinstance.foo.get_for('bar')The latter is useful if you have a variable instead of known value:somebar='bar'foo_bar=myinstance.foo.get_for(somevar)Note that you can use this shortcut instead of usingget_for:foo_bar=myinstance.foo(somevar)Knowing this, you can do operations on these fields:myinstance.foo(somevar).sadd('one','two','three')myinstance.foo(othervar).sadd('four','five')myotherinstance.foo(somevar).sadd('three','thirty')printmyinstance.foo(somevar).smembers()printmyinstance.foo(othervar).smembers()printmyotherinstance.foo(somevar).smembers()To know the existing versions in a dynamic_field, you can usescan_fields.It takes the same argument as thesscancommand ofSetField(from limpyd), because it is applied on the inventory key where all versions are saved.So if you have some versions:You can retrieve them all:Or only a part:FilteringTo filter on indexable dynamic fields, there is two ways too:use the classic way, if you now the dynamic part in advance:MyModel.collection(foo_bar='three')use the newdynamic_filtermethod:MyModel.collection().dynamic_filter('foo','bar','three')Parameters are: the field name, the dynamic part, the value for the
filter and, not show in the previous example, the index suffix to use.This suffix is default to ‘’.But if what you want to do isMyModel.collection(foo_bar__eq='three')You can usedynamic_filterthis way:MyModel.collection().dynamic_filter('foo','bar','three','eq')# you can use '__eq' tooThe collection manager used withModelWithDynamicFieldMixindepends
onExtendedCollectionManager, so you can chain filters and dynamic
filters on the resulting collection.Dynamic related fieldsDynamic fields also work with related fields, exactly the same way.
There is only two additions:if you pass a model instance in theget_formethod, it will be
translated to it’s pkthe first argument of a “related collection” is the dynamic part (can
also be an instance)An exemple using dynamic related fields:fromlimpyd.fieldsimportPKFieldfromlimpyd_extensions.dynamic.modelimportModelWithDynamicFieldMixinfromlimpyd_extensions.dynamic.relatedimportDynamicM2MSetFieldclassTag(MyBaseModel):slug=PKField()classPerson(MyBaseModel):name=PKField()classMovie(ModelWithDynamicFieldMixin,MyBaseModel):name=PKField()tags=DynamicM2MSetField(Tag,related_name='movies')somebody=Person(name='Somebody')matrix=Movie(name='Matrix')cool=Tag(name='cool')matrix.tags.get_for(somebody).sadd(cool)# same as: matrix.tags(somebody).sadd(cool)cool_movies_for_somebody=cool.movies(somebody)# the related collection# ['Matrix']Provided classesHere is the list of modules and classes provided with thelimpyd_extensions.dynamicmodule:modelmixinsModelWithDynamicFieldMixin(object)- A mixin tu use for
your model with dynamic fieldscollectionmixinsCollectionManagerForModelWithDynamicFieldMixin(object)- A
mixin to use if you want to add thedynamic_filtermethod
to your own collection managerfull classesCollectionManagerForModelWithDynamicField(CollectionManagerForModelWithDynamicFieldMixin, ExtendedCollectionManager)- A simple class inheriting from our mixin and the manager fromlimpyd.contrib.collectionfieldmixinsDynamicFieldMixin(object)- A mixin within all the stuff
for dynamic fields is done, to use to add dynamic field support
to your own fieldsfull classesAll fields simply inherits from our mixin and the
wanted base field, without anymore addition:DynamicStringField(DynamicFieldMixin, StringField)DynamicInstanceHashField(DynamicFieldMixin, InstanceHashField)DynamicListField(DynamicFieldMixin, ListField)DynamicSetField(DynamicFieldMixin, SetField)DynamicSortedSetField(DynamicFieldMixin, SortedSetField)DynamicHashField(DynamicFieldMixin, HashField)relatedmixinsDynamicRelatedFieldMixin(DynamicFieldMixin)- A mixin
within all the stuff for dynamic related fields is done, to use
to add dynamic field support to your own related fieldsfull classesDynamicFKStringField(DynamicRelatedFieldMixin, FKStringField)DynamicFKInstanceHashField(DynamicRelatedFieldMixin, FKInstanceHashField)DynamicM2MSetField(DynamicRelatedFieldMixin, M2MSetField)DynamicM2MListField(DynamicRelatedFieldMixin, M2MListField)DynamicM2MSortedSetField(DynamicRelatedFieldMixin, M2MSortedSetField)