Package: django-models-redis-cache
django-models-redis-cacheDjango Models Redis Cache (DMoReCa), library that gives your specified Django models regular caching via RedisFor one project, I needed to work with redis, but redis-py provides a minimum level of work with redis. I didn't find any Django-like ORM for redis, so I wrote librarypython-redis-orm(PyPI).Also, if you are searching for just django-like redis ORM, please checkdjango-redis-orm(PyPI).And this library is port to Django that provides easy-to-use Django models caching via Redis.Working with this library, you are expected:Fully works in 2021Saving almost all types of fields automaticallyEfficient data storage (SET model_name:instance_id "JSON string")Async cachingConnection poolingEasy adaptation to your needsAdequate informational messages and error messagesBuilt-in RedisRoot class that stores specified models, with (optional):Async database limitIgnoring deserialization errorsUse structure-first dataCustomizing caching settings by model (optional):Cache every X secondsSave related modelsFields to exclude from cachingFilter objects to cacheCRUD (Create Read Update Delete), that uses your django modelsInstallationpip install django-models-redis-cacheHere is PyPIAdd "django_models_redis_cache" to your INSTALLED_APPS setting like this::INSTALLED_APPS = [
    ...
    'django_models_redis_cache',
]UsageCreateRedisRootwith params:prefix(str) - prefix for your redis rootconnection_pool(redis.ConnectionPool) - redis-py redis.ConnectionPool instance, with decode_responses=Trueasync_db_requests_limit(int) - your database has max connections limit, please enter it hereignore_deserialization_errors(bool) - to ignore deserialization errors or raise exceptioneconomy(bool) - if True, all update requests will return only instance idCallregister_django_models({...})on your RedisRoot instance and provide dict, where keys are django models and values are dicts (django_model:dict) with config params (str:value):enabled(bool) - to cache or notttl(int) - to cache every x secondssave_related_models(bool) - to save ForeignKey-s and ManyToMany-s instances or notexclude_fields(list of strings) - fields to exclude from cachingfilter_by(dict str:value) - filter objects to cache by somethingdelete(bool) - foolproofwrite_to_django(bool) - if you need to write data to django, also uses as foolproofCallcheck_cache()on your RedisRoot instanceUse our CRUD, or just get your cached dataExample usageSettingsYou can set this part in your project settings.py:fromdjango_models_redis_cache.coreimport*defget_connection_pool():host='localhost'port=6379db=0connection_pool=redis.ConnectionPool(decode_responses=True,host=host,port=port,db=db,)returnconnection_poolREDIS_ROOTS={'test_caching_root':RedisRoot(prefix='test_caching',connection_pool=get_connection_pool(),async_db_requests_limit=100,ignore_deserialization_errors=True,save_consistency=False,economy=True)}Run in the backgroundYou can just copy it to:app/management/commands/command_name.pyAnd just run with:python manage.py command_nameHelp:Django custom management commandsHow to import something from settingsredis_roots=getattr(settings,"REDIS_ROOTS",None)ifredis_roots:iftype(redis_roots)==dict:test_caching_root=redis_roots['test_caching_root']test_caching_root.register_django_models({CustomUser:{'enabled':True,'ttl':60*15,'save_related_models':True,'delete':True,'write_to_django':True,'exclude_fields':['is_admin','api_key','first_name','last_name','email','is_staff','date_joined','password','last_login','user_permissions','is_superuser','groups',],},BotSoft:{'enabled':True,'ttl':60*15,'save_related_models':True,'delete':True,'write_to_django':True,'exclude_fields':['name','image','image_webp','developer_url'],},Service:{'enabled':True,'ttl':60*15,'save_related_models':True,'delete':True,'write_to_django':True,'exclude_fields':['name_append','description','min','max',],},CustomService:{'enabled':True,'ttl':60*15,'save_related_models':True,'delete':True,'write_to_django':True,'exclude_fields':['name_append',],},UniqueTask:{'enabled':True,'ttl':60*5,'save_related_models':True,'delete':True,'write_to_django':True,},Task:{'enabled':True,'ttl':60*5,'save_related_models':True,'delete':True,'write_to_django':True,'filter_by':{'status':'in_work',}},Account:{'enabled':True,'ttl':60*5,'save_related_models':True,'delete':True,'write_to_django':True,'filter_by':{'last_task_completed_in__gte':datetime.datetime.now()-datetime.timedelta(days=14),'last_checked_in__gte':datetime.datetime.now()-datetime.timedelta(days=14),}},BotSession:{'enabled':True,'ttl':60*5,'save_related_models':True,'delete':True,'write_to_django':True,},TaskChallenge:{'enabled':True,'ttl':60*1,'save_related_models':True,'delete':True,'write_to_django':True,},})roots_to_cache=[test_caching_root,]print('STARTING CACHING')whileTrue:forredis_rootinroots_to_cache:redis_root.check_cache()else:raiseException('redis_roots must be dict')else:raiseException('No redis_roots')Use in viewsIf you enabled write_to_django and delete, you can fully use redis caching and does not care about writing to the database withour CRUD:# Django partgh0st_user=CustomUser.objects.get(username='gh0st')another_user=CustomUser.objects.get(username='another_username')random_service=random.choice(list(Service.objects.all()))placement=random_service.placementifServiceCustomPrice.objects.filter(user=gh0st_user,service=random_service,active=True):placement=ServiceCustomPrice.objects.get(user=gh0st_user,service=random_service,active=True).priceifgh0st_user.sale:placement=placement*gh0st_user.saletask_count=9999task_price=task_count*placementnew_task_1_params={'owner':gh0st_user,'service':random_service,'url':'https://github.com/gh0st-work/','count':task_count,'price':task_price,'status':'checking',}new_task_1=Task.objects.create(**new_task_1_params)new_task_2_params={'owner':another_user,'service':random_service,'url':'https://github.com/gh0st-work/','count':task_count,'price':task_price,'status':'checking',}new_task_2=Task.objects.create(**new_task_2_params)# Cache part# Preparationstest_caching_root.check_cache()# Just for testing, if it not runned in the background and not caching right now# Getcached_task_1=test_caching_root.get(Task,django_id=new_task_1.id)# filter by django_id, if you leave blank will return all instancesprint('\n\n\n')cached_task_2=test_caching_root.get(Task,django_id=new_task_2.id)# filter by django_id, if you leave blank will return all instancessuccess=Falsetry:cached_task_1=cached_task_1[0]cached_task_2=cached_task_2[0]ifcached_task_1['owner']['django_id']==new_task_1.owner.id:ifcached_task_1['price']==new_task_1.price:ifcached_task_2['owner']['django_id']==new_task_2.owner.id:ifcached_task_2['price']==new_task_2.price:success=Trueexcept:passprint(f'Get test:{success= }')# If create works, will print: "Get test: success = True"# Create and deep filteringnew_task_params=new_task_1_paramsnew_task_params['owner']=test_caching_root.get(CustomUser,username='gh0st')new_task_params['service']=test_caching_root.get(Service,django_id=random_service.id)created_task=test_caching_root.create(Task,**new_task_params)cached_gh0st_tasks=test_caching_root.get(Task,owner__username='gh0st')all_tasks_owner_is_gh0st=all([(task['owner']['username']=='gh0st')fortaskincached_gh0st_tasks])task_created=(created_taskincached_gh0st_tasks)success=(all_tasks_owner_is_gh0standtask_created)print(f'Create and deep filtering test:{success= }')# If works, will print: "Create and deep filtering test: success = True"# Updaterandom_price_first_part=Decimal(random.randrange(0,10000))random_price_second_part=Decimal(random.randrange(0,1000))random_price=random_price_first_part+random_price_second_part/Decimal(1000)test_caching_root.update(Task,cached_task_2,price=random_price,status='completed',)cached_task_2=test_caching_root.get(Task,price=random_price,# filter by price, if you leave blank will return all instancesstatus__in=['checking','completed'],# if status in the list)success=Falsetry:cached_task_2=cached_task_2[0]price_is_same=(cached_task_2['price']==random_price)django_id_is_same=(cached_task_2['django_id']==new_task_2.id)status_is_completed=(cached_task_2['status']=='completed')ifprice_is_sameanddjango_id_is_sameandstatus_is_completed:success=Trueexcept:passprint(f'Update test:{success= }')# If works, will print: "Update test: success = True"# Deletetest_caching_root.delete(Task,cached_task_2)old_cached_task_2=test_caching_root.get(Task,price=random_price)success=(notlen(old_cached_task_2))print(f'Delete test:{success= }')# If works, will print: "Delete test: success = True"