Использование Django Managers для ограничения запросов пользователем - PullRequest
1 голос
/ 07 февраля 2011

Скажем, у меня есть два типа пользователей: краткое и длинное .

Когда пользователь краткий входит в систему, он должен видеть только самые последние 10 элементов.Когда пользователь long входит в систему, он должен увидеть последние 30 элементов.В остальном они очень похожи.

Полагаю, я мог бы использовать менеджеров Django для реализации чего-то вроде этого:

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]

Я думаю о патчах обезьян Item возможно, используя Middleware, так что остальная часть кода не замечает, является ли пользователь краткое или длинное . Элемент .objects менеджер будет установлен в BriefItemManager или LongItemManager к моменту запуска основного кода.

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

Вопросы:

  • Являются ли менеджеры правильным способом реализации этого?
  • Является ли monkeypatching Item s .objects менеджер правильный путь?Есть ли способ чище?

1 Ответ

2 голосов
/ 08 февраля 2011

Вы не хотели бы устанавливать эту присоску, потому что, как только тип Item создан, его состояние затем разделяется между потоками, что включает в себя менеджер по умолчанию.Тогда вы можете получить 10 элементов, даже если пользователь для текущего запроса имеет тип long, потому что у вас есть конфликт потоков в менеджере моделей.(см. ModelBase в пакете django.db.models.base)

В вашем случае вы захотите сделать совершенно очевидным, что вы делаете.Это мое лучшее предположение:

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).Это просто основная идея, и существуют другие способы, такие как прокси-классы, которые являются идеальными (единственный верный способ) для переопределения менеджеров моделей.

Менеджеры - это правильный способ реализации всего, что работает с коллекциями.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...