Пользовательские менеджеры Django - как вернуть только объекты, созданные вошедшим в систему пользователем? - PullRequest
29 голосов
/ 05 января 2010

Я хочу перезаписать менеджер модели пользовательских объектов, чтобы он возвращал только объекты, созданные конкретным пользователем. Пользователи с правами администратора должны по-прежнему возвращать все объекты, используя менеджер моделей объектов.

Теперь я нашел подход , который мог бы работать. Они предлагают создать ваше собственное промежуточное программное обеспечение, похожее на это:

#### myproject/middleware/threadlocals.py

try:
    from threading import local
except ImportError:
    # Python 2.3 compatibility
    from django.utils._threading_local import local

_thread_locals = local()

def get_current_user():
    return getattr(_thread_locals, 'user', None)

class ThreadLocals(object):
    """Middleware that gets various objects from the
    request object and saves them in thread local storage."""
    def process_request(self, request):
        _thread_locals.user = getattr(request, 'user', None)

#### end

А в пользовательском менеджере вы можете вызвать метод get_current_user(), чтобы вернуть только объекты, созданные конкретным пользователем.

class UserContactManager(models.Manager):
    def get_query_set(self):
        return super(UserContactManager, self).get_query_set().filter(creator=get_current_user())

Это хороший подход к этому варианту использования? Будет ли это работать? Или это как «использовать кувалду, чтобы сломать орех»? ; -)

Просто используя:

Contact.objects.filter(created_by= user)

в каждом представлении выглядит не очень аккуратно для меня.

РЕДАКТИРОВАТЬ Не используйте этот подход промежуточного программного обеспечения !!!

используйте подход, изложенный Джеком М. ниже

Через некоторое время тестирования этот подход вел себя довольно странно, и с этим подходом вы смешиваете глобальное состояние с текущим запросом.

Используйте подход, представленный ниже. Это действительно легко и не нужно взламывать промежуточное ПО.

создайте собственный менеджер в вашей модели с функцией, которая ожидает текущего пользователя или любого другого пользователя в качестве ввода.

#in your models.py
class HourRecordManager(models.Manager):
    def for_user(self, user):
        return self.get_query_set().filter(created_by=user)

class HourRecord(models.Model):
    #Managers
    objects = HourRecordManager()

#in vour view you can call the manager like this and get returned only the objects from the currently logged-in user.

hr_set = HourRecord.objects.for_user(request.user)

См. Также это обсуждение о подходе промежуточного программного обеспечения.

Ответы [ 4 ]

50 голосов
/ 29 января 2010

Один из способов справиться с этим - создать новый метод вместо переопределения get_query_set. Что-то вроде:

class UserContactManager(models.Manager):
    def for_user(self, user):
        return super(UserContactManager, self).get_query_set().filter(creator=user)

class UserContact(models.Model):
    [...]
    objects = UserContactManager()

Это позволяет вашему взгляду выглядеть так:

contacts = Contact.objects.for_user(request.user)

Это должно помочь сделать ваш обзор простым, и поскольку вы будете использовать встроенные функции Django, он вряд ли сломается в будущем.

6 голосов
/ 05 января 2010

Кажется необходимым использовать промежуточное программное обеспечение для хранения пользовательской информации.

Однако я бы предпочел не изменять ModelManager по умолчанию objects, а подключить его к другому менеджеру., что я буду использовать в коде, скажем, в вашем случае user_objects вместо объектов.

Поскольку вы будете использовать это только в представлениях, которые @login_required, вам не нужна вся сложная обработка ошибок в Middleware.

Только мои 2 *.

2 голосов
/ 11 февраля 2010

Спасибо, что поделились кодом. Не очень хорошее решение с точки зрения тестируемости, но я не нашел другого способа настроить менеджеров моделей по данным объекта запроса. Было бы лучше иметь контроль над созданием менеджера, но Django не позволяет этого.

0 голосов
/ 22 августа 2017

Или даже проще и используйте внешний ключ для получения набора запросов.

Если у вас есть такая модель

class HourRecord(models.Model):
    created_by = ForeignKey(get_user_model(), related_name='hour_records')

Вы можете запросить HourRecords в представлении пользователя просто:

request.user.hour_records.all()
...