Пользовательские менеджеры Django-как вернуть только объекты, созданные зарегистрированным пользователем?

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

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

#### 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())

Is это хороший подход в этом случае? Это сработает? Или это как "с помощью кувалды расколоть орех"? ;-)

просто используешь:

Contact.objects.filter(created_by= user)

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

EDIT не используйте этот подход промежуточного программного обеспечения !!!

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

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

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

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

#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)

см. также обсуждение о подходе middelware.

4 ответов


один из способов справиться с этим - создать новый метод вместо переопределения 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, это вряд ли сломается в будущем.


кажется, надо использовать промежуточное ПО для хранения информации пользователя.

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

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

просто мой 2¢.


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


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

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

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

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

request.user.hour_records.all()