feat: implement custom redis endpoint
Signed-off-by: Ameya Shenoy <shenoy.ameya@gmail.com>
This commit is contained in:
parent
0f76a31b61
commit
e0c0e3bf2b
7 changed files with 99 additions and 9 deletions
32
backend/app/redis.py
Normal file
32
backend/app/redis.py
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
from django.core.serializers.json import DjangoJSONEncoder
|
||||||
|
from django_redis.pool import ConnectionFactory as Factory
|
||||||
|
from django_redis.serializers.base import BaseSerializer
|
||||||
|
|
||||||
|
|
||||||
|
class JSONSerializer(BaseSerializer):
|
||||||
|
"""
|
||||||
|
The default JSON serializer of django-redis assumes `decode_responses`
|
||||||
|
is disabled, and calls `decode()` and `encode()` on the value.
|
||||||
|
This serializer does not.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def dumps(self, value):
|
||||||
|
return json.dumps(value, cls=DjangoJSONEncoder)
|
||||||
|
|
||||||
|
def loads(self, value):
|
||||||
|
return json.loads(value)
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionFactory(Factory):
|
||||||
|
"""
|
||||||
|
Custom ConnectionFactory that injects the decode_responses parameter.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def make_connection_params(self, url):
|
||||||
|
kwargs = super().make_connection_params(url)
|
||||||
|
kwargs["decode_responses"] = True
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
|
@ -1,8 +1,18 @@
|
||||||
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from app.views import BhavCopyEquityView, BhavCopyEquityDefaultRedisView, EmptyRespoinseView
|
from app.views import BhavCopyEquityView, BhavCopyEquityDefaultRedisView, BhavCopyEquityCustomRedisView, EmptyRespoinseView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('emptyresponse/', EmptyRespoinseView.as_view(), name='emptyresponse_view'),
|
path('emptyresponse/', EmptyRespoinseView.as_view(), name='emptyresponse_view'),
|
||||||
path('bhavcopyequity/', BhavCopyEquityView.as_view(), name='bhavcopyequity_view'),
|
path('bhavcopyequity/', BhavCopyEquityView.as_view(), name='bhavcopyequity_view'),
|
||||||
path('bhavcopyequitydefaultredis/', BhavCopyEquityDefaultRedisView.as_view(), name='bhavcopyequitydefaultredis_view'),
|
path(
|
||||||
|
'bhavcopyequitydefaultredis/',
|
||||||
|
BhavCopyEquityDefaultRedisView.as_view(),
|
||||||
|
name='bhavcopyequitydefaultredis_view'
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
'bhavcopyequitycustomredis/',
|
||||||
|
BhavCopyEquityCustomRedisView.as_view(),
|
||||||
|
name='bhavcopyequitycustomredis_view'
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,18 @@ from io import BytesIO, TextIOWrapper
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
# third-party imports
|
# third-party imports
|
||||||
import django_rq
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from django_redis import get_redis_connection
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django_rq import job
|
|
||||||
|
|
||||||
# app imports
|
# app imports
|
||||||
from app.models import BhavCopyEquity
|
from app.models import BhavCopyEquity
|
||||||
|
|
||||||
|
|
||||||
|
cache = get_redis_connection("default")
|
||||||
|
|
||||||
|
|
||||||
def fetch_bhav_copy_equity_data(curr_date=None):
|
def fetch_bhav_copy_equity_data(curr_date=None):
|
||||||
"""Fetch data from BSE India website."""
|
"""Fetch data from BSE India website."""
|
||||||
# hack: since bseindia website doesn't respond well to python requests
|
# hack: since bseindia website doesn't respond well to python requests
|
||||||
|
|
@ -47,10 +49,34 @@ def fetch_bhav_copy_equity_data(curr_date=None):
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def populate_bhav_copy_data():
|
def populate_bhav_copy_data():
|
||||||
"""Populate DB with Bhav Copy data."""
|
"""Populate DB with Bhav Copy data."""
|
||||||
|
pipe = cache.pipeline()
|
||||||
data = fetch_bhav_copy_equity_data()
|
data = fetch_bhav_copy_equity_data()
|
||||||
del data[0]
|
del data[0] # delete title row
|
||||||
|
|
||||||
|
cache.delete("stocks")
|
||||||
for stock in data:
|
for stock in data:
|
||||||
# prevent creation of duplicate entries
|
# prevent creation of duplicate entries
|
||||||
|
pipe.rpush("stocks", stock[0])
|
||||||
|
pipe.hset(
|
||||||
|
f"stock:{stock[0]}",
|
||||||
|
mapping={
|
||||||
|
"sc_code": stock[0],
|
||||||
|
"sc_name": stock[1],
|
||||||
|
"sc_group": stock[2],
|
||||||
|
"sc_type": stock[3],
|
||||||
|
"open_price": float(stock[4]),
|
||||||
|
"high_price": float(stock[5]),
|
||||||
|
"low_price": float(stock[6]),
|
||||||
|
"close_price": float(stock[7]),
|
||||||
|
"last_price": float(stock[8]),
|
||||||
|
"prevclose_price": float(stock[9]),
|
||||||
|
"no_trades": int(stock[10]),
|
||||||
|
"no_of_shrs": int(stock[11]),
|
||||||
|
"net_turnov": float(stock[12]),
|
||||||
|
"tdcloindi": stock[13],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
pipe.execute()
|
||||||
BhavCopyEquity.objects.get_or_create(
|
BhavCopyEquity.objects.get_or_create(
|
||||||
sc_code=int(stock[0]),
|
sc_code=int(stock[0]),
|
||||||
sc_name=stock[1],
|
sc_name=stock[1],
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,17 @@
|
||||||
# third-party imports
|
# third-party imports
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
|
from django_redis import get_redis_connection
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views.decorators.cache import cache_page
|
from django.views.decorators.cache import cache_page
|
||||||
|
|
||||||
# app imports
|
# app imports
|
||||||
from app.models import BhavCopyEquity
|
from app.models import BhavCopyEquity
|
||||||
from app.serializers import BhavCopyEquitySerializer
|
from app.serializers import BhavCopyEquitySerializer
|
||||||
|
from app.utils import populate_bhav_copy_data
|
||||||
|
|
||||||
|
|
||||||
|
cache = get_redis_connection("default")
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
@ -36,3 +40,14 @@ class EmptyRespoinseView(generics.RetrieveAPIView):
|
||||||
return Response([])
|
return Response([])
|
||||||
|
|
||||||
|
|
||||||
|
class BhavCopyEquityCustomRedisView(generics.RetrieveAPIView):
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
pipe = cache.pipeline()
|
||||||
|
stocks = cache.lrange("stocks", 0, -1)
|
||||||
|
if len(stocks) == 0:
|
||||||
|
populate_bhav_copy_data()
|
||||||
|
stocks = cache.lrange("stocks", 0, -1)
|
||||||
|
for stock in stocks:
|
||||||
|
pipe.hgetall(f"stock:{stock}")
|
||||||
|
return Response(pipe.execute())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,10 @@ CACHES = {
|
||||||
'LOCATION': 'redis://redis:6379/1',
|
'LOCATION': 'redis://redis:6379/1',
|
||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
|
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
|
||||||
|
"REDIS_CLIENT_CLASS": "redis.client.StrictRedis",
|
||||||
|
"REDIS_CLIENT_KWARGS": {"decode_responses": True},
|
||||||
|
# Custom serializer
|
||||||
|
"SERIALIZER": "app.redis.JSONSerializer",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -155,6 +159,8 @@ RQ_QUEUES = {
|
||||||
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
|
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
|
||||||
SESSION_CACHE_ALIAS = "default"
|
SESSION_CACHE_ALIAS = "default"
|
||||||
CACHE_TTL = 60 * 5
|
CACHE_TTL = 60 * 5
|
||||||
|
DJANGO_REDIS_CONNECTION_FACTORY = "app.redis.ConnectionFactory"
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import axios from 'axios'
|
||||||
// TODO: fix baseurl as per builds
|
// TODO: fix baseurl as per builds
|
||||||
const getAPI = axios.create({
|
const getAPI = axios.create({
|
||||||
baseURL: 'http://127.0.0.1:8000',
|
baseURL: 'http://127.0.0.1:8000',
|
||||||
timeout: 5000,
|
timeout: 60000,
|
||||||
})
|
})
|
||||||
|
|
||||||
export { getAPI }
|
export { getAPI }
|
||||||
|
|
|
||||||
|
|
@ -96,11 +96,12 @@
|
||||||
return {
|
return {
|
||||||
sc_name: '',
|
sc_name: '',
|
||||||
apiData: [],
|
apiData: [],
|
||||||
apiEndpointSelected: { endpoint: 'bhavcopyequity', text: "Plain Endpoint" },
|
apiEndpointSelected: { endpoint: 'bhavcopyequitycustomredis', text: "Custom Redis Cache" },
|
||||||
apiEndpoints: [
|
apiEndpoints: [
|
||||||
{ endpoint: 'emptyresponse', text: "Empty Response Endpoint" },
|
{ endpoint: 'emptyresponse', text: "Empty Response Endpoint" },
|
||||||
{ endpoint: 'bhavcopyequity', text: "Plain Endpoint" },
|
{ endpoint: 'bhavcopyequity', text: "Plain Endpoint" },
|
||||||
{ endpoint: 'bhavcopyequitydefaultredis', text: "Default Redis Cache" }
|
{ endpoint: 'bhavcopyequitydefaultredis', text: "Default Redis Cache" },
|
||||||
|
{ endpoint: 'bhavcopyequitycustomredis', text: "Custom Redis Cache" },
|
||||||
],
|
],
|
||||||
headersData: [
|
headersData: [
|
||||||
{text: 'Stock Code', value: 'sc_code'},
|
{text: 'Stock Code', value: 'sc_code'},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue