2016-07-23 4 views
2

У меня есть модель с именем Post и поле с названием owner (внешний ключ User). Конечно, только владельцы могут update или delete свои собственные сообщения.Django: принцип DRY и UserPassesTestMixin

Это, как говорится, я использую login_required декоратора в представлениях, чтобы убедиться, что пользователь вошел в систему, но тогда, мне также нужно убедиться, что пользователь пытается update/delete вопрос является owner.

Как я использую Django: Generic Editing Views В документации говорится, что мне нужно использовать Django: UserPassesTestMixin.

Эта валидация будет сделана для изображений update и delete. СУХОЙ, каков способ этого? должен ли я создать класс с именем TestUserOwnerOfPost и создать test_func(), а затем сделать вид update и delete наследовать?

Потому что это то, что я пытался и не работать, код ниже:

from django.views.generic.edit import UpdateView 
from django.contrib.auth.decorators import login_required 
from django.contrib.auth.mixins import UserPassesTestMixin 

class TestUserOwnerOfPost(UserPassesTestMixin):       
    def test_func(self):              
     return self.request.user == self.post.owner 

class EditPost(UpdateView, TestUserOwnerOfPost):       
    model = Post                   
    @method_decorator(login_required)           
    def dispatch(self, *args, **kwargs):          
     return super(EditPost, self).dispatch(*args, **kwargs) 

С кода выше, каждый зарегистрированный пользователь в системе может edit/delete любой пост. Что я делаю не так? я что-то упускаю? Благодарю.

ответ

4

Первая проблема заключается в том, что порядок классов вы наследующих неверно, так как @rafalmp говорит.

Однако фиксация, которая не решает проблему, поскольку миксин UserPassesTest выполняет тест до, управляющий представлением. Это означает, что не стоит проверять владельца self.object, потому что self.object еще не установлен. Примечание. Я использую self.object вместо self.post. Я не думаю, что представление когда-либо устанавливает self.post, но я могу ошибаться.

Один из вариантов заключается в вызове self.get_object() внутри функции тестирования. Это немного неэффективно, потому что ваше представление будет извлекать объект дважды, но на практике это, вероятно, не имеет значения.

def test_func(self): 
    self.object = self.get_object() 
    return self.request.user == self.object.owner 

Другой подход заключается в переопределении get_queryset, чтобы ограничить его объектов, принадлежащих пользователю. Это означает, что пользователь получит ошибку 404, если они не владеют объектом. Это не совсем то же самое, что и UserPassesTestMixin, который будет перенаправляться на страницу входа, но это может быть хорошо для вас.

class OwnerQuerysetMixin(object):       
    def get_queryset(self): 
     queryset = super(OwnerQuerysetMixin, self).get_queryset()             
     # perhaps handle the case where user is not authenticated 
     queryset = queryset.filter(owner=self.request.user) 
     return queryset 
+0

Большое спасибо за подробное объяснение. И мне имеет смысл ограничивать объекты теми, которые принадлежат пользователю. Просто один быстрый вопрос: для этого мне нужно наследовать 'OwnerQuerysetMixin' до' UpdateView'. Почему это?Я думал, что 'get_queryset' был методом из« UpdateView »и должен быть перезаписан тем, который был у меня в' OwnerQuerysetMixin', с этой мыслью (помиловать меня, если я чего-то не хватает) имеет смысл наследовать 'OwnerQuerysetMixin' после «UpdateView». Вздох, я просто хочу понять, как здесь работает наследование. – gglasses

+1

[Этот вопрос] (http://stackoverflow.com/questions/10018757/how-does-the-order-of-mixins-affect-the-derived-class) может помочь вам понять порядок. – Alasdair

2

Порядок классов, которые вы наследуете от вопросов. Для контроля доступа к работе, оно должно быть обеспечено до UpdateView выполняется:

class EditPost(TestUserOwnerOfPost, UpdateView): 
+0

В самом деле, но я получаю '«AttributeError: EditPost»объект не имеет атрибута«post'':/ – gglasses

+0

Ну, я на самом деле получить это потому, что UpdateView является объектом, который фактически получает объект 'Post' и ваш путь я импортирую «TestUserOwnerOfPost» первым. Дело в том, как я могу выполнить мою проверку? – gglasses

Смежные вопросы