хороший пример, кстати. шаблонизатор предназначен для рендера html, в первую очередь. поэтому автоэкранирование (поддержка рендера валидного html) тут очень даже уместно.
а view-функции из другой области. они предназначены для обработки http запросов. поэтому было бы просто замечательно, если бы django предоставляла аналогичные средства, так же упрощающие поддержку семантики этого протокола (в понимании rfc2616)…
в реальности все совершенно иначе. view-фукнция является точкой входа для обработки любого запроса к данному URI. и вся мудреная логика формирования ответа целиком лежит на совести пользовательского кода (в том числе соответствие ответа типу сообщения GET, POST, PUT, ..). заморчки с диспетчеризацией данных для формы, по типу запроса, это прямое следствие джанговской архитектуры. вот решение этой задачи (на что сейчас все прикладники кладут, по понятным причинам) было бы приятно видеть на уровне фреймворка. сравните:
впрочем, не так давно, появилась определенная надежда на class-based views, ожидаемые в следующем релизе. они могли бы предоставлять нужный функционал по умолчанию… (правда это нехилый такой лисапед — классная реализация уже давно есть в django-piston).
а csrf это вообще фича уровня протокола приложения. в contrib ей самое место. :)
в принципе, я понял Вашу точку зрения, но принять не могу. :)
какие именно проблемы? я пока вижу только одну проблему — в пресловутом сниппете нужно учитывать массу плохо контролируемых нюансов внешней среды (csrf, содержание html-формы, ajax, возможности http-клиента). а это чревато появлением ошибок на этапе развития проекта (отключив csrf вы рискуете уронить бизнес-логику).
учите писать правильно, а не экономить строчки кода. даже если «все под контролем». :)
csrf же это не «наука», а инженерное решение, которое имеет вполне конкретную область применимости: работает только для html-форм, требует поддержку кук от браузера. (кстати, именно из-за привязанности к кукам, csrf не обеспечивает защиту на под-доменах). полезная штука, в своей нише, и не нужная во всех остальных случаях. не понимаю, ради чего его вытащили из contrib в core и переворотили четверть джанги. )
«общий случай», где используются Forms (кстати, намеренно абстрагированные от request) — гораздо шире. forms часто используются для обработки данных, полученных через ajax — здесь csrf бесполезен, в принципе (кстати, и не обрабатывается django); с помощью forms удобно делать валидацию при создании api сайта. здесь csrf так же не нужен…
Я согласен с Иваном, в том плане, что @render_to скорее вреден, чем полезен. Хотя в django и есть аналогичная безделушка, в api шаблонизатора simple_tag
Но в общем случае, декораторы часто используются в качестве адаптеров, поэтому отличие сигнатуры декорируемой функции это не аргумент. :)
Если после этого сразу непонятно, как работает код ContactForm(request.POST or None), то разберитесь в качестве упражнения, расписывать не буду. Это простая и полезная идиома.
я с вами согласен в том плане, что описание контроллеров для форм, своей однотипностью и многословностью вызывает уныние. но делать так, как вы предлагаете, тоже нельзя. :)
ваш же код это грязный хак, а не «полезная идеома», т.к. в корне меняет семантику проверки. проверяя request.POST, вы делаете допущение, что при POST запросе (request.method == 'POST'), тело HTTP сообщения (request.POST) не может быть пустым. это так:
допустим, форма предлагает выбрать один из вариантов контактов (список полей type=«radio»). если не выбрать ни одного и сделать POST, то тело POST запроса будет пустым и после перезагрузки страницы посетитель увидит снова оригинальную форму, вместо формы с сообщением об ошибке.
т.е. для какой-то конкретной формы, при данных условиях это может работать. но в общем случае — нет. вот поэтому
В документации и обучающих примерах по django обычно пишут вьюхи вот так
Главная — ГЛАВА 19. ОТПУСКА — Статья 125. ТК РФ. Разделение ежегодного оплачиваемого отпуска на части. Отзыв из отпуска
Статья 125. ТК РФ. Разделение ежегодного оплачиваемого отпуска на части. Отзыв из отпуска
По соглашению между работником и работодателем ежегодный оплачиваемый отпуск может быть разделен на части. При этом хотя бы одна из частей этого отпуска должна быть не менее 14 календарных дней. ...
ни чем — это элемент автоматизации. :) при выходе из режима вставки (insert mode) плагин автоматически дергает за системный переключатель и переключает раскладку на английскую. при входе — восстанавливает в прежнее состояние.
А чем лучше? Мы не будем говорить про вычисления на калькуляторе, где «программа» живет лишь до получения первого результата. Давайте рассмотрим более привычную для разработчиков ситуацию ситуацию, когда программа должна использоваться и поддерживаться в течении продолжительного времени. Как это часто бывает, проходит полгода, и цены на яблоки вырастают на на 1 рубль. Этот факт нужно отразить в чудо-программе. Разумеется, предыдущего гения-программиста уже месяц, как схантил йандекс, и задачу предстоит решать другому. Что он видит? Он видит в коде две волшебные константы: что из них цена, которую нужно менять «1» или «3»? В исходнике нет ответа, поэтому он идет выяснять состояние прайса на яблоки в предыдущем периоде, проклиная всех долбаных гениев, решивших (уж не знаю чем вам этот код приглянулся) — допустим, сэкономить 10 секунд на написание 2 строчек проясняющего суть текста. :)
мне показалось, что упоминание Оккама/П.Д.О. было бы уместнее в предыдущей статье — про модульность. здесь же он ясности не добавил). в программировании нередко приходится добавлять обозначения для того, чтобы повысить ясность. сравните:
Исключения должны проектироваться не от кода, а от ситуаций,
которые вы хотите по-особенному обработать.
Исключения являются частью внешнего интерфейса. Т.е. это то, с чем будет
взаимодействовать _клиенсткий_ код (чужой — а не ваш). Вы не можете заранее предугадать, какие ситуации клиентский код «захочет»
обрабатывать «по-особенному». Соответственно — проектировать исключения исходя
из какой-то особенной обработки нет ни какого резона. Вы можете лишь обозначать
исключительные ситуации в той мере, в которой сочтете нужным
это требуется для обеспечения полноты модели предметной области.
из-за ошибки, эта версия не сохраняет изменения. правится в файле firefile@strebitzer.at/content/firefile.js, в строчке 718. - if(qpos !== false) { + if(qpos !== -1) {
2 пирата -> Главарь оставляет себе всё.
3 пирата -> 99, 0, 1 монет пиратам по старшинству. последний пират доволен, ведь иначе, если убрать главаря, то второй заберёт себе все
Когда 2 пирата все очевидно.
В случае с 3 пиратами решение слишком парадоксально. Мне кажется, что тут ошибка в рассуждении.
Задача пирата состоит не только в том, чтобы получить золото — он ещё должен остаться в живых. Поэтому, модель решения нужно строить не на бинарном отношении «получит/не получит», а на высказывании: «если останется жив, то получит». Здесь все интереснее.
От ответа другого пирата зависит не только дележ золота, но и жизнь главаря. Если главарь ценит свою жизнь дороже 100 монет, то другой пират, за свою лояльность, получает не 1 жалкую монету, а все 100 (в противном случае главаря уберут). Кто этот «другой» уже не важно (в реальной жизни задействуется принцип субординации).
Поэтому ситуации с тремя пиратами решение будет таким: главарь получает жизнь, всё золото получает следующий по старшинству, а последний пират остаётся ни с чем. :)
Следовательно, доказательство на случаи 4 и 5 пиратов тоже не верно.
задумывался об этом, читая rfc. но пришел к выводу, что фактически это бесполезная хрень. все клиенты понимают 302 и автоматически редиректят, поэтому инсинуации в rfc про 303 ни кого не волнуют. :)
«проблему» стоило бы порешать лишь в одном случае — если бы браузеры действительно запрашивали потдветждение юзера при 302 редиректе. но этого нет и никогда не будет, потому, что так устроен современный интернет. :)
в последнее время, многие производители ноубков размещают свето-индикаторы (caps-lock, num-lock и т.п.) в том месте, где в процессе печати на клавиатуре они закрыты запястьем руки. имхо, дурацкое дизайнерское решение. :(
Префикс WWW придумали не столько для указания типа сервиса, столько по соображениям безопасности.
Куки, установленные для домена site.ru, будут видны и на всех под-доменах *.site.ru.
Куки, установленные для домена www.site.ru, будут видны только на этом сайте, т.к. *.www.site.ru не бывает. :)
Поэтому, если не нужно, чтобы сайты на под-доменах были связаны с сайтом на основном домене, то ему присваивается всем известный префикс www.
Вы можете сложить 0.5 и 0.5, получив 1, но из двух огрызков вы не получите целого яблока. Объекты из ООП имеют примерно такое же отношение к объектам реального мира, как натуральные числа к огрызкам от яблок — и то и другое это абстракции. Развитие «объектного мышления» это развитие абстрактного мышления, с использованием концепций ООП.
Одна из них — интерфейс — абстракция поведения (взаимодействия сущности в внешним миром). На диаграммах используется наследование классов там, где нужно было использовать реализацию интерфейсов. В самом деле, описав интересующее поведение «продавца» и «игрока» интерфейсами, можно было бы абстрагироваться от конкретной сущности «человек», и в последствии, без проблем, перенести это поведение на автоматы-обменники. Мне кажется, эта ошибка, стала следствием того, что автор слишком много уделяет внимания объектам реального мира. :)
«Прошла конференция, посвященная ООП. Одни докладчики говорили про моделирование объектов реального мира и их иерархий. Другие — по делу…» =)
Объясните, почему продавец жетонов — которые на диаграмме суть деньги — до сих пор на свободе, ведь он, осуществляя обмен, и не являясь представителем кредитной организации, злостно нарушает закон «О валютном регулировании и валютном контроле»? Как продавцу жетонов самому поиграть на игровом автомате? Как разместить на диаграмме класс для механического продавца — автомат-обменник, меняющий купюры на жетоны, — так чтобы при этом он не оказался киборгом (наследником человека)?
хороший пример, кстати. шаблонизатор предназначен для рендера html, в первую очередь. поэтому автоэкранирование (поддержка рендера валидного html) тут очень даже уместно.
а view-функции из другой области. они предназначены для обработки http запросов. поэтому было бы просто замечательно, если бы django предоставляла аналогичные средства, так же упрощающие поддержку семантики этого протокола (в понимании rfc2616)…
в реальности все совершенно иначе. view-фукнция является точкой входа для обработки любого запроса к данному URI. и вся мудреная логика формирования ответа целиком лежит на совести пользовательского кода (в том числе соответствие ответа типу сообщения GET, POST, PUT, ..). заморчки с диспетчеризацией данных для формы, по типу запроса, это прямое следствие джанговской архитектуры. вот решение этой задачи (на что сейчас все прикладники кладут, по понятным причинам) было бы приятно видеть на уровне фреймворка. сравните:
# первая попавшаяся под руку хрень -)
$ curl -svX PUT msdn.microsoft.com/ru-ru/default.aspx > /dev/null
(HTTP/1.1 411 Length Required)
# django
$ curl -svX PUT docs.djangoproject.com/en/1.2/ > /dev/null
(HTTP/1.0 200 OK)
впрочем, не так давно, появилась определенная надежда на class-based views, ожидаемые в следующем релизе. они могли бы предоставлять нужный функционал по умолчанию… (правда это нехилый такой лисапед — классная реализация уже давно есть в django-piston).
а csrf это вообще фича уровня протокола приложения. в contrib ей самое место. :)
в принципе, я понял Вашу точку зрения, но принять не могу. :)
учите писать правильно, а не экономить строчки кода. даже если «все под контролем». :)
csrf же это не «наука», а инженерное решение, которое имеет вполне конкретную область применимости: работает только для html-форм, требует поддержку кук от браузера. (кстати, именно из-за привязанности к кукам, csrf не обеспечивает защиту на под-доменах). полезная штука, в своей нише, и не нужная во всех остальных случаях. не понимаю, ради чего его вытащили из contrib в core и переворотили четверть джанги. )
«общий случай», где используются Forms (кстати, намеренно абстрагированные от request) — гораздо шире. forms часто используются для обработки данных, полученных через ajax — здесь csrf бесполезен, в принципе (кстати, и не обрабатывается django); с помощью forms удобно делать валидацию при создании api сайта. здесь csrf так же не нужен…
Но в общем случае, декораторы часто используются в качестве адаптеров, поэтому отличие сигнатуры декорируемой функции это не аргумент. :)
я с вами согласен в том плане, что описание контроллеров для форм, своей однотипностью и многословностью вызывает уныние. но делать так, как вы предлагаете, тоже нельзя. :)
если контоллерная логика такая же простая как в примере — используйте create-update-delete-generic-views — будет еще короче. :)
ваш же код это грязный хак, а не «полезная идеома», т.к. в корне меняет семантику проверки. проверяя request.POST, вы делаете допущение, что при POST запросе (request.method == 'POST'), тело HTTP сообщения (request.POST) не может быть пустым. это так:
допустим, форма предлагает выбрать один из вариантов контактов (список полей type=«radio»). если не выбрать ни одного и сделать POST, то тело POST запроса будет пустым и после перезагрузки страницы посетитель увидит снова оригинальную форму, вместо формы с сообщением об ошибке.
т.е. для какой-то конкретной формы, при данных условиях это может работать. но в общем случае — нет. вот поэтому
print 1 * 3и
price_of_apples = 1
number_of_apples = 3
print price_of_apples * number_of_apples
первый пример несомненно короче. но где больше ясность?
Кроме того:
wiki: Принцип достаточного основания) иными словами, бритва Оккама не нужна))
Исключения являются частью внешнего интерфейса. Т.е. это то, с чем будет
взаимодействовать _клиенсткий_ код (чужой — а не ваш). Вы не можете заранее предугадать, какие ситуации клиентский код «захочет»
обрабатывать «по-особенному». Соответственно — проектировать исключения исходя
из какой-то особенной обработки нет ни какого резона. Вы можете лишь обозначать
исключительные ситуации в той мере, в которой
сочтете нужнымэто требуется для обеспечения полноты модели предметной области.
git config --global alias.oops \ '!am() { curl -s http://whatthecommit.com/ | grep '"'<p>'"' | cut -c4-; }; git commit -em "# $(am)" "$@"'использование:
firefile@strebitzer.at/content/firefile.js, в строчке 718.- if(qpos !== false) {+ if(qpos !== -1) {Когда 2 пирата все очевидно.
В случае с 3 пиратами решение слишком парадоксально. Мне кажется, что тут ошибка в рассуждении.
Задача пирата состоит не только в том, чтобы получить золото — он ещё должен остаться в живых. Поэтому, модель решения нужно строить не на бинарном отношении «получит/не получит», а на высказывании: «если останется жив, то получит». Здесь все интереснее.
От ответа другого пирата зависит не только дележ золота, но и жизнь главаря. Если главарь ценит свою жизнь дороже 100 монет, то другой пират, за свою лояльность, получает не 1 жалкую монету, а все 100 (в противном случае главаря уберут). Кто этот «другой» уже не важно (в реальной жизни задействуется принцип субординации).
Поэтому ситуации с тремя пиратами решение будет таким: главарь получает жизнь, всё золото получает следующий по старшинству, а последний пират остаётся ни с чем. :)
Следовательно, доказательство на случаи 4 и 5 пиратов тоже не верно.
«проблему» стоило бы порешать лишь в одном случае — если бы браузеры действительно запрашивали потдветждение юзера при 302 редиректе. но этого нет и никогда не будет, потому, что так устроен современный интернет. :)
Куки, установленные для домена site.ru, будут видны и на всех под-доменах *.site.ru.
Куки, установленные для домена www.site.ru, будут видны только на этом сайте, т.к. *.www.site.ru не бывает. :)
Поэтому, если не нужно, чтобы сайты на под-доменах были связаны с сайтом на основном домене, то ему присваивается всем известный префикс www.
Одна из них — интерфейс — абстракция поведения (взаимодействия сущности в внешним миром). На диаграммах используется наследование классов там, где нужно было использовать реализацию интерфейсов. В самом деле, описав интересующее поведение «продавца» и «игрока» интерфейсами, можно было бы абстрагироваться от конкретной сущности «человек», и в последствии, без проблем, перенести это поведение на автоматы-обменники. Мне кажется, эта ошибка, стала следствием того, что автор слишком много уделяет внимания объектам реального мира. :)
Объясните, почему продавец жетонов — которые на диаграмме суть деньги — до сих пор на свободе, ведь он, осуществляя обмен, и не являясь представителем кредитной организации, злостно нарушает закон «О валютном регулировании и валютном контроле»? Как продавцу жетонов самому поиграть на игровом автомате? Как разместить на диаграмме класс для механического продавца — автомат-обменник, меняющий купюры на жетоны, — так чтобы при этом он не оказался киборгом (наследником человека)?