对象通过 model.objects.filter().first() 、model.objects.get() 或者 for i in QuerySet 等方式获得。
def convert_obj_to_dict(obj, fields=None, exclude=None):
"""
将 Model 对象 obj 转化为字典格式返回
:param obj: 通过 model.objects.filter().first() 、model.objects.get() 或者 for i in QuerySet 获取的对象
:param fields: 要选择性呈现的字段
:param exclude: 排除呈现的字段
:return: 返回字典 {'id': 1, 'field1': 'field1_data'}
"""
data = {}
for f in getattr(obj, '_meta').concrete_fields + getattr(obj, '_meta').many_to_many:
value = f.value_from_object(obj)
if fields and f.name not in fields:
continue
if exclude and f.name in exclude:
continue
if isinstance(f, ManyToManyField):
value = [i.id for i in value] if obj.pk else None
elif isinstance(f, DateTimeField):
value = value.strftime('%Y-%m-%d %H:%M:%S') if value else None
elif isinstance(f, DateField):
value = value.strftime('%Y-%m-%d') if value else None
elif isinstance(f, TimeField):
value = value.strftime('%H:%M:%S') if value else None
elif isinstance(f, Decimal):
value = float_value(f)
# ForeignKey 特殊处理
if isinstance(f, ForeignKey):
data[f.column] = value
data[f.name] = value
else:
data[f.name] = value
# 获取 property 里面的数据
for p in getattr(getattr(obj, '_meta'), '_property_names'):
value = getattr(obj, p)
if isinstance(value, (str, int, Decimal)):
data[p] = value
return data
def model_obj_to_dict(objs, fields=None, exclude=None):
"""
将 model对象 或 QuerySet 转化成 字典 或者 列表 数据
:param objs: 相应的对象
:param fields: 需要的字段
:param exclude: 排除的字段
:return: 返回字典或列表
"""
if isinstance(objs, QuerySet):
data = list()
for obj in objs:
data.append(convert_obj_to_dict(obj, fields=fields, exclude=exclude))
else:
data = convert_obj_to_dict(objs, fields=fields, exclude=exclude)
return data
缓存的使用需要安装相应的依赖,例如 django-redis。请自行安装。
import redis
from django_redis import get_redis_connection
def get_redis():
"""
获取 Redis 的连接
"""
pool = get_redis_connection('default').connection_pool
r = redis.Redis(connection_pool=pool)
return r
def hset_data(name, key, value):
# 将数据存储到 redis 缓存中
r = get_redis()
value = json.dumps(value)
r.hset(name, key, value)
def hget_data(name, key):
# 从 redis 缓存中获取数据
r = get_redis()
value = r.hget(name, key)
if value:
value = json.loads(value)
return value
def model_data_from_cache(model, pk, force_update=False):
"""
从缓存中获取数据,返回字典数据。
:param model: 数据对应的 Model
:param pk: 对应的 ID
:param force_update: 是非强制更新
:return: 返回序列化后的数据字典 {"id": 1, "field1": "field1_data"}
"""
app_label = getattr(model, '_meta').app_label
model_name = getattr(model, '_meta').model_name
name = 'model_{}_{}'.format(app_label, model_name)
pk = int_value(pk)
if force_update:
data = {}
else:
data = hget_data(name, pk)
# 没有数据,从数据库中获取,并且永久放入缓存中
if not data:
obj = model.objects.filter(pk=pk).first()
if obj:
value = convert_obj_to_dict(obj)
else:
value = {}
hset_data(name, key=pk, value=value)
data = hget_data(name, pk)
return data
def model_data_dict_from_cache(model, pks):
"""
通过缓存获取数据。
:param model:
:param pks: 需要查询数据的 ID,可以传人列表,例如 [1, 2],也可以传入文本,例如 ’1,2‘
:return: 返回以id为键的数据字典 {1:{}, 2: {}}
"""
app_label = getattr(model, '_meta').app_label
model_name = getattr(model, '_meta').model_name
name = 'model_{}_{}'.format(app_label, model_name)
need_update_pks = list()
res_data = dict()
# 如果传入的id是文本,转换为列表
if isinstance(pks, str):
pk_list = pks.split(',')
while '' in pk_list:
pk_list.remove('')
pks = pk_list
for pk in pks:
new_pk = int_value(pk)
# 从缓存里面获取数据
current_data = hget_data(name, pk)
res_data[new_pk] = current_data
# 获取要更新的数据所对应的ids
if not current_data:
need_update_pks.append(new_pk)
if need_update_pks:
objs = model.objects.filter(pk__in=need_update_pks)
for obj in objs:
if obj:
value = convert_obj_to_dict(obj)
current_pk = value['id']
hset_data(name, key=current_pk, value=value)
res_data[current_pk] = hget_data(name, current_pk)
return res_data
通过 sginals 在对象保存以后自动将缓存写入。
from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
@receiver(post_save, sender=School)
def post_save_school(sender, instance, **kwargs):
model_data_from_cache(sender, instance.pk, force_update=True)