使用Django Managers限制用户查询

时间:2011-02-07 20:23:24

标签: django

假设我有两种类型的用户:简短

简要用户登录时,他应该只能看到最近的10个项目。当 long 用户登录时,他应该会看到最近的30个项目。否则他们非常相似。

我相信我可以使用Django Managers来实现这样的东西:

class Item(models.Model):
    name = models.CharField(max_length=200)
    date = models.DateField()

class BriefItemManager(models.Manager):
    def get_query_set(self):
        return super(BriefItemManager, self).get_query_set().order_by('date')[:10]

class LongItemManager(models.Manager):
    def get_query_set(self):
        return super(LongItemManager, self).get_query_set().order_by('date')[:30]

我正在考虑猴子修补项目,也许使用中间件,以便其余代码无视用户是简要还是 。在主代码启动时, .objects 管理器将被设置为 BriefItemManager LongItemManager 英寸

if user_type(request.user) == 'brief':
    Item.objects = BriefItemManager()
else:
    Item.objects = LongItemManager()

问题:

  • 管理者是否是实现此目的的正确方法?
  • monkeypatching Item .objects 经理是正确的方法吗?有更干净的方式吗?

1 个答案:

答案 0 :(得分:2)

你不希望monkeypatch那个sucker,因为一旦Item类型被创建,它的状态就会在线程之间共享,其中包括默认的管理器。即使当前请求的用户属于long类型,也可以检索10个项目,因为模型管理器上存在线程争用。 (请参阅包django.db.models.base)中的ModelBase

在你的情况下,你会想要明确你做的是什么。这是我最好的猜测:

class ItemManager(models.Manager):

    def latest_for_user_type(user_type):
        limit = user_type=='brief' and 10 or user_type=='long' and 30
        return self.get_query_set().order_by('date')[:limit]

class Item(models.Model)

    # ...

    objects = ItemManager()

# views.py

class LatestItemListView(ListView):

    def get_query_set(self):
        return Item.objects.latest_for_user_type(
            user_type=user_type(self.request.user)
        )

您可能希望在user_type()中实施ItemManager逻辑...您甚至可能希望将其重构为latest_for_user(user=None, user_type=None)。这只是基本思想,还有其他方法,如代理类,是覆盖模型管理器的理想选择(唯一的方法)。

管理者是实施集合操作的正确方法。