Фильтрация данных в соответствии с пользователем, зарегистрированным в приложении Django

#django #tdd #filtering

#django #tdd #фильтрация

Вопрос:

У меня есть приложение Django, которое хорошо работает для меня, но в настоящее время не имеет понятия о пользователе: я единственный, кто его использует, и я хотел бы это изменить…

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

  • Я полагаю, мне нужно добавить user внешний ключ ко всем созданным мной моделям. Правильно?

  • Есть ли простой способ реализовать фильтрацию на основе request.user ? Можно ли это сделать более или менее автоматически, или мне нужно просмотреть весь код, чтобы проверить каждый запрос, выполняемый в базе данных?

  • Я написал код с использованием TDD, и я намерен продолжить… Каковы наилучшие стратегии для обеспечения правильной реализации фильтрации пользователей, например, чтобы я не забыл отфильтровать существующий запрос? Я полагаю, я могу написать тесты, которые показывают, что конкретный запрос еще не отфильтрован, и реализовать фильтр. Но как насчет запросов, которые я напишу позже? Есть ли способ, которым я могу утверждать, что все существующие и будущие запросы возвращают объекты, которые принадлежат только текущему пользователю?

Спасибо.

Ответ №1:

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

Одним из способов реализации фильтра было бы определение пользовательских менеджеров для ваших моделей с for_user методом, который принимает пользователя в качестве аргумента: что-то вроде:

 class ForUserManager(models.Manager):
    def for_user(self, user):
        return self.filter(user=user)
  

Теперь вы можете использовать этот менеджер — с подклассами и / или с микшированием по мере необходимости — на всех ваших моделях и не забывайте использовать objects.for_user(request.user) везде.

Это также упростит тестирование — ваш тест может использовать этот for_user метод, чтобы он устанавливал флаг или счетчик где-нибудь в глобальной переменной, а затем проверял, что он увеличился, как ожидалось.

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

Комментарии:

1. Я могу представить следующее: когда пользователь входит в систему, я создаю экземпляр подкласса Manager, который (1) хранит user и (2) использует его для фильтрации набора запросов в get_query_set . Затем я устанавливаю этот менеджер по умолчанию для своих моделей. Будет ли это работать с несколькими разными пользователями? Или все пользователи будут видеть объекты для последнего подключенного пользователя? Боюсь, последнее…