Comments 14
def form_valid(self, form):
Post.objects.create(**form.cleaned_data)
return redirect(self.get_success_url())
Это жесть и чревато ошибками. Лучше так:
def form_valid(self, form):
# Мы используем ModelForm, а его метод save() возвращает инстанс
# модели, связанный с формой. Аргумент commit=False говорит о том, что
# записывать модель в базу рановато.
instance = form.save(commit=False)
# Теперь, когда у нас есть несохранённая модель, можно ей чего-нибудь
# накрутить. Например, заполнить внешний ключ на auth.User. У нас же
# блог, а не анонимный имижборд, правда?
instance.user = request.user
# А теперь можно сохранить в базу
instance.save()
return redirect(self.get_success_url())
И ещё: не надоело в каждой вьюхе писать что-то такое?
@method_decorator(login_required)
def dispatch(self, request, *args, **kwargs):
super(CreatePost, self).dispatch(request, *args, **kwargs)
Особенно нелепо это выглядит на фоне class based, основная идея которого — избавить нас от рутины. Почему бы не сделать миксин, в котором все лишь раз прописать эту магическую формулу, а потом уже наследовать все вьюхи от него?
+1
Это жесть и чревато ошибками. Лучше так
Ну в принципе я указал, что все примеры синтетические. В любом случае перед сохранением объекта потребуются дополнительные проверки или необходимо проставить внешние ключи, о чем вы уже упомянули. Не хотелось просто перегружать примеры логикой, которая не связанна непосредственно с ними. Спасибо за пример, добавлю и его как демонстрация более правильного решения данной задачи.
И ещё: не надоело в каждой вьюхе писать что-то такое?
Как я выше упомянул — примеры надуманные и не связанные между собой. Это не часть какого-то проекта, я просто упомянул о существовании данной возможности
Разумеется если вам потребуются соответсвующие проверки на наличие авторизации у пользователей или соответствующих прав, то вы можете сделать это используя декораторы для метода dispatch или добавить свою логику проверки:
Спасибо еще раз за объективную критику, на мой взгляд многие из ваших комментариев были полезнее самой статьи)
+1
Ну как минимум миксинов будет не один, а пачка.
В реальном проекте часто бывает нужен не один, а два-три декоратора в разном сочетании.
Ну и для передачи параметров для миксинов придется писать код в любом случае.
В реальном проекте часто бывает нужен не один, а два-три декоратора в разном сочетании.
Ну и для передачи параметров для миксинов придется писать код в любом случае.
0
Давайте всё же попробуем обойтись одним миксином безо всяких пачек? =)
А потом нам потребуется всего лишь перечислить требуемые декораторы в нужном порядке:
Но это, что называется, низкий уровень. Если хочется абстракций, можно пытаться писать микшины с изменяемым поведением:
Наследуемся и когда потребуется сменить логику проверки доступа пользователя, просто перекрываем
class DecoratorChainingMixin(object):
def dispatch(self, *args, **kwargs):
decorators = getattr(self, 'decorators', [])
base = super(DecoratorChainingMixin, self).dispatch
for decorator in decorators:
base = decorator(base)
return base(*args, **kwargs)
А потом нам потребуется всего лишь перечислить требуемые декораторы в нужном порядке:
class MyView(DecoratorChainingMixin, UpdateItem):
form_class = ItemForm
model = Item
decorators = [login_required, never_cache, i_cherta_lysogo_v_stupe(foo='bar')]
Но это, что называется, низкий уровень. Если хочется абстракций, можно пытаться писать микшины с изменяемым поведением:
class UserPassesTestMixin(object):
def user_passes_test(self, user):
return user.is_authenticated()
def user_failed_test(self):
return redirect(LOGIN_URL)
def dispatch(self, request, *args, **kwargs):
if not self.user_passes_test(request.user):
return self.user_failed_test()
return super(UserPassesTestMixin, self).dispatch(request, *args, **kwargs)
Наследуемся и когда потребуется сменить логику проверки доступа пользователя, просто перекрываем
user_passes_test
. В том маловероятном случае, если не устраивает редирект на страницу логина, можно перекрыть и user_failed_test
.+4
Это уже интереснее. Спасибо!
Попробую первый вариант использовать в текущем проекте :)
Нужно пнуть разработчиков django чтобы улучшили работу с декораторами.
Да и вообще текущая документация по CBV очень куцая…
Попробую первый вариант использовать в текущем проекте :)
Нужно пнуть разработчиков django чтобы улучшили работу с декораторами.
Да и вообще текущая документация по CBV очень куцая…
0
В стиле django это должно называться иначе:
-class DecoratorChainingMixin(object):
+class ClassBasedViewMiddleware(object):
0
login_required можно оборачивать в urls.py.
url(r'^/register$', login_required(AnyView.as_view())),
url(r'^/register$', login_required(AnyView.as_view())),
0
а это конец или будет еще? Можно еще тему миксинов разжувать :)
0
В наборе стандартных CBV не хватает вьюх для обработки формсетов и работы с дочерними объектами (inline). В нескольких проектах требовался такой функционал. Еще пара подобных проектов и можно будет куда-нибудь выложить боле-менее универсальное решение.
0
Спасибо за цикл статей. Как-то потратил много времени, чтобы разобраться.
0
Sign up to leave a comment.
Немного подробностей про Class Based Views, ч.4