Пользовательские менеджеры 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()