django 缓存管理器方法带参数

问题描述

所以我有几个模特和这样的经理。

class Member(BaseModel):
    objects = models.Manager()
    permissions = api_managers.PermissionManager()
    Box = models.ForeignKey('api_backend.Box',on_delete=models.CASCADE)
    roles = models.ManyToManyField('api_backend.Role',through='api_backend.MemberRole')

    required_FIELDS = [Box,user]


class Role(BaseModel):
    objects = models.Manager()
    positions = api_managers.PositionalManager()
    name = models.CharField(default='new role',max_length=100,validators=[MinLengthValidator(2)])
    permissions = BitField(flags=permission_flags,default=default_perm_flags,db_index=True)
    is_default = models.BooleanField(default=False,db_index=True)
    position = models.PositiveSmallIntegerField(db_index=True,default=0)
    Box = models.ForeignKey('api_backend.Box',on_delete=models.CASCADE)

    required_FIELDS = [name,Box]


class MemberRole(BaseModel):
    objects = models.Manager()
    member = models.ForeignKey('api_backend.Member',on_delete=models.CASCADE)
    role = models.ForeignKey('api_backend.Role',on_delete=models.CASCADE)

    required_FIELDS = [member,role]

class Overwrite(BaseModel):
    objects = models.Manager()
    allow = BitField(flags=permission_flags,null=True,blank=True,db_index=True)
    deny = BitField(flags=permission_flags,db_index=True)
    channel = models.ForeignKey('api_backend.Channel',on_delete=models.CASCADE,editable=False)
    Box = models.ForeignKey('api_backend.Box',editable=False)
    role = models.OnetoOneField('api_backend.Role',db_index=True)

    required_FIELDS = [role,channel,Box]
from memoize import memoize


class PermissionManager(models.Manager):
    def __init__(self):
        super().__init__()

    @transaction.atomic
    @memoize(timeout=3600)
    def get_overwrites(self,channel):
        assert channel.Box == self.model.Box,'invalid channel given'
        permissions = self.get_base_permissions
        if channel.Box.owner == self.model.user:
            return permissions
        try:
            # get the default everyone role's overwrite
            default_role = self.model.Box.roles.get(is_default=True)
            default_overwrite = default_role.overwrite_set.get(channel=channel)
        except ObjectDoesNotExist:
            pass
        else:
            permissions &= set(~default_overwrite.deny)
            permissions |= set(default_overwrite.allow)
        member_role_ids = [role.id for role in self.model.roles.all()]
        overwrite_roles = channel.overwrites.filter(role__id__in=member_role_ids)

        deny,allow = None,None

        for overwrite in overwrite_roles:
            deny |= set(overwrite.deny)
            allow |= set(overwrite.allow)

        permissions &= ~deny
        permissions |= allow

        return permissions

如您所见,我的经理上的 get_overwrites 方法一个执行起来非常昂贵的过程。因此,我想缓存特定参数的值以提高性能

为此,我目前正在使用 django-memoize。 每当模型发生任何更新时,我都会像这样使缓存无效。

@receiver(post_delete,sender=api_models.Overwrite)
def on_overwrite_delete(instance=None,**kwargs):
    delete_memoized(api_models.Member.permissions.get_overwrites,instance.channel)

@receiver(post_save,sender=api_models.Overwrite)
def on_overwrite_save(instance=None,instance.channel)

@receiver(post_delete,sender=api_models.MemberRole)
def on_member_role_delete(instance=None,**kwargs):
    for overwrite in instance.role.overwrite_set.all():
        delete_memoized(instance.member.permissions.get_overwrites,overwrite.channel)

@receiver(post_save,sender=api_models.MemberRole)
def on_member_role_create(instance=None,overwrite.channel)

@receiver(post_delete,sender=api_models.Role)
def on_role_delete(instance=None,**kwargs):
    for overwrite in instance.overwrite_set.all():
        delete_memoized(api_models.Member.permissions.get_overwrites,sender=api_models.Role)
def on_role_save(instance=None,overwrite.channel)

但是,这种方法是否值得推荐?有没有更好的方法来做同样的事情? 现在,我觉得我必须坚持这一点,因为 django 在 3.0 版本中放弃了对 LRU-cache 的支持

此外,我认为 memoize-deletion 过程非常无效 (因为在这种情况下我也必须遵循反向关系)

有人可以帮我吗? 非常感谢!

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)