Django 的 Model 对象转化为字典以及缓存中获取数据

目录

  • 将单个对象转化为字典
  • 将 QuerySet 转为列表
  • 从缓存中获取数据
  • 缓存的自动刷新

将单个对象转化为字典

对象通过 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

将 QuerySet 转为列表


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)

你可能感兴趣的:(Django,redis,django)