Лучшая практика для фильтрации контента на основе идентификатора пользователя в Django? - PullRequest
0 голосов
/ 30 декабря 2011

Я создаю коллекцию фильмов на основе Django, которая хранит DVD / BD в базе данных. Приложение сохраняет эти фильмы в архив. Пользователь может иметь один архив, но архив может использоваться несколькими людьми (например, члены семьи могут совместно использовать один и тот же архив). И то же самое с моделями Django:

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    archive = models.ForeignKey(Archive, blank=True, null=True)

class Archive(models.Model):
    name = models.CharField(max_length=200)

class Movie(models.Model):
    archive = models.ForeignKey(Archive)
    title = models.CharField(max_length=200, null=True, blank=True)

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

Конечно, filter () выполнит эту работу, но есть ли способ выполнить фильтрацию, чтобы она выполнялась только один раз для всех представлений? С промежуточным программным обеспечением? Или декоратор?

Ответы [ 2 ]

2 голосов
/ 30 декабря 2011

Если ваш URL-стиль должен иметь что-то вроде /movies/some-movie/, ответ @ jknupp, вероятно, будет вашим лучшим выбором, но если вы делаете что-то более похожее на /user/some-user/movies/some-movie/. Обязанностью этого представления является обеспечение показа только фильмов, принадлежащих пользователю.

В любом случае, это в значительной степени все еще ответственность за представление, в той или иной форме. Это естественное разделение шаблона проектирования MVC (который использует Django, хотя и слабо). Модель не знает и не должна знать ничего о пользователе. Его цель - просто разрешить хранение и поиск данных в каждом сценарии. Представление, однако, знает о пользователях, потому что оно обрабатывает запрос и, следовательно, сеанс, поэтому любая обработка, относящаяся к сеансу (например, разрешения и аутентификация), относится к нему.

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

class MovieQuerySet(models.query.QuerySet):
    def allowed_for_user(self, user):
        return self.filter(archive__user=user)

class MovieManager(models.Manager):
    use_for_related_fields = True

    def get_query_set(self):
        return MovieQuerySet(self.model)

    def allowed_for_user(self, *args, **kwargs):
        return self.get_query_set().allowed_for_user(*args, **kwargs)

class Movie(models.Model):
    ...
    objects = MovieManager()

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

movies = Movie.objects.allowed_for_user(request.user)
0 голосов
/ 30 декабря 2011

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

...