Django prefetch_related和很多对多关系

时间:2012-12-19 14:33:21

标签: django django-models django-permissions

我有这些模特:

class Permission(models.Model):

    name = models.CharField(u'Name', max_length=100)
    codename = models.CharField(u'Code name', max_length=100)

class Role(models.Model):

    name = models.CharField(u'Name', max_length=80)
    organization = models.ForeignKey(Organization)
    permissions = models.ManyToManyField(Permission, blank=True)

class UserProfileManager(models.Manager):

    def get_query_set(self):
        return super(UserProfileManager, self).get_query_set().select_related(
            'user', 'organization'
        )

class UserProfile(models.Model):

    user = models.OneToOneField(User)

    organization = models.ForeignKey(Organization, blank=True)
    roles = models.ManyToManyField(Role, blank=True)
    permissions = models.ManyToManyField(Permission, blank=True)

    objects = UserProfileManager()

我想阅读最多2个SELECTS的所有用户权限('permissions'和'roles__permissions')。

如果我尝试将prefetch_related('permissions', 'roles__permissions')添加到UserProfileManager,我会得到3个SELECT(对于权限,角色和角色_权限)

怎么做?

2 个答案:

答案 0 :(得分:0)

这些是我的一些辅助功能:

class UserProfile(models.Model):

    def get_permissions_user(self):
        if not hasattr(self, '_perm_user_cache'):
            perms = self.permissions.select_related()
            self._perm_user_cache = set([u'%s' % (p.codename) for p in perms])

        return self._perm_user_cache

    def get_permissions_group(self):
        if not hasattr(self, '_perm_group_cache'):
            perms = Permission.objects.filter(role__userprofile = self)
            self._perm_group_cache = set([u'%s' % (p.codename) for p in perms])

        return self._perm_group_cache

    def get_permissions(self):
        if not hasattr(self, '_perm_cache'):
            self._perm_cache = set()
            self._perm_cache.update(self.get_permissions_user())
            self._perm_cache.update(self.get_permissions_group())

        return self._perm_cache

答案 1 :(得分:0)

阅读此问题:A left outer reverse select_related in Django?

当时,Django没有prefetch_related(),所以我通过使用{% regroup %}模板标签或在视图中查询最少的模型并重新组合结果来解决它类型的字典。

在多对多的情况下,最少的表格为through

# one way of optimizing: building a dict accessable by id
# beware to do this in really large tables
permissions = dict([(p.id, p) for p in Permission.objects.all()])

permission_roles = Role.permissions.through.select_related('role').all()
for permission_role in permission_roles:
    # permission_role is an object that associates a role with a permission
    # note that we haven't selected "permission", but permission_id is available:
    role = permission_role.role
    permission = permissions[permission_role.permission_id]