Comments 78
большинство таких задач решается через CBV.
обычно создаю базовый класс от TemplateView с методами:
* reverse
* redirect
* json_response
* get_object_or_404
* оберктой над django.contrib.messages вида self.messages.success('Hello, man!')
* get_model
и др.
для login_required так же делается класс-потомок от предыдущего с переопределенным методом dispatch.
все это избавляет от кучи импортов в каждом views.py и добавляет удобства в работе.
обычно создаю базовый класс от TemplateView с методами:
* reverse
* redirect
* json_response
* get_object_or_404
* оберктой над django.contrib.messages вида self.messages.success('Hello, man!')
* get_model
и др.
для login_required так же делается класс-потомок от предыдущего с переопределенным методом dispatch.
все это избавляет от кучи импортов в каждом views.py и добавляет удобства в работе.
+4
Кажется, Вы перемудрили :-)
get_object_or_404 — это как get_object() в DetailView. Что такое get_model не очень из контекста ясно, но наверняка в List/Detail не пригодится. А вместо json_response, я считаю, лучше пользовать микшин.
get_object_or_404 — это как get_object() в DetailView. Что такое get_model не очень из контекста ясно, но наверняка в List/Detail не пригодится. А вместо json_response, я считаю, лучше пользовать микшин.
0
from django.db.models import get_model
entries = get_model('auth', 'User').objects.get(...)
0
а теперь сделайте DetailView с login_required :)
можно через urls.py, но это зачастую размазывает логику по urls.py и views.py
можно через urls.py, но это зачастую размазывает логику по urls.py и views.py
0
Ох, сколько раз мне это приходилось делать…
0
Ох уж эти новомодные горячие клавиши.
class LoginRequiredMixin(object):
@ method_decorator(login_required) # пробел после собачки надо убрать.
def dispatch(self, request, *args, **kwargs):
return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
class PostDetailView(LoginRequiredMixin, DetailView):
model = Post
0
все круто и юзабельно, пока не нужно добавить свою логику в login_required. например, логгирование попыток входа.
а за DetailView — отдельное спасибо, не внимательно читал доки, не знал за него.
а за DetailView — отдельное спасибо, не внимательно читал доки, не знал за него.
0
развидьте предыдущий комментарий на счет попыток входа, фигню написал, туплю в конце недели.
+1
Я показал лишь пример
И уже потом от него наследовать LoginRequired ;)
Главное — вовремя остановиться =)
LoginRequiredMixin
. Разумеется, можно сделать более общий микшин UserPassesTestMixin и организовать его по образу и подобию аналогичного декоратора. class LoginRequiredMixin(object):
@ method_decorator(login_required) # пробел после собачки надо убрать.
def dispatch(self, request, *args, **kwargs):
if self.test():
return super(LoginRequiredMixin, self).dispatch(request, *args, **kwargs)
else:
return self.test_failed()
def test_failed(self):
"Response в случае ошибки"
def test(self):
return True
И уже потом от него наследовать LoginRequired ;)
class LoginRequiredMixin(UserPassesTestMixin):
def test(self):
return self.request.user.is_authenticated()
Главное — вовремя остановиться =)
+1
Классы сложнее функций, а композиция проще, чем наследование. Я выбираю более простой способ писать вьюхи. Я допускаю, что возможна ситуация когда код на CBV будет проще, но сам с таким не сталкивался.
В любом случае, считать функциональные вьюхи устаревшими попросту неправильно.
В любом случае, считать функциональные вьюхи устаревшими попросту неправильно.
+4
С другой стороны необходимость кучи импортов раздражает. Я даже подумывал сделать спец. пакет, сложить туда всё дерьмо и делать:
from handy.shits import *
-2
Вот что думает один из core developerов Django по поводу CBV: lukeplant.me.uk/blog/posts/djangos-cbvs-were-a-mistake/.
И это не только его мнение, классы сложны в поддержке и понимании. А сила Pythonа в том, что код легко понимается с одного взгляда.
И это не только его мнение, классы сложны в поддержке и понимании. А сила Pythonа в том, что код легко понимается с одного взгляда.
+2
post = Post.objects.get(pk=request.GET['id'])
вы действительно используете такую конструкцию в реальных проектах? без валидации?
-4
?id=ololotrololo';delete from auth_users;
во так например
-3
Джанго экранирует подставляемые значения.
+2
Не сообразил =)
Впрочем, удаления тут не произойдёт. Будет некрасивая «пятисотка», но да, это плохо. Согласен.
Впрочем, удаления тут не произойдёт. Будет некрасивая «пятисотка», но да, это плохо. Согласен.
0
А разве django не использует preparedStements для запросов?
0
Нет, не использует, он использует клиенты для бд, которые следуют Python Database API, в котором экранирование параметров осуществляется на клиенте средствами этих библиотек.
В результате SQL-инъекции при запросе через ORM не будет.
В результате SQL-инъекции при запросе через ORM не будет.
+1
Ясно, получается, что в случае MySQL и MySQLdb мы не сможем использовать server-side prepared statements
0
Ну через ORM нет, а так там есть расширения, только зачем?
0
Запросы будут бегать быстрее, ведь не надо будет каждый раз строить план выполнения запроса
0
Зато планы будут неоптимальны, потому как будут строиться без знания конкретных значений.
0
Откуда такая информация? Как по вашему происходит выполнения запроса в СУБД?
0
Примерно так — пришедший запрос парсится в какое-то внутреннее представление, потом для него готовится план выполнения. При составлении плана могут использоваться значения в условиях, например, если какое-то условие выберет небольшое количество рядов (по прогнозам), то будет использоваться соответствующий индекс, если много, то просто последовательное сканирование.
0
Всё это относится к PostgreSQL:
wiki.postgresql.org/wiki/FAQ#Why_is_my_query_much_slower_when_run_as_a_prepared_query.3F
В MySQL возможно планирование попроще и выиграть на подготовленных запросах действительно можно.
wiki.postgresql.org/wiki/FAQ#Why_is_my_query_much_slower_when_run_as_a_prepared_query.3F
В MySQL возможно планирование попроще и выиграть на подготовленных запросах действительно можно.
0
Хм, очень странно такое поведение Postgres-а. Ересь какая-то. Просто очень плотно работал с oracle, для которого неиспользование PreparedStatement-ов приводит к очень грустным результатам. Может просто не надо делать оптимизацию на уровне компилирования запроса, а уж если очень хочется — строить общий план, а потом корректировать на основании полученных данных. По крайней мере мы избегаем компиляции запроса, что для сложных запросов даст припрост.
0
Ну в 9.1, вроде, добавили перестройку плана при получении реальных параметров, но я не вижу где тут можно много времени выиграть — парсинг запроса не такая уж сложная вещь.
0
Ну у вас получается разобраный запрос во внутреннем представлении и план на основе синтаксиса запроса. Уже будет выигрыш. А если запрос большой? Интерпретация его каждый раз тоже небесплатна
0
Ну да, но это не так уж и медленно, а вот если план неэффективен, то можно замедлиться сразу в тысячи раз.
Да и большинство юзкейсов покрывают INSERT… VALUES… и UPDATE… VALUES…
Да и большинство юзкейсов покрывают INSERT… VALUES… и UPDATE… VALUES…
0
Я так понял план неправильно считает постгре, и то как Вы написали-они поправили это дело. Mysql строит не весь план в случае prepared statements. Так что то, что preparedstatements медленные в постгре можно отнести к недальновидности разработчиков постгряшного оптимизатора.
Что касается юзкейсов — Вы почему то опустили селекты, которые в данном случае намного интереснее. Если у Вас селект в полстраницы — его разбирать уже не так быстро.
Что касается юзкейсов — Вы почему то опустили селекты, которые в данном случае намного интереснее. Если у Вас селект в полстраницы — его разбирать уже не так быстро.
0
500-ку можно сделать красивой. Выдавать 500 в н. ештатной ситуации вполне адекватно. Более того, если возникнет KeyError, то это будет означать, что проблема не здесь, а где-то ещё, и замалчивать её неправильно. DoesNotExists наоборот надо ловить, потому как оно отражает штатную ситуацию — устаревшую ссылку
0
500-ка это внутренняя ошибка сервера. Ключевое слово — внутренняя. То есть если БД упала, например, или место на диске закончилось. Как-то нехорошо, когда внутренняя ошибка провоцируется внешним воздействием.
0
Вопрос восприятия, у нас концепция такова, что 500я должна выдаваться если произошло что-то неожиданное, что не было предусмотрено. И одновременно уходит письмо разработчикам. Такой подход позволяет быстро находить и чинить многие баги.
0
В этом случае любой кшольник-кулхацкер, запустивший сканер поиска ошибок, просто засыпет спамом :-) А если отчёты будут отправляться синхронно, ещё и отказ в обслуживании вызовет
0
Когда запустит тогда и будем смотреть, и адекватно отвечать. Решать проблему до её возникновения в корне неверно. А если просто ловить все такие ошибки, то это может привести к замалчиванию неправильного поведения, битых ссылок и т.п.
Опыт показывает, что при замалчивании ошибок искать такие проколы по жалобам пользователей довольно сложно и небыстро.
Опыт показывает, что при замалчивании ошибок искать такие проколы по жалобам пользователей довольно сложно и небыстро.
+1
Бывало такое, что просыпаешься, а на почте 1500 писем с одной и той же ошибкой. Ну и что? Ошибка быстро исправлена, вреда эти 1500 писем не принесли (Gmail и миллион бы пережил).
А если замалчивать ошибку, то они и дальше бы оставались на сайте. В конце концов что важней — работающий продукт или чистота инбокса?
А если замалчивать ошибку, то они и дальше бы оставались на сайте. В конце концов что важней — работающий продукт или чистота инбокса?
+2
Уверен, что у большинства есть своя bulletproof-библиотека с полезными функциями. Но досадно, что народ с завидным упорством плодит всё новые и новые пакеты: django-annoying, django-extensions, handy. А ведь функциональность зачастую перекрывается. Тот же
И вместе с тем, очень многие из этих библиотек словно из прошлого века. В смысле, заточены под старые версии Джанги.
За упрощение жизни: многие в повседневной жизни используют CBV. Для них катастрофически не хватает микшинов с функциональностью, аналогичной декораторам. Или абстрактных моделей, в которых уже добавлены какие-то полезные колонки, которые приходится каждый раз добавлять руками (типа
render_to
или json_response
не реализовывал только ленивый.И вместе с тем, очень многие из этих библиотек словно из прошлого века. В смысле, заточены под старые версии Джанги.
За упрощение жизни: многие в повседневной жизни используют CBV. Для них катастрофически не хватает микшинов с функциональностью, аналогичной декораторам. Или абстрактных моделей, в которых уже добавлены какие-то полезные колонки, которые приходится каждый раз добавлять руками (типа
date_created
). 0
> Для них катастрофически не хватает микшинов с функциональностью, аналогичной декораторам.
Эти иногда пользую github.com/brack3t/django-braces
Эти иногда пользую github.com/brack3t/django-braces
0
Спасибо. Но даже если и использовать, всё равно как-то грустно, что придётся подключать django-braces для микшинов, django-annoying для
Вот бы один метапакет, в котором это всё в одном месте было… Не совсем джанго-вэй, конечно, но его можно разбить на аппы и подключать только нужное:
Вроде и красиво, и зависимостей не плодит.
get_object_or_None
и django-extensions для чего-нибудь ещё.Вот бы один метапакет, в котором это всё в одном месте было… Не совсем джанго-вэй, конечно, но его можно разбить на аппы и подключать только нужное:
INSTALLED_APPS = (
'metapacket.views',
'metapacket.shortcuts',
'metapacket.decorators',
)
Вроде и красиво, и зависимостей не плодит.
0
Некрасиво, что декоратором render_to нельзя воспользоваться, не поставив пустые скобки. Посмотрите на login_required, например.
0
Декоратором
Начиная с 1.3 есть
render_to
вообще пользоваться моветон, на мой взгляд. Ладно бы жили в каменные времена версии 1.2, когда это было вынужденной мерой: тогда шорткаты были длиннее собственно функций, на которые ссылались.Начиная с 1.3 есть
django.shortcuts.render
. А в 1.2, кстати, можно было импортировать direct_to_template as render
. Получалось вполне себе универсально. 0
Декоратор render_to принимает аргументы, поэтому нужны скобки.
0
login_required тоже. И хотя «Explicit is better than implicit», есть ещё и «Beautiful is better than ugly» (The Zen of Python). Кроме того мы находимся в контексте джанги, поэтому стоит соблюдать единообразие. И третий аргумент — такое поведение реализуется довольно просто: django/contrib/auth/decorators.py. Поэтому мне кажется, что такой подход будет удачнее.
+1
Декораторы render_to и json_response есть в django-annoying. Полезная библиотека. Но насчет render_to — это уже действительно устарело. Сейчас можно написать просто:
По мне это как то более… не знаю как сказать. Нагляднее что ли.
return render(request, 'template/template.html', {'a':2,' b':3})
По мне это как то более… не знаю как сказать. Нагляднее что ли.
+6
И если у тебя несколько выходов из вьюхи, то придётся имя шаблона повторять, либо вынести в переменную. Так что всё спорно.
Это просто другой способ смотреть на вещи — отдельно логика, отдельно рендеринг. Кроме того,
Это просто другой способ смотреть на вещи — отдельно логика, отдельно рендеринг. Кроме того,
@render_to()
предлагает более высокий уровень факторизации, например похожие страницы для зарегистрированных и для анонимов могут использовать общую логику:def _edit(request):
# логика редактирования какой-нибудь штуки
# будет использоваться повторно
# создаём вьюхи из логики и других аспектов
my_edit = login_required(render_to('my/edit.html')(_edit))
edit = render_to()(_edit)
0
Если у вьюхи несколько выходов, то почти наверняка лучше использовать CBV: отлаживать и писать тесты намного проще.
0
Если несколько выходов на один и тот же шаблон, значит у вас формируется несколько различных вариантов параметров контекста. Логично значит внутри условий добавлять в контекст параметры, а потом в конце функции отрендерить данный контекст при помощи шаблона.
Если же у вас посередине функции в рендомных местах стоят return-ы, то эта функция по определению нуждается в рефакторинге.
Если же у вас посередине функции в рендомных местах стоят return-ы, то эта функция по определению нуждается в рефакторинге.
+3
Ну структурном программировании можно долго спорить, я не считаю его такой уж безусловно правильной идеей. По мне, код должен отражать, то как удобно думать о решении, и если удобней думать «если так, то сразу выкидываем, если сяк, то выводим сообщение, а иначе — обычная обработка», то и код должен выглядеть именно так.
Каждый раз когда мы не выходим из функции сразу, мы вынуждены вводить новый элемент состояния (переменную/флажок), который занимает внимание, читающего такой код, программиста, а это весьма ограниченный ресурс.
Каждый раз когда мы не выходим из функции сразу, мы вынуждены вводить новый элемент состояния (переменную/флажок), который занимает внимание, читающего такой код, программиста, а это весьма ограниченный ресурс.
0
Хотя шорткат
render()
, конечно, уменьшает надобность в @render_to()
. 0
… и ни одного теста?)
+1
Буду занудствовать.
1. Вот такое:
при всем удобстве, в корне неправильно. Декораторам, меняющим синтаксис вызываемых функций не место в этом мире. Почему — рассказывать долго и холиварно.
2. last_modified — а если в вьюха уже установила Last-Modified?
3. class StripWhitespace(object):
компиляцию регеспов вынести в модуль.
4. render_to_email; if settings.DEBUG:
Зачем? есть же console.EmailBackend
В общем, еще пилить и пилить :)
Ну а в целом — кнопка watch уже нажата, удачного развития!
1. Вот такое:
<hh user=render_to>()
def foo(request):
return {
}
при всем удобстве, в корне неправильно. Декораторам, меняющим синтаксис вызываемых функций не место в этом мире. Почему — рассказывать долго и холиварно.
2. last_modified — а если в вьюха уже установила Last-Modified?
3. class StripWhitespace(object):
компиляцию регеспов вынести в модуль.
4. render_to_email; if settings.DEBUG:
Зачем? есть же console.EmailBackend
В общем, еще пилить и пилить :)
Ну а в целом — кнопка watch уже нажата, удачного развития!
+4
1. Один из вариантов декораторов — это композиция, и естественно они будут менять семантику декорируемой функции.
2. Такой проблемы не возникало, а следовательно и решать её преждевременно.
4. console.EmailBackend выводит на консоль уже кодированное письмо, т.е. русский текст не прочитаешь. Решение конечно ad-hoc, правильнее было бы свой EmailBackend написать.
foo
здесь уже не вьюха, а только её часть и если думать о ней так, то вполне логично, что и выглядит она по другому.2. Такой проблемы не возникало, а следовательно и решать её преждевременно.
4. console.EmailBackend выводит на консоль уже кодированное письмо, т.е. русский текст не прочитаешь. Решение конечно ad-hoc, правильнее было бы свой EmailBackend написать.
-2
В целом спасибо за конструктив )
0
Честно говоря, я против того, чтобы декоратор менял тип и логику выходных данных функций. Декоратор — как приправа, должен делать функцию «вкуснее», однако в его отсутствии блюдо все равно должно быть съедомным.
Например,
легко может быть заменено на:
При этом сохранив оригинальный дух и стиль кодирования Django (View возвращает объект Response) и снизив порог вхождения для новичков.
Например,
ajax
def enable_post(request):
...
raise ajax.error('permission_denied')
легко может быть заменено на:
def enable_post(request):
...
return ErrorAjaxResponse('permission_denied')
При этом сохранив оригинальный дух и стиль кодирования Django (View возвращает объект Response) и снизив порог вхождения для новичков.
+1
Никто не запрещает, но мне удобно думать, что у меня отдельно есть обработчик бизнес логики, а отдельно другие аспекты — контроль доступа, обработка ошибок и представление. То, что я могу их отделить — однозначно хорошо, как это делать в виде утилит и шорткатов, которые вызываются по мере надобности, в виде композиции функций с использованием синтаксиса декораторов или с помощью наследования классов дело вкуса.
P.S. Можно использовать
P.S. Можно использовать
<source lang="python">...</source>
для подстветки кода и @
для создания собак. 0
Разделение логики и представления это хорошо. Тут все верно. Но причем тут декораторы?
Т.е. когда у Вас есть здание и вы его декорируете — это значит что вы делаете красивым готовое решение. Вы же не поручаете декоративным гипсовым колоннам поддерживать потолок. Без декора здание будет некрасивым — однако оно будет, и оно будет работать.
А для разделения логики и представления есть модули, инкапсуляция, наследование, функциональные паттерны и другие вещи. Да и return SomeCostomResponse() даже короче в написании чем raise SomeCustomError в функции с дополнительной оберткой.
Декор — (от лат. decorare — украшать) — дополнительные элементы в живописных композиционных сюжетах.
Т.е. когда у Вас есть здание и вы его декорируете — это значит что вы делаете красивым готовое решение. Вы же не поручаете декоративным гипсовым колоннам поддерживать потолок. Без декора здание будет некрасивым — однако оно будет, и оно будет работать.
А для разделения логики и представления есть модули, инкапсуляция, наследование, функциональные паттерны и другие вещи. Да и return SomeCostomResponse() даже короче в написании чем raise SomeCustomError в функции с дополнительной оберткой.
+1
Кстати для шаблонов есть вполне красивое решение от самой джанги:
Оно очевидно, документировано и через наследование позволяет делать еще более крутые вещи.
class MyCustomView(TemplateView):
template_name = 'my_custom_template.html'
def get_context_data(self, **kwargs):
return {
'bar': Bar.objects.all()
}
Оно очевидно, документировано и через наследование позволяет делать еще более крутые вещи.
0
Ну может декораторы и не совсем правильное название, но они делают дело, да и не я их называл. Так что аргумент не принимается.
Что же качается return и raise, то где вы увидели SomeCustomError()? А использование исключений позволяет выносить отдельные вещи в подфункции, декораторы и возвращать {«success»: true} просто по успешному завершению функции. В остальном же дело вкуса и спорить об этом глупо.
Что же качается return и raise, то где вы увидели SomeCustomError()? А использование исключений позволяет выносить отдельные вещи в подфункции, декораторы и возвращать {«success»: true} просто по успешному завершению функции. В остальном же дело вкуса и спорить об этом глупо.
0
Зачем все это в одном пакете? Почему не в нескольких? Вообще же никакой связности.
+1
Связность есть — мелкие нужные штуки, слабая, конечно, но поддерживать кучу пакетов, а соответственно привносить кучу сущностей — тоже сомнительное решение.
0
Хм, а в чем именно сомнительность? Всегда был уверен, что куча маленьких узкоспециализированных аппов лучше одного монструозного.
Еще, по поводу StripWhitespace middleware. Чем {% spaceless %} не угодил?
Еще, по поводу StripWhitespace middleware. Чем {% spaceless %} не угодил?
0
Он решает несколько другую задачу, да и засорять свои шаблоны не хочется. Использование middleware чище.
0
Этот тег отлично наследуется, так что достаточно одного раза в базовом шаблоне. Но даже если вы уверены, что middleware чище, почему бы не использовать
django.utils.html.strip_spaces_between_tags
, зачем писать эту логику самостоятельно? 0
> DAYS = zip(range(7), 'Sun Mon Tue Wed Thu Fri Sat'.split())
можно заменить на
DAYS = tuple(enumerate('Sun Mon Tue Wed Thu Fri Sat'.split()))
можно заменить на
DAYS = tuple(enumerate('Sun Mon Tue Wed Thu Fri Sat'.split()))
0
Sign up to leave a comment.
Упрощая жизнь c Django