Церемонию «Оскар-2021» отложили на два месяца из-за коронавируса
Автор фото, Reuters
Церемония вручения «Оскаров», которая должна была пройти 28 февраля следующего года, перенесена на 25 апреля.
Пока не понятно, пройдёт ли церемония как обычно, или организаторы придумают онлайн-вариант «Оскаров».
Также продлевается срок подачи заявок на участие в программе премии.
Возможность претендовать на «Оскар» получили фильмы, выходящие в прокат с 1 января 2020 года по 28 февраля 2021 года.
Вручение Оскаров в истории премии откладывалось трижды. В 1938 году церемонию перенесли из-за наводнения в Лос-Анджелесе, в 1968-м — из-за убийства Мартина Лютера Кинга, а в 1981-м — после покушения на жизнь президента Рональда Рейгана.
«Уже больше века кино играет важную роль в нашей жизни — оно вдохновляет, развлекает и утешает нас в самые тёмные времена», — говорится в заявлении президента Американской киноакадемии Дэвида Рубина.
Продлевая срок подачи заявок и перенося церемонию, академия надеется дать кинопроизводителям время, чтобы закончить производство фильмов, приостановленных из-за пандемии, добавил Рубин.
«Предстоящая церемония и открытие нашего нового музея будет историческим моментом: любителей фильмов во всём мире объединит кино», — заявил глава академии.
Список претендентов на кинопремию будет опубликован 15 марта следующего года.
Другие правила
В соответствии с новыми правилами киноакадемии, на Оскар могут претендовать фильмы, снятые для стриминговых платформ, таких как Netflix.
Таким образом, от классических правил, которые гласят, что номинируемый фильм должен демонстрироваться в кинотеатрах Лос-Анджелеса по меньшей мере неделю, отступили. Кинотеатры в Лос-Анджелесе закрыты, как и в большинстве стран мира.
В связи с пандемией производство многих фильмов было приостановлено, премьеры отложены или вовсе отменены. Некоторые фильмы миновали этап проката в кинотеатровах и вышли сразу в онлайне или на цифровых носителях.
На прошлой неделе киноакадемия вновь заявила, что будет стараться сделать список номинантов более представительным — «Оскар» давно критикуют за то, что на премии представлено мало работ режисеров-женщин и представителей этнических меньшинств.
«Оскар» — не единственное крупное мероприятие, которого коснулась пандемия. Вручение престижной театральной премии «Тони», которое должно было состояться в июне, перенесено на неопределённый срок. Также из-за пандемии перенесли олимпийские игры в Токио и «Евровидение».
«Джанго освобожденный» Квентина Тарантино: Да будь я хоть негром!
Но если для нашего зрителя предыдущим абзацем вся глубина фильма почти полностью исчерпывается, это не значит, что в «Джанго» совсем нет провокации и фиги в кармане. Тарантино, конечно, не мог не заложить в своей картине несколько взрывных механизмов, на которых подорвались все, на кого они были рассчитаны.
Поскольку история, которую он рассказывает – про негра, который сбросил оковы, вооружился и убил всех белых парней, постольку самым ожидаемым образом на «Джанго» ополчились многочисленные американские правые, которые увидели в этом сюжете расизм наоборот. А поскольку в фильме слово «нигер», которое по-прежнему считается сильным ругательством в английском языке, звучит чуть ли не через слово, часть афроамерканцев также высказалась против «Джанго». Замечательный режиссер Спайк Ли и вовсе призвал бойкотировать фильм не глядя, обвинив Тарантино в том, что сама идея снимать вестерн на тему рабства кажется ему оскорбительной.
На самом деле, все нападки на «Джанго» звучат неубедительно: фильмы про темнокожих ковбоев были задолго до Тарантино. Самый известный из них, Boss Nigger Джека Арнольда, режиссер, без сомнения, знает чуть ли не наизусть. Его «Джанго освобожденный», даже название которого – отсылка к культовой серии спагетти-вестернов, как и все прочие фильмы Тарантино – это талантливо составленный калейдоскоп цитат, в котором почти нет ничего, выходящего за рамки кинематографической традиции.
Киногид: ведьмы, монстры и Тарантино >>
В случае с «Джанго» ко всему этому добавился разве что непривычный для самого Тарантино сентиментальный голливудский тон. Но сам режиссер и его команда в ответ на критику лукаво отвечают: а что, по-вашему, рабства не было? Или слово «нигер» накануне гражданской войны не употреблялось именно таким образом?
Посмотрите характерную сценку: темнокожий актер Сэмюэл Л. Джексон провоцирует своего белого интервьюера сказать страшное слово на «н», а тот не смеет. Это вопиющее торжество политкорректности, над которым, как видно в ролике, открыто хохочет Джексон, и которому режиссер Тарантино не первый год успешно дает щелчка.
Ведь все до единого его фильмы – про то, как быть классным, даже когда ты «плохой парень». В мире Тарантино поведение этого ухоженного репортера, который начинает метаться, когда его вынуждают сделать что-то не по правилам – самое жалкое, что только можно придумать. Поэтому и отговорки про то, что он снимает так, как было на самом деле, придуманы для таких вот слабосильных метросексуалов.
Bounty Hunter / Компьютерные и мобильные игры / iXBT Live
В далекой-далекой галактике, есть много историй. О добре и зле. О предательстве и чести. О войне за правое дело. Их не перечислить и не рассказать. Но есть одна, — забытая и необычная. Изменившая ход истории в самой Далекой-далекой галактики. Это история о Джанго Фетте. Лучшем охотнике за головами.
Перед выходом второго эпизода киносаги «Звездные Войны», компания LucasArts Entertainment выпустила историю приквел. Она расскажет, откуда появилась планета Камино, познакомила нас с наемницей Зам Уэселл, рассказала, откуда взялся корабль «РАБ I» и поведала, как Джабба Хатт достиг таких высот. Небольшая игра, с простым линейным сюжетом, и огромной историей, проливающей свет на происходящее во вселенной Звездных войн.
Повествование за наемника начинается с простого задания — выследить преступника-муттани Мико Гинти. Пройти обучение. Научится пользоваться джетпаком. Использовать разное оружие для разных ситуаций. Находить секреты. Опознавать и ловить «заказы». Для игры 2002 года — это был прорыв, как с визуальной точки зрения, так и с наполнения мира.
После окончания первой миссии, Джанго Фетт возвращается к своему нанимателю. И получает самое важное задание в своей жизни— выследить и уничтожить джедайку Комари Восу (бывшую ученицу графа Дуку), создавшую культ «Бандо Гора». Задание идет лично от Дарта Сидиуса, будущего императора Галактики. Наградой за выполнение станет огромная сумма денег и возможность стать донором в проекте клонирования. Помимо Джанго Фетта на это дело нанимается множество других наемников со всей галактики. Главным из которых становиться Монтросс — мандалорский охотник за головами. На протяжении всей игры, он будет одним из боссов уровней и попьет немало вашей крови.
Отменная экшен-адвечура понравится не только поклонникам Джорджа Лукаса, но и обычным игрокам. Аутентичный антураж, подходящая музыка, узнаваемые персонажи. История подается отличными видеовставками и огромнейшим числом секретов и бонусов разбросанных по уровню. На протяжении 18 миссий вы будете расследовать кто такая Комари Восу, искать улики о ее местоположении. Узнаете, чем «Бандо Гора» не угодила будущему Императору и почему он желает уничтожение данного культа.
Сейчас, во время показа сериала «Мандалорец» с мягким и изнеженным главным героем, брутальный Джанго Фетт выходит на новый уровень. Из грозного харизматичного мандалорца эпохи до Битвы при Явине, новая ипостасия этого народа выглядит размякшей и детской.
Разработка сайта на Djanglo с нуля
Если вы решили стать программистом, но ничего не понимаете в разработке, вам, кроме желания, нужно иметь хоть какое-то подспорье. Не помешает также определиться с тем, что конкретно вы собираетесь делать, ведь программирование – широкая область, в которой реализуется масса совершенно разных задач.
Две основные области разработки – фронтенд и бэкенд – требуют различного подхода, поскольку связаны с совершенно разной областью деятельности. Если первое отвечает за то, как сайт выглядит и взаимодействует с посетителем, то второе нужно для его бесперебойной работы и обработки данных.
Для фронтенд и бэкенд разработки используются разные языки, которые отличаются друг от друга не только сложностью, но и логикой.
Какой язык выбрать новичку?
Одним из самых простых языков программирования, существующих в мире, является Python (Питон). На нём можно писать сайты, делать игры, ботов, приложения и многое другое. Python использует различные фреймворки и библиотеки, которые упрощают разработку, так как последние уже включают готовые элементы, которые не нужно создавать заново, растрачивая время впустую – вместо этого можно просто добавлять их в свой код. Среди таких фреймворков особую популярность завоевал Django (Джанго), и новички, как правило, начинают именно с него.
Кстати говоря, на Джанго сделаны даже такие сайты, как Гугл, Ютуб, Инстаграм и Пинтерест. Так что хотя он и прост, он при этом и хорош – иначе бы такие гиганты не стали бы его использовать.
Разумеется, перед тем как приступить к изучению Django, следует выучить Питон, потому что без этого просто ничего не получится. Однако не нужно бояться: Python прост и понятен, его код можно читать без особой подготовки и писать не так уж и сложно.
Как выучить Джанго?
Любой язык или фреймворк требуют не только теории, но и практики. Изучайте документацию, читайте учебники, но не забывайте делать упражнения, без которых невозможно закрепление знаний. Учите код – и пишите код. Повторяйте всё по несколько раз и общайтесь с такими же энтузиастами, как и вы.
Выполняйте тестовые задания. Их можно найти, например, на фрилансе. Учитывая, что знаний у вас пока мало, не следует пытаться на этом заработать – вашей оплатой станет опыт, который нельзя поменять ни на какие деньги.
Запишитесь на специальные курсы. Как бы хорошо вам ни давалась теория и выполнение практических заданий, самостоятельное обучение вряд ли сравнится с курсами, на которых преподаватель курирует ваши успехи и поправляет в случае ошибки (которую в противном случае вы бы могли попросту недоглядеть).
На правах рекламы
Бессмертные строки
МХАТ им. М. Горького встречает День Победы спектаклем «Бессмертные строки», в котором прозвучат стихи поэтов, прошедших войну или оставшихся на ней навечно. Стихи о войне – это всегда от сердца, потому что память Великой отечественной – это генная память, и Победа над нацизмом – это победа на все времена. И никто так, как поэты, не может рассказать правду о войне и о Победе, стихи поэтов-фронтовиков – это сокровенный и пронзительный рассказ очевидцев, способных облечь в поэзию свой самый важный жизненный опыт. Разве кто-нибудь еще может уместить в две строки такую правду: «Кто говорит, что на войне не страшно, тот ничего не знает о войне» (Юлия Друнина), или « Дай-ка лучше согрею ладони я//Над дымящейся кровью твоей» (Ион Деген). Такие стихи слушать больно, но это светлая боль, это тот самый труд души, проделать который наш долг.
Спектакль «Бессмертные строки» — это подношение победителям от актеров, режиссеров, музыкантов и всего театра.
Конечно, поэзия о войне немыслима без поэмы Александра Твардовского «Василий Теркин» — эту поэму, напечатанную в годы войны в газетах «Красноармейская правда», «Правда», «Известия», «Знамя» — солдаты не рвали на самокрутки, они хранили эти главы у сердца рядом со стихотворением «Жди меня и я вернусь» Константина Симонова.
В постановке участвует ансамбль «Джанго» во главе с Алексеем Поддубным, известный по саундтрекам к фильмам «Бой с тенью», «Беглянки», сериалам «Солдаты», «Последняя репродукция», «Беглец». Каждая песня Джанго – это целая история. В живом исполнении прозвучат самые любимые народом военные песни.
Перед спектаклем вокруг театра и в фойе мы все вместе сможем пообщаться, послушать военный оркестр и войти в атмосферу настоящего всенародного торжества.
Мы ждем вас, дорогие зрители, чтобы вместе отметить День Победы.
Продолжительность: 1 часа 30 мин.
Премьера состоится 9 мая 2021 года
Настольные игры. Бэнг! Дуэль. Лицом к лицу.
Не так давно на Диком Западе единственным развлечением для лихих ребят были перестрелки, ограбления поездов, взрывы сейфов и, конечно же, дуэли. Поводом для выяснения отношений на кольтах мог стать совершенно безобидный поступок: удар бутылкой виски по голове или сломанный во время культурной беседы нос. Безусловно, были ещё салуны, в которых коротали время степенные погонщики быков, но… Ничто не заменит бодрящий запах порохового дыма и разливающийся по телу адреналин от пролетающих над головой пуль! Сегодня на Розовом диване – соседаубивательная настольная игра «Бэнг! Дуэль».
Так как оружие тех времён не отличалось особой меткостью, требовало времени на перезарядку и периодично давало осечки, то одиночные дуэли, порой, превращались в грандиозные перестрелки, поучаствовать в которых желали многие. Для внесения ясности в безумный хаос происходящего, с незапамятных времён принято разделять дуэлянтов на служителей закона и преступников. Хотя, грань между этими враждующими лагерями, порой, была столь условна, что отличить «хороших» от «плохих» можно было лишь по звезде шерифа…
Набор для организации дуэли поставляется в небольшой прямоугольной коробочке от издательства «Hobby Games». Если внимательно вглядеться в переполняющий коробку воздух прерий, то можно без труда разглядеть пули, свистящие над головами сомнительных личностей, лошадей, поднимающих пыль дорог, таверны, бочки, склады оружия и парящих в небе стервятников…
Название игры «Бэнг! Дуэль» даёт понять, что в перестрелке могут принять участие лишь двое – шериф и преступник. Тем не менее, в распоряжение соперников поступят отряды единомышленников, готовые изрешетить любого встречного при помощи града пуль.
Сторону шерифа примут двенадцать почтенных граждан города, каждый из которых обладает уникальным умением и имеет индивидуальный запас прочности. Но не рассчитывайте, что все они бросятся вам на подмогу – многие будут в отъезде, либо заняты важными государственными делами…
Аналогичное количество отчаянных головорезов с радостью сделают решето из служителей закона. Но собрать их всех в одну команду также будет практически невозможно – помешают салуны и плановые ограбления экспрессов.
«Бэнг! Дуэль» ставит жирную точку в споре: «Кого любят лихие леди?» Однозначно, они отдают предпочтение плохим парням – в банде вы увидите трёх красоток с пистолетами, а вот у шерифа всего лишь одна, но зато с внушительной винтовкой…
Как я упомянул ранее, отличить «хороших» от «плохих» можно по звезде шерифа (в левом верхнем углу), фону портрета и рубашке карты. Жизнь каждого персонажа измеряется в патронах (правый верхний угол), а свойство указано в нижнем текстовом блоке. Если вы являетесь поклонником серии «Бэнг!» то освоитесь с новым оформлением буквально за минуту…Принцип использования карт также остался практически без изменений, за исключением того, что перед вами теперь располагается два персонажа, один из которых является «активным», а второй – «прикрывающим».
Двусторонние памятки сориентируют искателей приключений и дадут ответ на все возможные вопросы. Кстати, соперники отныне играют индивидуальными колодами, но после их использования все карточки сброса составляют общую стопку и применяются обеими сторонами.
Кардинальное отличие дуэли от стандартного «Бэнга!» — отсутствие, самих карт «Бэнг!» в том виде, в котором все привыкли их «бахать». Звук выстрела заменило оружие, обведённое красной рамкой. Честно говоря, поначалу это вводит в замешательство – я дважды пересмотрел колоду в надежде отыскать знакомое слово, пока не «принял» новую форму его графического отображения. Мало того, многие залпы отныне сопровождаются дополнительными событиями, указанными на карте.Основные правила дуэли, которые вам необходимо запомнить: красные карточки наносят урон только активному персонажу противника; коричневые можно сыграть как на себя, так и на оппонента; синие применяются на вашего прикрывающего персонажа, либо на активного стрелка противника. Этих знаний вполне достаточно, чтобы вступить в бой…
Ваша лошадь на меня неуважительно смотрит!
Первым делом соберите команду: оппоненты перемешивают личные колоды персонажей и случайным образом призывают под ружьё четверых лихих парней. Остальные, увы, галопом мчатся в прерию по своим делам… Два случайных персонажа располагаются перед игроком (на карточки выложите жетоны пуль, символизирующие уровень жизни). Пометьте одного из стрелков жетоном активного персонажа. Оставшаяся пара прячется за салуном и становится резервом, готовым заменить выбывших из строя соратников по оружию.
Памятки и перемешанные личные колоды располагаются неподалёку, возьмите в руку пять (бандит) и четыре (шериф) игровые карты. Стартовый выстрел делает служитель закона.
В свой ход первым делом возьмите с личной колоды две карты, а затем можете сыграть с руки только одну с красной окантовкой и сколько угодно с коричневой и синей. Помните, что атаковать можно только активного персонажа, отмеченного маркером. Хотя, некоторые свойства позволяют дотянуться и до прикрывающего его соперника.
Один раз в любой момент розыгрыша карт вы можете переместить свой маркер активного стрелка на соседнего персонажа (перегруппировать ваших подопечных). Синие карточки длительного действия располагаются неподалёку от героев, на которых они сыграны, и остаются со своими хозяевами до момента их гибели, оказывая определённый эффект. Например, «Прицел» позволяет атаковать прикрывающего персонажа противника.
Каждый успешный выстрел снимает один патрон с карточки персонажа. Использованные карты уходят в общий сброс, который потом доступен оппонентам. Поэтому не удивляйтесь, когда ближе к концу партии к вам в руку придут карточки противоборствующей стороны…
Парировать выстрел можно карточкой «Мимо!», а восстановить здоровье поможет глоток крепкого напитка. Некоторые синие карты разрешается «подбрасывать» в стан врага – там они принесут массу неприятностей. Знаменитая «Бочка» вся также стоит на страже спрятавшегося за ней стрелка.
Коричневая окантовка, порой, не несёт ничего хорошего для противника: имея хорошие карты в руке можно вызвать оппонента на дуэль, а брошенный нож дополнит меткий выстрел. Безусловно, не забывайте и о личной пользе – «Фургон», например, дополнительно пополнит вашу руку.
На место убитого персонажа встаёт новый, пока вся ваша команда либо не уничтожит отряд противника, либо сама не падёт под градом вражеских пуль. Третьего не дано – таковы безжалостные законы Дикого Запада…
Убив четырёх зайцев
Давно хотел сыграть в «Бэнг!» вдвоём… Довольно часто после насыщенного трудового дня возникает желание разрядить в кого ни будь пару обойм, а необходимого количества стрелков поблизости как назло нет. Дуэльный вариант – это то, что нужно! Увы, никакие «домашние» правила, внедрённые в обычную «пулю», так и не прижились. А пострелять-то хочется!Процесс перестрелки динамичный и интересный – та как все персонажи обладают индивидуальными свойствами, вам необходимо сориентироваться по ситуации и вовремя переставить маркер активного стрелка на героя, наиболее подходящего под текущий момент. Не забывайте про синие карточки длительного действия – с их помощью можно атаковать даже засевшего в укрытии прикрывающего стрелка.
Атмосферная карточная «стрелялка» для двух отчаянных игроков в ковбойских шляпах и с кольтами наперевес.
Стиль героев Леонардо ДиКаприо | Журнал Esquire.ru
Если пристально рассматривать кинообразы Леонардо ДиКаприо, то видна закономерность: большинство его перевоплощений на экране похожи между собой — это хорошо одетые мужчины в классических, немного старомодных или просто сдержанных костюмах, и не важно, в каком времени разворачивается сюжет картины.
Исторический фильм Мартина Скорсезе «Банды Нью-Йорка» рассказывает про уличные столкновения на улицах города в середине XIX века. Примерно в ту же эпоху разворачивается и сюжет «Джанго освобожденного» Квентина Тарантино. В обоих картинах Леонардо ДиКаприо щеголяет в костюмах по моде того времени, с обязательным шейным платком и строгим головным убором.
Alamy/Legion Media«Банды Нью-Йорка», 2002
Alamy/Legion Media«Джанго освобожденный», 2012
Получивший «Оскар» за костюмы «Великий Гэтсби» База Лурмана — история про блистательные двадцатые, и главный герой в исполнении ДиКаприо одевается с особым шиком: пиджаки пастельных оттенков, запонки, галстуки и платки тон в тон.
Alamy/Legion Media«Великий Гэтсби», 2013
Биографическая драма Мартина Скорсезе «Авиатор» рассказывает о жизни американского авиатора и кинопродюсера Говарда Хьюза и охватывает предвоенную половину XX века: в кадре можно увидеть костюмы из мягкой ткани, широкие галстуки и белые рубашки с острым отложным воротничком.
Alamy/Legion Media«Авиатор», 2004
Драма «Дорога перемен» и триллер «Остров проклятых» — две совсем разные по духу истории, разворачивающиеся в пятидесятые. В одной из них Леонардо ДиКаприо играет роль примерного семьянина, отважившегося на перемены в жизни, в другом фильме он — полицейский в погоне за беглым преступником, но в обоих его герои носят все те же простые и чуть свободные костюмы, аккуратные рубашки и галстуки с узором.
Alamy/Legion Media«Дорога перемен», 2008
«Остров проклятых», 2010
Действие фильма «Волк с Уолл-стрит» Мартина Скорсезе начинается в конце восьмидесятых, и Леонардо ДиКаприо в роли брокера Джордана Белфорта одевается по всем правилам пауэр-дрессинга — темные костюмы в тонкую полоску с пиджаком нараспашку, рубашка под запонки и неброские, но статусные аксессуары.
Alamy/Legion Media«Волк с Уолл-стрит», 2013
Сюжет «Совокупности лжи» Ридли Скотта разворачивается уже в XXI веке, а «Начало» Кристофера Нолана балансирует на грани недалекого будущего. В обоих фильмах Леонардо ДиКаприо носит классические темные костюмы — одновременно и униформу, и не отвлекающий от личности персонажа «чистый лист». Такая одежда может быть у героя абсолютно любого времени и профессии.
Alamy/Legion Media«Совокупность лжи», 2008
Alamy/Legion Media«Начало», 2010
Эта вереница похожих образов вовсе не говорит о сходстве ролей и героев и никак не принижает таланта ДиКаприо как актера, а наоборот, наглядно иллюстрирует тезис о том, что хороший мужской костюм — решение вневременное и очень удачное для самых разных обстоятельств.
django-rules · PyPI
h2 (# аннотация). django-rulesdjango-rules — это бэкэнд авторизации Django, который предлагает унифицированное управление авторизацией для каждого объекта. Он сильно отличается от других механизмов авторизации тем, что позволяет гибко управлять разрешениями для каждого объекта.
В правилах django каждое правило добавляет ограничение авторизации к данной модели. Ограничение авторизации проверяет, соответствует ли данный пользователь ограничению (например, если у пользователя есть права на выполнение определенного действия над объектом и т. Д.). Ограничение авторизации может быть логическим атрибутом, свойством или методом модели, в зависимости от того, что вы предпочитаете для каждого правила 🙂
h3 (#philosophy). Философия
django-rules стремится создать гибкий и масштабируемый бэкэнд авторизации. Почему это лучше, чем другие механизмы авторизации?
* Бэкэнд простой, лаконичный и компактный. Меньше строк кода означает меньшую сложность, более быстрое выполнение и (надеюсь) меньше ошибок и ошибок.
* Вы можете реализовать каждое ограничение авторизации как логический атрибут, свойство или метод модели, в зависимости от того, что вы предпочитаете для каждого правила 🙂 Таким образом, вы сможете повторно реализовать работу авторизации в любое время.Он динамический, и вы знаете динамические звуки лучше, чем статические 🙂
* Вам не нужно добавлять дополнительные разрешения или группы для ваших пользователей. Вы просто программируете ограничения, какими хотите, а затем назначаете их правилам. Сделанный!
* У вас есть точный контроль над тем, как правила обрабатывают аутентификацию: одно правило может использовать ограничение авторизации, которое использует LDAP, в то время как другие правила вызывают веб-службу (или все, что вы хотите подключить к ограничению авторизации).
* Другие серверы авторизации для каждого объекта создают строку в таблице для каждого объекта, каждого пользователя и каждой комбинации разрешений. Даже с сайтом среднего размера вам будут сниться кошмары о масштабируемости, независимо от того, сколько вы можете кэшировать.
* Другие серверы авторизации должны ВЫБРАТЬ все разрешения, которые есть у пользователя, даже если вам нужно проверить только одно конкретное разрешение, что увеличивает объем памяти.
* Другие серверы авторизации не имеют возможности устанавливать централизованные разрешения, которые являются реальной необходимостью в большинстве проектов.
h3 (# требования). Требования
django-rules требует правильной установки Django 1.2 (как минимум).
h3 (# установка). Установка
h4 (#pypi). Из Pypi
Все просто:
pip install django-rules
h4 (#source). Из источника
Чтобы установить django-rules из источника:
git clone https://github.com/maraujop/django-rules/
cd django-rules
python setup.py install
h3 (#configuration). Конфигурация
Чтобы django-rules работало, вы должны подключить его к своему проекту:
* Добавьте его в список INSTALLED_APPS
в settings.py
:
INSTALLED_APPS = (
...
'django_rules',
)
* Добавить сервер авторизации django-rules в список AUTHENTICATION_BACKENDS
в настройках .py
:
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # бэкэнд аутентификации по умолчанию в Django
'django_rules.backends.ObjectPermissionBackend',* Запустите syncdb, чтобы обновить базу данных новыми моделями правил django:
python manage.py syncdb
h3 (#rules). Правила
Правило представляет собой функциональное ограничение авторизации, которое ограничивает действия, которые определенный пользователь может выполнять с определенным объектом (экземпляром Модели).
Каждое определение правила состоит из 6 параметров (3 обязательных и 3 необязательных):
*app_name
: имя приложения, к которому применяется правило.
*кодовое имя
: имя правила, _уникальное для всех приложений_. Это должно быть краткое, но характерное имя.
*модель
: имя модели, связанной с правилом.*
field_name
_ (необязательно) _: имя логического атрибута, свойства или метода модели, реализующей ограничение авторизации.Если не установлен, по умолчанию используется значение обязательного поляcodename
.
*view_param_pk
_ (необязательно) _: имя параметра представления, которое будет использоваться для получения первичного ключа модели. Он используется в декорированных представлениях для получения фактического экземпляра модели, объекта, для которого будут проверяться права доступа. Если не установлен, по умолчанию используется имя поля первичного ключа в модели. Обратите внимание, что если имя параметра представления, содержащего значение первичного ключа объекта, не совпадает с именем первичного ключа модели, в этом параметре должно быть указано новое имя (мы поговорим об этом специальном case в "разделе о декораторах": # декораторы).и должен использоваться всегда.Правила должны создаваться для каждого приложения Django. То есть в корневом каталоге приложения Django, в котором вы хотите создать правила, у вас должен быть файл
rules.py
, содержащий только объявления тех правил, которые относятся к этому приложению Django.После того, как вы определили правила в
rules.py
, вы захотите их активировать. Для каждого правила, которое вы хотите активировать, вы * должны * добавить для него точку регистрации, вызвавdjango_rules.utils.register
вrules.py
.Наконец, как только вы правильно настроите
rules.py
, вы захотите синхронизировать правила с базой данных. В вашем проекте Django вам нужно будет запустить командуsync_rules
:
python manage.py sync_rules
Эта команда будет искать все ваши
rules.py
в вашемINSTALLED_APPS
и будут синхронизировать последние изменения в базе данных, поэтому вам не нужно запускатьsyncdb
или перестраивать полную базу данных вообще.h3 (#examples). Примеры:
h4 (# ex1). Пример 1. Создание простого и компактного правила для модели Item в Django-приложении "доставка"
Давайте представим себе, что в Django-приложении
shipping
у меня есть следующие модели. py
:
class Item (models.Model):
supplier = models.ForeignKey (User)
description = models.CharField (max_length = 50)
Затем представьте что бизнес-логика в нашем приложении имеет функциональное ограничение авторизации для каждого элемента, например «Товар может быть отправлен только его поставщиком».Теперь, чтобы выполнить ограничение функциональной авторизации, нам нужно только создать простое правило.
Во-первых, давайте начнем с добавления ограничения авторизации в модель Item. Помните, что мы можем использовать метод, логический атрибут или свойство, возвращающее логическое значение. На этот раз мы будем использовать метод:
class Item (models.Model):
supplier = models.ForeignKey (User)
description = models.CharField (max_length = 50)def can_ship (self, user_obj):
"" "
Проверяет, является ли данный user_obj поставщиком элемента
" ""
return self.всегда добавлять необязательное поле «описание»
#, чтобы дать краткое объяснение ожидаемого поведения правила.# Чтобы правила были активными, мы * должны * зарегистрировать их:
для правила в rules_list:
utils.register (app_name = 'shipping', ** rule)
Наконец, не забывайте для синхронизации правил, чтобы убедиться, что все новые определения, изменения и т. д. синхронизируются с базой данных.
python manage.py sync_rules
h4 (# ex2).Пример 2: Создание правила, которое не следует соглашениям об именах
Представьте, что мы хотели бы назвать наши ограничения авторизации, как мы хотим. Например, давайте изменим предыдущую модель предмета:
class Item (models.Model):
supplier = models.ForeignKey (User)
description = models.CharField (max_length = 50)def isSameSupplier (self , user_obj): # -> изменение соглашения об именах ограничения авторизации
"" "
Проверяет, является ли данный user_obj поставщиком элемента
" ""
return self.чтобы дать краткоеописание
:
из django_rules import utilsrules_list = [
{'codename': 'can_ship', 'model': 'Item', 'field_name': 'isSameSupplier',
'description': 'Проверяет, является ли данный пользователь поставщиком элемента'},
]# Чтобы правила были активными, мы * должны * зарегистрировать их:
для правила в rules_list:
utils.register (app_name = 'shipping', ** rule)
Опять же, не забудьте синхронизировать правила, чтобы убедиться, что все новые определения, изменения и т. д.применяются к базе данных.
python manage.py sync_rules
h4. Использование ваших правил
После того, как вы настроили правило, реализующее функциональное ограничение авторизации, вы можете (и должны 🙂 использовать его в своем приложении. Это действительно просто! В каждом месте, где вы хотите применить ограничение авторизации для пользователя, вы просто сделаете следующий вызов:
user_obj.has_perm (codename, model_obj)
Следуя предыдущему «примеру 1» : # ex1, давайте представим, что приложение уже работает с данными в базе данных (по крайней мере, один поставщик и один товар, оба с идентификаторами равными 1).Помните, что мы уже реализовали, определили, зарегистрировали и синхронизировали следующее правило:
{'codename': 'can_ship', 'model': 'Item'}
Тогда, если мы хотели проверить, может ли поставщик отгрузить товар, нам нужно было только обеспечить соблюдение правила, выполнив:
supplier = Supplier.objects.get (pk = 1)
item = Item.objects.get (pk = 1)если supplier.has_perm ('can_ship', item):
print 'Ура! Поставщик может отправить товар! :) '
Легко, правда? 🙂
h5.Подробности о внутренней магии django-rules
Обратите внимание, что ниже приводится подробное объяснение того, как протекает вся внутренняя магия в django-rules. Если вам все равно, пожалуйста, двигайтесь дальше. Вам действительно не нужны эти детали, чтобы иметь возможность писать правила и эффективно использовать django-rules. Однако, если вам интересно и вы хотите узнать больше, обратите особое внимание на детали, приведенные ниже.
Вот как все части головоломки собираются вместе:
* Когда вы вызываетеuser_obj.has_perm (codename, model_obj)
(в предыдущем примере,supplier.has_perm ('can_ship', item)
), Django передает управление бэкэнду django-rules.
* Серверная часть django-rules затем попытается сопоставитькодовое имя
с правилом. Обратите внимание, что мы запрашиваем правило сcodename
из'can_ship'
иmodel_obj
как Модель объекта элемента. Поскольку в «Пример 1»: # ex1 мы определили правило{'codename': 'can_ship', 'model': 'Item'}
, совпадение будет.
* Затем django-rules проверит, является лиfield_name
атрибутом, свойством или методом, и будут действовать соответственно. Еслиfield_name
является методом, бэкэнд django-rules проверит, требуется ли ему только один пользовательский параметр или вообще не требуется никаких параметров. В зависимости от требований к параметрам он выполнитmodel_obj.field_name ()
илиmodel_obj.field_name (user_obj)
. В нашем «примере 1»: # ex1 нам требуется пользовательский параметр, чтобы он выполнял элемент.can_ship (поставщик)
.
* Наконец, если ограничение авторизации, реализованное вfield_name
, имеет значение True или возвращает True, ограничение считается выполненным. В противном случае вы не авторизуетесь.h4. Подробности использования методов модели в правилах
Как мы видели, django-rules проверяет, является ли
field_name
атрибутом, свойством или методом, и будет действовать соответственно. Вы можете создавать правила на основе атрибутов и свойств модели, которые более чем подходят для очень простых случаев, но в большинстве случаев вы будете устанавливатьfield_name
для метода в модели.Важно отметить, что этот метод ограничен наличием только одного параметра (пользовательский объект) или отсутствием параметров вообще. Он не может получать несколько аргументов или аргумент, не являющийся экземпляром User. Хотя это может показаться ограничением, мы не могли придумать вариант использования, в котором остальная необходимая информация не могла бы быть получена от пользователя или объекта модели. Если вы попали в ситуацию, когда это вас ограничивает, пожалуйста, свяжитесь с нами и объясните свою проблему, чтобы мы могли подумать, как ее обойти! 🙂
Наконец, вам нужно знать кое-что очень важное: метод, назначенный правилу (с этого момента давайте называть их _rule methods_) * никогда не должен вызывать какой-либо другой метод *.То есть они должны быть самодостаточными. Это сделано для того, чтобы избежать потенциальной бесконечной рекурсии. Представьте себе ситуацию, когда метод правила вызывает другой метод, который имеет такое же_ ограничение авторизации, что и предыдущий метод правила. Бум! Вы только что создали бесконечный цикл. Беги, если твоя жизнь тебе дорога! 🙂
Вы можете подумать, что можете это контролировать, но, поверьте мне, это будет очень сложно поддерживать и масштабировать. Не всегда все будет так просто, возможно, вы в конечном итоге вызовете метод, который позже будет изменен и в конечном итоге вызовет вспомогательную функцию, которая запускает тот же цикл авторизации.Да, я знаю. Косвенное обращение - это стерва 🙂 Или, другими словами, «великая сила приходит с большой ответственностью». Так что остерегайтесь бесконечного цикла;)
h3 (#decorators). Декораторы
Если вам нравится Python так же, как и мне, вы полюбите декораторы. Django имеет декоратор
permission_required
, поэтому казалось естественным, что django-rules реализовали декораторobject_permission_required
.Представьте, что для нашего «Пример 1»: # ex1 у нас есть следующий код в представлениях
.py
:
def ship_item (request, id):
item = Item.objects.get (pk = id)if request.user.has_perms ('can_ship', item):
return HttpResponse ('success')return HttpResponse ('error')
Мы могли бы легко украсить представление, чтобы сделать метод более компактным и легким для чтения:
from django_rules import object_permission_required@object_permission_required ('can_ship')
def ship_item (request, id):
return HttpResponse ('Товар успешно отправлен! :)')
Магия декоратора действительно очень крутая.Во-первых, он соответствует правилу и получает из него тип модели. Затем он получает параметр
id
из kwargs представления и создает экземпляр объекта Model с помощьюitem = model.objects.get (pk = id)
. Наконец, он может вызвать для васrequest.user.has_perm ('can_ship', item)
и перенаправить на страницу сбоя, если ограничение не выполнено.Обратите внимание, как мы сохранили имя первичного ключа модели в параметрах представления.Если параметр имеет имя, не совпадающее с именем первичного ключа в модели, помните, что нам придется добавить в правило еще один необязательный параметр. Из «раздела о правилах:»: # rules
*view_param_pk
_ (необязательно) _: имя параметра представления, которое будет использоваться для получения первичного ключа модели. Он используется в декорированных представлениях для получения фактического экземпляра модели. Если не установлен, по умолчанию используется имя поля первичного ключа в модели. Обратите внимание: если имя параметра представления, содержащего значение первичного ключа объекта, не совпадает с именем первичного ключа модели, в этом параметре необходимо указать новое имя.Например, если мы изменим параметр представления:
из django_rules import object_permission_required@object_permission_required ('can_ship')
def ship_item (request, my_item_code): # -> изменение наименования параметра в представлении
return HttpResponse ('success')
Нам нужно будет указать
view_param_pk
в определении правила:
rules_list = [
{'codename': 'can_ship', 'model': 'Item', 'view_param_pk': 'my_item_code',
'description': 'Проверяет, является ли данный пользователь поставщиком товара'},
]
Декоратор
object_permission_required
может получать 4 аргумента:
@object_permission_required ('can_ship', return_403 = True)
@object_permission_required ('can_ship', redirect_url = '/ more / foo / bar / ')
@object_permission_required (' can_ship ', redirect_field_name =' myFooField ')
@obj ect_permission_required ('can_ship', login_url = '/ foo / bar /')
По умолчанию:
*return_403
имеет значение False.
*redirect_url
- пустая строка.
*redirect_field_name
имеет значение REDIRECT_FIELD_NAME django.contrib.auth.
*login_url
имеет значениеsettings.LOGIN_URL
.Таким образом, если ограничение авторизации не выполняется, декоратор по умолчанию будет перенаправлять на страницу входа в систему в стиле Django 🙂
Также обратите внимание, что несколько параметров имеют специфичность. А именно:
* если дляreturn_403
установлено значение True, он переопределит остальные параметры, и декоратор вернет HttpResponseForbidden.
* если дляredirect_url
задан URL-адрес, он заменит URL-адресlogin_url
.Наконец, важно отметить сложную деталь, касающуюся использования декоратора для защиты доступа к тем методам, которые не представлены напрямую как представления, сопоставленные с внешними URL-адресами. Когда метод представления является точкой входа через URL-адреса (то есть, если ваш метод представления сопоставлен непосредственно с одной из записей
urls.py
), Django анализирует URL-адрес и передает параметры представлению какkwargs
.Таким образом, если вы хотите использовать декораторobject_permission_required
над внутренним методом (методом, который вызывается внутри одного из этих внешних представлений или где-то еще в вашем коде), вы должны использоватьkwargs при передаче параметров.
Давайте посмотрим на пример:
def item_shipper (request, id):
internal_code = 'XXX-' + my_item_code
return _ship_item (request, id = internal_code) # вместо того, чтобы делать return _ship_item (request, internal_code )@object_permission_required ('can_ship')
def _ship_item (request, id)
return HttpResponse ('success')
h3 (#centralizedpermissions).Централизованные разрешения
django-rules имеет централизованный диспетчер авторизации, который нацелен на очень распространенные потребности в реальных проектах: специальные привилегированные группы, такие как администраторы, сотрудники службы поддержки пользователей и т. Д., Которые имеют разрешения на переопределение определенных аспектов ограничения авторизации в приложении. В таких случаях django-rules может позволить вам обойти его систему авторизации по любым причинам.
Для настройки централизованных разрешений вам необходимо установить в настройках вашего проекта переменную
CENTRAL_AUTHORIZATIONS
, указывающую на модуль.В этом модуле вам нужно будет определить возвращающую логическое значение функцию с именемcentral_authorizations
, принимающую ровно два параметра:
*user_obj
: объект пользователя.
*codename
: кодовое имя правила, которое будет отменено. Очень полезно уточнить разрешения специального пользователя «а-ля ACL».
Обратите внимание, что, хотя название параметров не имеет значения, порядок имеет значение. Первый параметр получит объект пользователя, а второй параметр - кодовое имя правила.Эта функция
central_authorizations ()
будет вызываться * перед * любым другим правилом, поэтому вы можете переопределить их здесь.Например, в
settings.py
вы добавите:
CENTRAL_AUTHORIZATIONS = 'myProjectFoo.utils'
А затем в myProjectFoo в
utils.py
, вы реализуете функциюcentral_authorizations ()
с переопределениями для специальных пользователей.Представьте, что вы хотите предоставить специальный доступ персоналу службы поддержки пользователей, который будет иметь доступ к некоторым личным полям в профиле (например, электронной почте и возрасту), которые обычно скрыты от обычных пользователей приложения. Они предназначены для поддержки пользователей, поэтому у них не должно быть возможности переопределять определенные вещи в приложении. Тем не менее, вы также хотите, чтобы ваши сверхадминистраторы (как правило, разработчики) имели доступ ко всему в приложении, чтобы они могли быстро кодировать и тестировать во время разработки.
В таком случае вы можете написать следующую функцию
central_authorizations ()
:
def central_authorizations (user_obj, codename):
"" "
Эта функция будет вызываться * перед * любое другое правило,
, чтобы вы могли переопределить здесь все разрешения.
"" "
isAuthorized = Falseif user_obj.get_profile (). isUberAdmin ():
isAuthorized = True
elif user_obj.get_profile (). isUserS ) и кодовое имя в ['can_see_full_profile', 'can_delete_item']:
isAuthorized = Truereturn isAuthorized
Как вы понимаете, все, что проверяется в
central_authorizations
, является глобальным для * весь * проект.h3. Статус и тестирование
django-rules предназначено для обеспечения безопасности. Таким образом, он был тщательно протестирован. Он поставляется с набором тестов, которые пытаются охватить все доступные функциональные возможности. Однако, если вы столкнетесь с ошибкой или нестандартной ситуацией, не стесняйтесь сообщать об этом через «трекер ошибок Github»: https: //github.com/maraujop/django-rules/issues.
Наконец, приложение поддерживает множество различных исключений, которые обеспечивают правильное создание правил.Они также предназначены для защиты вашего приложения от небрежности. Управляйте исключениями с умом, и вы станете счастливым и безопасным программистом, поскольку безопасность защищена от возможной халатности. Вы должны обращаться с ними осторожно.
h4. Тестирование django-rules
Чтобы запустить тесты, войдите в каталог тестов и выполните:
./runtests.py
Он всегда должен говорить ОК. Если нет, то есть сломанный тест, о котором, я надеюсь, вы скоро сообщите 🙂
h3.Нужны еще примеры?
Я изо всех сил пытался объяснить концепцию правил django, но, если вы предпочтете посмотреть больше примеров кода, я уверен, что вы найдете «код в тестах»: https: //github.com/ maraujop / django-rules / blob / master / django_rules / tests / test_core.py весьма полезно 🙂
h3. Дополнительная документация
В случае, если вы хотите знать, где появился весь этот «бэкэнд для индивидуальной аутентификации в Django», вы должны, по крайней мере, прочитать следующие ссылки:
* Отличная статья о «бэкэндах для индивидуальных разрешений в Django» : http: // djangoadvent.com / 1.2 / object-permissions / от Флориана Аполлонера
* Также проверьте объяснение изменений, внесенных при исправлении "django ticket # 11010": http: //code.djangoproject.com/ticket/11010Наконец, мой Самая искренняя признательность всем, кто вносит свой вклад в прекрасную среду разработки Django, а также остальным разработчикам и коммиттерам, которые создают с их помощью правила django. Уважать! 🙂
python - разрешения django-rules не распространяются должным образом через Django REST Framework
Я пытаюсь настроить базовую авторизацию в своем тестовом приложении
, свяжитесь с
в проекте Django, используя правила django.Есть две модели:
Контакт
иАдрес
. Я хочу ограничить удаление объектов на основе моего настраиваемого предикатаis_owner
.Вот мои определения предикатов и правил в
myapp / rules.py
:правила импорта из shared.decorators импортировать log_exec logger = logging.getLogger ("myproject.auth") @log_exec (регистратор) @ rules.predicate def is_owner (пользователь, объект): если obj: если obj.created_by == user: регистратор.info ("[OK] Разрешение предоставлено.") вернуть True еще: logger.info («[НЕТ] Разрешение не предоставлено.») вернуть ложь еще: logger.info ("Объект не определен.") вернуть ложь # Определения правил rules.add_perm ("контакт", rules.always_allow)
Вот мои определения моделей в
models.py
, включая разрешения:правила импорта из моделей импорта django.db из django_countries.fields импорт CountryField из .импорт правил is_owner из shared.models импортировать CommonModel Адрес класса (CommonModel):
класс Мета: [...] rules_permissions = { "просмотр": rules.is_authenticated, "добавить": rules.is_staff, "изменить": rules.is_staff, «удалить»: is_owner, } [...] класс Контакт (CommonModel): класс Мета: [...] rules_permissions = { "взгляд": правила.is_authenticated, "добавить": rules.is_staff, "изменить": rules.is_staff, «удалить»: is_owner, } Оба основаны на CommonModel, который я определил в отдельном приложении (shared / models.py), к которому я также привязываю миксин django-rules:
импорт uuid из настроек импорта django.conf из моделей импорта django.db из django_extensions.db.models import TimeStampedModel из rules.contrib.models импортировать RulesModelBase, RulesModelMixin класс CommonModel (RulesModelMixin, TimeStampedModel, метакласс = RulesModelBase): "" "Общие поля, общие для всех моделей."" " класс Мета: abstract = True created_by = models.ForeignKey ( settings.AUTH_USER_MODEL, editable = False, related_name = "+", blank = True, null = True, on_delete = models.PROTECT, ) modified_by = models.ForeignKey ( settings.AUTH_USER_MODEL, editable = False, related_name = "+", blank = True, null = True, on_delete = models.PROTECT, ) uuid = models.UUIDField (по умолчанию = uuid.uuid4, editable = False)
Проверяю правила в двух местах:
1.Оболочка Django
Кажется, работает нормально. Проверка моих пользователей на соответствие наборов разрешений с помощью has_perm, похоже, дает только ожидаемые результаты.
2. Django REST Framework
Когда я делаю запросы через свой API, который я установил с помощью Django REST Framework, при удалении я наблюдаю следующее:
Разрешение предоставлено, как ожидалось (на основе регистрации). Однако API возвращает 403 Forbidden с
«detail»: «У вас нет разрешения на выполнение этого действия.«
.Где я могу / могу проверить, какие изменения произошли между проверкой правила и генерацией ответа для API?
Есть ли хороший способ проследить, что именно происходит внутри?
Вот как определяются мои представления (
contact / views.py
):из rules.contrib.rest_framework import AutoPermissionViewSetMixin from contact.models import Address, Contact из contact.serializers import AddressSerializer, ContactSerializer из общего.Представления импортируют CommonViewSet класс AddressViewSet (AutoPermissionViewSetMixin, CommonViewSet): "" " Конечная точка API, позволяющая просматривать или редактировать адреса. "" " queryset = Address.objects.all () serializer_class = AddressSerializer класс ContactViewSet (AutoPermissionViewSetMixin, CommonViewSet): "" " Конечная точка API, позволяющая просматривать или редактировать контакты. "" " queryset = Contact.objects.all () serializer_class = ContactSerializer
NB: вот декоратор ведения журнала, который я использую в дополнение к декоратору предикатов:
def log_exec (регистратор): "" "Декоратор для записи имени выполняемой функции" "" def external_wrapper (fn): def inner_wrapper (* args, ** kwargs): msg = f "Выполняемая функция: {fn.__название__}" logger.info (сообщение) fn (* аргументы, ** kwargs) вернуть inner_wrapper вернуть external_wrapper
Создание приложения Django с контролем доступа к данным - oso
Почти каждое приложение должно позволять своим пользователям видеть только свои данные. Многие другие приложения идут еще дальше и добавляют дополнительные элементы управления, такие как совместное использование или создание частного и общедоступного контента. Эти концепции становятся все более важными, поскольку конфиденциальность данных постоянно находится в центре обсуждения в технических, деловых и политических кругах.
В этом посте мы рассмотрим, как создать простое социальное приложение, которое позволяет пользователям делиться сообщениями, например Twitter. Мы будем использовать Django, популярный веб-фреймворк Python, который включает ORM и систему шаблонов. В отличие от Twitter, наше приложение будет включать контроль видимости постов. Мы реализуем этот контроль доступа с помощью Oso, механизма политик с открытым исходным кодом, встроенного в ваше приложение. Пакет django-oso позволяет использовать Oso в приложении Django с небольшой настройкой.
В этом руководстве будут рассмотрены:
- Запуск проекта Django
- Создание пользовательской модели пользователя
- Создание моделей и представлений Django для вывода списка и создания сообщений
- Добавление Oso в наше приложение Django для реализации общедоступных и частных сообщений.
Учебное пособие является самодостаточным, но при желании вы можете следить за ним в репозитории на github.
Запуск нашего проекта Django
Для начала нам понадобится Python 3 (минимум 3.6) установлен. Давайте запустим новый каталог для нашего проекта, а также создадим и активируем виртуальную среду.
$ mkdir осо-социальный
$ cd oso-social
$ python -m venv venv
$. Venv / bin / активировать
Теперь давайте установим django
и django-oso
в нашу виртуальную среду.
$ pip install django
$ pip установить django-oso
Django включает инструмент django-admin
, в котором есть команды для создания шаблонов приложений django и их разработки.Мы будем использовать его для запуска нового проекта:
$ django-admin startproject oso_social
Это создаст новый каталог oso_social
в нашем каталоге верхнего уровня:
ls -l oso_social
всего 392
-rwxr-xr-x 1 персонал dhatch 666 3 сентября 16:14 manage.py
drwxr-xr-x 8 dhatch Staff 256 3 сен, 17:55 oso_social
ls -l oso_social / oso_social
всего 32
-rw-r - r-- 1 посох дхатча 0 3 сен 16:14 __init__.ру
-rw-r - r-- 1 посох дхатча 397 3 сен 16:14 asgi.py
-rw-r - r-- 1 посох dhatch 3219 3 сентября 17:55 settings.py
-rw-r - r-- 1 посох дхатча 798 3 сентября 16:44 urls.py
-rw-r - r-- 1 посох дхатча 397 3 сентября 16:14 wsgi.py
Каждый проект Django разбит на несколько приложений. Приложения - это модули Python, которые можно использовать в разных проектах. Модуль oso_social / oso_social
- это модуль проекта, который включает настройки и конфигурацию для нашего проекта oso_social
.
Давайте сейчас создадим приложение, которое будет содержать наши модели и представления базы данных. В каталоге oso_social
:
$ cd oso_social
$ ./manage.py startapp social
ls -l социальный
всего 56
-rw-r - r-- 1 посох dhatch 0 3 сентября 16:14 __init__.py
-rw-r - r-- 1 персонал dhatch 206 3 сен 16:33 admin.py
-rw-r - r-- 1 персонал dhatch 87 3 сентября 16:14 apps.py
-rw-r - r-- 1 посох дхатча 638 3 сен 17:46 models.py
-rw-r - r-- 1 персонал dhatch 60 3 сентября 16:14 tests.ру
-rw-r - r-- 1 посох дхатча 394 3 сен 17:52 urls.py
-rw-r - r-- 1 посох дхатча 1312 3 сен 17:59 views.py
Мы только что использовали утилиту manage.py
, которая делает то же самое, что и django-admin, но знает настройки проекта. Это позволяет ему выполнять специфические задачи проекта, такие как операции с базой данных.
Чтобы завершить настройку нашего приложения social
, нам нужно добавить его в файл настроек, чтобы Django узнал об этом. В oso_social / oso_social / settings.py
:
# Найдите этот параметр в файле и добавьте «социальный».
INSTALLED_APPS = [
# ... существующие записи ...
'Социальное',
]
Создание нашей модели пользователя
Сначала мы собираемся создать модель User для представления пользователей в нашем приложении. Эта модель будет использоваться для хранения информации о пользователях в нашей базе данных. Django имеет встроенную систему авторизации, которая обрабатывает такие вещи, как управление паролями, вход в систему, выход из системы и пользовательские сеансы. Пользовательская модель User обеспечивает гибкость для добавления атрибутов позже нашему пользователю.
Давайте создадим его в нашем файле oso_social / social / models.py
. Используйте следующее содержимое:
из моделей импорта django.db
из django.contrib.auth.models импортировать AbstractUser
класс User (AbstractUser):
проходить
Встроенное приложение django.contrib.auth
обеспечивает аутентификацию для проектов Django. Мы будем использовать его, чтобы начать настройку аутентификации. Чтобы создать собственную модель пользователя, мы просто наследуем от AbstractUser
.Мы не определили никаких настраиваемых полей, поэтому тело класса пусто.
Затем мы добавим запись в наш файл настроек в oso_social / oso_social / settings.py
. Файл настроек настраивает проекты и приложения Django в нем. Это стандартный файл Python, в котором каждая запись конфигурации хранится как глобальная переменная. Мы добавим следующую строку:
AUTH_USER_MODEL = 'social.User'
Это указывает приложению django.contrib.auth
использовать модель User
из приложения social
для аутентификации.
Наконец, мы создадим миграцию базы данных. Встроенный в Django инструмент миграции базы данных поддерживает синхронизацию схемы вашей базы данных с моделями, используемыми в вашем приложении. Чтобы выполнить миграцию, запустите:
$ ./manage.py makemigrations social
Будет создано oso_social / social / migrations / 0001_initial.py
. Теперь примените эту миграцию к нашей базе данных (поскольку мы не настраивали параметры нашей базы данных, по умолчанию это база данных SQLite).
$./manage.py перенести
Тестирование наших настроек авторизации: вход в систему
Теперь давайте убедимся, что мы правильно настроили нашу аутентификацию и можем войти в систему. Мы еще не создали никаких представлений, но мы можем использовать встроенный интерфейс администратора Django, чтобы проверить нашу авторизацию.
Сначала добавьте нашу пользовательскую модель пользователя на сайт администратора в oso_social / social / admin.py
:
от администратора импорта django.contrib
из django.contrib.auth.admin импортировать UserAdmin
из .модели импортировать Пользователь
# Зарегистрируйте здесь свои модели.
admin.site.register (Пользователь, UserAdmin)
Затем создайте суперпользователя с помощью команды manage.py
:
$ ./manage.py создает суперпользователя
Вам будет предложено ввести учетные данные, которые вы затем будете использовать для входа на сайт администратора.
Давайте запустим наше приложение:
$ ./manage.py runserver
И посетите http: // localhost: 8000 / admin. Отсюда мы можем войти в систему и получить доступ к интерфейсу администратора.
Создание нашей модели Post
Теперь, когда мы настроили нашу учетную запись, давайте приступим к созданию функции публикации. Наше приложение позволит пользователям создавать новые сообщения и просматривать ленту сообщений. Чтобы поддержать это, мы создадим модель публикации, которая хранит информацию о записях в нашей базе данных.
В oso_social / social / models.py
создайте модель Post
ниже модели User
:
класс Post (models.Model):
ACCESS_PUBLIC = 0
ACCESS_PRIVATE = 1
ACCESS_LEVEL_CHOICES = [
(ACCESS_PUBLIC, "Общедоступно"),
(ACCESS_PRIVATE, "Частный"),
]
содержимое = модели.CharField (max_length = 140)
access_level = models.IntegerField (choices = ACCESS_LEVEL_CHOICES, по умолчанию = ACCESS_PUBLIC)
created_by = models.ForeignKey (Пользователь, on_delete = models.CASCADE)
created_at = models.DateTimeField (auto_now_add = True)
Это определяет класс модели с именем Post
с четырьмя полями: , содержимое
, access_level,
, created_at
и created_by
. Поле содержимого
будет хранить сообщение, отправленное пользователем, а created_at
и created_by
сохранят метаданные сообщения.Мы будем использовать access_level
позже, чтобы реализовать видимость сообщений с Oso.
Сохраните этот файл и создайте миграцию, чтобы таблица сохраняла модель Post
в нашей базе данных:
$ ./manage.py makemigrations social
Команда makemigrations
проверит модели на соответствие существующим миграциям и при необходимости создаст новые сценарии миграции. Большинство типов изменений базы данных обнаруживаются автоматически. Примените эту миграцию, как мы делали это раньше, с командой migrate
.
Итак, мы сделали нашу модель Post
. Давайте проверим, что все работает как задумано. Вместо того, чтобы создавать представление, мы будем использовать интерфейс администратора для создания нескольких сообщений. Зарегистрируйте сообщение в интерфейсе администратора, добавив следующее в oso_social / social / admin.py
:
# Добавить импорт поста (в дополнение к пользователю)
из .models import User, Post
# ...
admin.site.register (Сообщение)
Теперь мы можем посетить админку по адресу: http: // localhost: 8000 / admin /.Доступна модель Post, давайте воспользуемся интерфейсом администратора для создания публикации. Нажмите сообщения , затем Добавить сообщение вверху справа.
Заполните форму, как мы делали выше, и сохраните новую публикацию. Этот пример демонстрирует возможности интерфейса администратора Django. Без специального кода мы смогли протестировать нашу модель и взаимодействовать с ней!
Хорошо, хватит времени в админке. Давайте перейдем к созданию представления фида, которое будут использовать пользователи.С каждой страницей в веб-приложении Django связано представление . Когда пользователь посещает конкретный URL-адрес, функция просмотра отвечает за обработку запроса и создание ответа. Напишем простое представление для отображения сообщений.
В oso_social / social / views.py
напишите следующий код:
из django.shortcuts import render
из django.http import HttpResponse
из .models import Post
def list_posts (запрос):
# Не более 10 последних сообщений
posts = Сообщение.objects.all (). order_by ('- created_at') [: 10]
posts_text = ""
для публикации в сообщениях:
posts_text + = f "@ {post.created_by} {post.contents}"
вернуть HttpResponse (posts_text)
list_posts
- это наша функция просмотра. Сначала он использует Django QuerySet API и нашу модель Post
, чтобы получить первые 10 сообщений из базы данных, упорядоченных по последним сообщениям. Затем мы создаем строку для ответа, используя строки формата Python. Наконец, мы возвращаем HttpResponse
, содержащий posts_text
.
Мы написали нашу функцию просмотра, но еще не закончили! Нам все еще нужно указать Django, когда это следует вызывать. Для этого Django использует модули URLconf. Откройте oso_social / oso_social / urls.py
в своем редакторе. Это корневой URLconf. Он указывает, какие функции просмотра запускаются при запросе определенного URL-адреса. Прямо сейчас вы увидите шаблон URL: путь ('admin /', admin.site.urls)
, который управляет сайтом администратора. Добавим еще один паттерн:
# Добавить включить импорт
из джанго.путь импорта URL-адресов, включить
urlpatterns = [
путь ('admin /', admin.site.urls),
путь ('', include ('social.urls'))
]
Это указывает Django использовать файл oso_social / social / urls.py
для разрешения любых URL-адресов, которые не соответствуют admin /
.
Создадим его. В oso_social / social / urls.py
:
из пути импорта django.urls
из .views import list_posts
urlpatterns = [
путь ('', list_posts)
]
Единственный маршрут ( ''
) соответствует странице индекса.Django удаляет начальную косую черту из URL-адреса, поэтому корневая страница соответствует пустой строке. Наша функция list_posts
будет вызываться для обработки запросов к /
.
Попробуем запустить! Если у вас все еще работает ./manage.py runserver
, он должен быть перезагружен автоматически. Если нет, запустите его сейчас и посетите http: // localhost: 8000 /. Вы должны увидеть страницу, подобную приведенной ниже:
Продолжайте и используйте интерфейс администратора, чтобы создать еще несколько сообщений и посмотреть, как все выглядит на нашей новой странице каналов.
Использование шаблонов
Если вы сделали более одного поста, вы, вероятно, заметили, что рендеринг не идеален. Все сообщения отображаются в одной строке. Давайте создадим правильную HTML-страницу для нашего ответа вместо того, чтобы просто отвечать текстом. В этом нам может помочь встроенная система шаблонов Django. Для начала создайте новый файл по пути oso_social / social / templates / social / list.html
.
Добавьте содержимое:
Лента
{% за сообщение в сообщениях%}
@ {{сообщение.created_by.username}} {{post.contents}} {{post.created_at | date: "SHORT_DATETIME_FORMAT"}}
{% endfor%}
Этот HTML-код создан с использованием системы шаблонов Django. Это позволяет нам создавать HTML-страницы, в которых переменные будут заменены нашим кодом представления. Теги {% для сообщения в сообщениях%}
приводят к тому, что переменная шаблона post
назначается каждому элементу из повторяемых сообщений
.Затем мы интерполируем имя пользователя и содержимое, используя {{post.created_by.username}}
и {{post.contents}}
. Дата проходит через фильтр, чтобы правильно отформатировать ее для пользователя. Этот шаблон будет создавать тег
для каждого сообщения.
Чтобы использовать шаблон, измените нашу функцию list_posts
в oso_social / social / views.py
:
def list_posts (запрос):
# Не более 10 последних сообщений.
posts = Сообщение.objects.all (). order_by ('- created_at') [: 10]
вернуть рендер (запрос, 'social / list.html', {'posts': posts})
Мы использовали функцию рендеринга, которая сообщает Django о необходимости рендеринга шаблона по адресу social / list.html
с контекстом шаблона {'posts': posts}
. Контекст определяет, какие переменные доступны для механизма создания шаблонов. Django будет искать имя шаблона в любом каталоге под названием templates
в каждом приложении.
Теперь наш вид выглядит немного лучше!
Добавление новой формы сообщения
Нам нужно создать еще одно представление: представление «нового сообщения».Это представление позволит пользователю отправить сообщение и сохранит его в нашей базе данных. Начнем с создания шаблона. В oso_social / social / templates / social / new_post.html
:
Новое сообщение
Этот шаблон создает HTML-форму.Мы воспользуемся формой Django для замены переменной {{form}}
. {% csrf_token%}
включает токен для предотвращения атак CSRF (подделка межсайтовых запросов). Эта функция встроена в Django. Мы должны создать новый класс формы для использования с нашим шаблоном. Создайте файл oso_social / social / forms.py
:
из django.forms import ModelForm
из .models import Post
класс PostForm (ModelForm):
класс Мета:
model = Опубликовать
fields = ['содержимое', 'access_level']
Класс PostForm
наследуется от ModelForm
, который создает форму, имеющую входные данные на основе полей модели.Раскрывающийся список access_level
не будет иметь никакого влияния, пока мы не реализуем авторизацию.
Теперь давайте подключим все это к нашей функции просмотра:
# Новый импорт
из django.http import HttpResponseNotAllowed, HttpResponseRedirect
из django.urls импортировать обратный
из .forms import PostForm
# ...
def new_post (запрос):
если request.method == 'POST':
# Эта ветка запускается, когда пользователь отправляет форму.
# Создать экземпляр формы с отправленными данными.form = PostForm (request.POST)
# Преобразовать форму в экземпляр модели. commit = Ложь откладывает
# сохранение в базу данных.
post = form.save (фиксация = False)
# Сделать пользователя, вошедшего в систему, создателем сообщения.
post.created_by = request.user
# Сохранить пост в базе.
post.save ()
# Повторно перейти к списку сообщений.
вернуть HttpResponseRedirect (обратный ('индекс'))
elif request.method == 'ПОЛУЧИТЬ':
# GET вычисляется при загрузке формы.form = PostForm ()
# Визуализировать представление с формой для заполнения пользователем.
возврат рендера (запрос, 'social / new_post.html', {'form': form})
еще:
return HttpResponseNotAllowed (['GET', 'POST'])
Наконец, мы обновим наш URLconf, чтобы включить новое представление сообщений:
из пути импорта django.urls
из .views import list_posts, new_post
urlpatterns = [
путь ('', list_posts, name = 'index'),
путь ('новый /', новый_пост, имя = 'новый_пост'),
]
Аргумент name
для path
позволяет нам искать путь url по имени, которое мы используем как в наших шаблонах ( {% url 'new_post'%}
), так и для просмотра в обратном порядке ('index')
.
Давайте добавим кнопку на страницу индекса для перехода на страницу нового сообщения в oso_social / social / templates / social / list.html
:
Новое сообщение
Добавление страниц входа и выхода
Затем нам нужно добавить функцию входа в наше приложение, чтобы пользователи, у которых нет доступа к интерфейсу администратора, могли его использовать. У встроенного приложения аутентификации Django есть представления, которые могут управлять входом в систему и выходом из нее.
Чтобы воспользоваться ими, нам нужно добавить записи в наш URLconf в oso_social / social / urls.py
:
из django.contrib.auth импортировать просмотры как auth_views
urlpatterns = [
# ...
путь ('login /', auth_views.LoginView.as_view (template_name = 'social / login.html'), name = 'login'),
путь ('logout /', auth_views.LogoutView.as_view (), name = 'logout'),
]
Мы должны предоставить шаблон для представления входа в систему, и мы также захотим добавить кнопки входа и выхода из системы на каждой странице. Мы воспользуемся преимуществами системы наследования шаблонов Django, чтобы создать базовый шаблон, содержащий эти кнопки.Создайте файл oso_social / social / templates / social / base.html
:
{% block title%} oso-social {% endblock%}
{% if user.is_authenticated%}
Добро пожаловать, @ {{user.username}}.
Выйти
{% endif%}
Войти
{% содержимого блока%}
{% endblock%}
Устанавливает кнопку выхода и входа в систему, а также область содержимого {% block contents%}
, которую могут заполнять другие шаблоны.
Обновите наш шаблон list.html
:
{% extends 'social / base.html'%}
{% содержимого блока%}
Лента
{% за сообщение в сообщениях%}
@ {{post.created_by.username}} {{post.contents}} {{post.created_at | date: "SHORT_DATETIME_FORMAT"}}
{% endfor%}
Новое сообщение
{% endblock%}
и new_post.html
:
{% extends 'social / base.html '%}
{% содержимого блока%}
Новое сообщение
{% endblock%}
Тег {% extends%}
указывает, что этот шаблон наследуется от базового шаблона и заменяет содержимое между {% block contents%}
и {% endblock%}
в базовый.
Теперь создадим наш шаблон входа в систему! В oso_social / social / templates / social / login.html
:
{% extends 'social / base.html'%}
{% содержимого блока%}
Войти
{% endblock%}
Мы добавим в наш файл настроек следующие записи, которые необходимы для обеспечения работы этих встроенных представлений:
LOGIN_REDIRECT_URL = 'индекс'
LOGIN_URL = 'войти'
LOGOUT_REDIRECT_URL = 'индекс'
Наконец, мы можем добавить декоратор @login_required
в наше представление new_post
в oso_social / social / views.py
, который перенаправит пользователя на страницу входа в систему, если они попытаются создать сообщение перед входом в систему:
из django.contrib.auth.decorators import login_required
@login_required
def new_post (запрос):
# ...
Использование Oso для скрытия личных сообщений
Теперь, когда у нас есть основы, давайте дадим пользователям возможность создавать личные сообщения. Мы будем использовать для этого Осо.
Напомним, что наше определение модели для сообщения Post
включало поле с именем access_level
:
класс Post (модели.Модель):
ACCESS_PUBLIC = 0
ACCESS_PRIVATE = 1
ACCESS_LEVEL_CHOICES = [
(ACCESS_PUBLIC, "Общедоступно"),
(ACCESS_PRIVATE, "Частный"),
]
access_level = models.IntegerField (choices = ACCESS_LEVEL_CHOICES, по умолчанию = ACCESS_PUBLIC)
В этом целочисленном поле хранятся два варианта: ACCESS_PUBLIC
или ACCESS_PRIVATE
. Значения выбора: 0
и 1
соответственно, но пользовательская метка - «Public»
или «Private»
.Подробнее о вариантах см. Здесь.
Теперь давайте добавим django-oso
в наше приложение и настроим нашу политику публикации. Сначала добавьте django_oso
в список установленных приложений.
В oso_social / oso_social / settings.py
добавьте django_oso
в список из INSTALLED_APPS:
INSTALLED_APPS = [
# ...,
'django_oso',
]
django-oso предоставляет функцию авторизации
, которая будет оценивать политику управления доступом для данного актера, действия и ресурса.Мы будем использовать эту функцию для фильтрации сообщений из списка. В oso_social / social / views.py
:
# ...
из django.core.exceptions import PermissionDenied
из django_oso.auth импорт авторизации
def list_posts (запрос):
# Не более 10 последних сообщений.
posts = Post.objects.all (). order_by ('- created_at') [: 10]
авторизованные_посты = []
для публикации в сообщениях:
пытаться:
авторизовать (запрос, сообщение, действие = "просмотр")
авторизованный_posts.append (сообщение)
кроме PermissionDenied:
Продолжать
возврат рендера (запрос, 'social / list.html ', {' posts ': authorized_posts})
Для каждого сообщения, полученного из базы данных, мы вызываем и авторизуем
. Сообщения, которые не могут быть просмотрены пользователем, вызывают исключение PermissionDenied
. Они отфильтровываются из списка authorized_posts
, который возвращается пользователю.
Напоследок напишем нашу политику. Создайте файл с именем oso_social / social / policy / post.polar
:
# Разрешить кому угодно просматривать любые общедоступные сообщения.allow (_actor, "view", post: social :: Post), если
post.access_level = social :: Post.ACCESS_PUBLIC;
# Разрешить пользователю просматривать свои личные сообщения.
allow (актер: social :: User, "view", post: social :: Post), если
post.access_level = social :: Post.ACCESS_PRIVATE и
post.created_by = актер;
Каждая политика Oso состоит из правил, которые начинаются с заголовка правила, содержащего предикат ( разрешить (субъект, действие, ресурс),
в данном случае) и тело правила. Функция авторизации
запросит политику разрешить
правил.Если санкционируемый субъект, действие и ресурс соответствуют заголовку правила (часть правила до , если
), тело будет оценено, чтобы определить, успешен ли запрос.
В этой политике у нас есть два правила. Первое правило гласит, что любой субъект может выполнить действие «просмотр»
над сообщением
, имеющим уровень общего доступа. В заголовке правила мы используем _actor
для идентификации актера, что указывает на то, что переменная не будет использоваться и будет соответствовать любому значению.Действие должно соответствовать буквальному значению "view"
, а сообщение должно быть экземпляром модели Django social.Post
(синтаксис : TYPE_NAME
указывает на ограничение типа, а подключаемый модуль django-oso
делает Django модели, доступные в политике под их
).
У второго правила такая же голова, но мы требуем, чтобы актер был моделью social.User
. Это правило будет соответствовать только зарегистрированным пользователям (незарегистрированные пользователи имеют тип django :: contrib :: auth :: AnonymousUser
).Затем мы проверяем, является ли уровень доступа частным, и что сообщение создано субъектом, пытающимся получить к нему доступ. Это кодирует правило «актеры могут получить доступ к своим личным сообщениям».
Теперь давайте протестируем наше приложение. Создайте несколько личных сообщений и убедитесь, что вы их видите. Затем создайте нового пользователя через интерфейс администратора (http: // localhost: 8000 / admin / social / user /). Выйдите из системы и снова войдите с этим пользователем и убедитесь, что личные сообщения не отображаются!
Расширение вашей политики и правил авторизации с помощью Oso
Приведенная выше политика очень проста, но демонстрирует способность политик Oso напрямую взаимодействовать с объектами из вашего приложения.Язык политик, называемый Polar, - это декларативный язык программирования, разработанный для выразительного описания правил авторизации.
Поскольку мы стандартизировали наш интерфейс в логику авторизации с помощью функции authorize
, мы можем легко вносить изменения, чтобы контролировать, какие сообщения могут просматривать пользователи. Предположим, у нас появился новый тип пользователей - модератор. Они могут просматривать все сообщения, но другие пользователи могут просматривать только сообщения, одобренные модератором. Приведенная ниже политика реализует эту функцию:
# Модераторы могут просматривать любые сообщения.allow (user: social :: User, "view", _: social :: Post), если
user.is_moderator;
# Модераторы могут проводить модерацию любого сообщения.
allow (user: social :: User, "умеренный", _: social :: Post), если
user.is_moderator;
# Разрешить кому угодно просматривать любые общедоступные сообщения.
allow (_actor, "view", post: social :: Post), если
# NEW - Публичные сообщения должны быть одобрены модераторами.
post.approved и
post.access_level = social :: Post.ACCESS_PUBLIC;
# Разрешить пользователю просматривать свои личные сообщения.
allow (актер: social :: User, "view", post: social :: Post), если
Почта.access_level = social :: Post.ACCESS_PRIVATE и
post.created_by = актер;
Это изменение политики, а также несколько небольших изменений в наших моделях - все, что нам нужно, чтобы настроить наше приложение для поддержки модераторов.
В этом руководстве мы увидели, как создать приложение Django и использовать модели, представления и шаблоны для создания простого клона Twitter. Приложение позволяет пользователям создавать новые сообщения и просматривать свои личные сообщения и все другие общедоступные сообщения.
Затем мы использовали Oso для реализации контроля видимости для сообщений и показали, как политики Oso допускают расширение по мере роста возможностей приложения и правил авторизации.
Чтобы узнать больше о политиках Oso, ознакомьтесь с нашим кратким руководством. Посетите нашу документацию, чтобы получить более подробную информацию о библиотеке django-oso
, которую мы использовали в этом посте, или, если у вас есть какие-либо другие технические вопросы или отзывы, присоединяйтесь к нам в Slack или открывайте проблему.
Управление доступом: сравнение приложений с разрешениями Django
Есть много способов управлять разрешениями в проекте. Например, у нас могут быть разрешения на уровне модели, разрешения на уровне объекта, детализированные разрешения пользователя или на основе ролей.В любом случае нам не нужно писать что-либо из них с нуля, в экосистеме Django есть огромное количество приложений для обработки разрешений, которые помогут нам с этой задачей. В этом посте мы сравним, как работают некоторые популярные приложения для разрешений, чтобы вы знали, какое из них подходит для вашего проекта. Если вы хотите изучить немного больше, Django Packages имеет полную сетку разрешений, вам следует взглянуть.
1. Собственные разрешения Django
Как и следовало ожидать, у Django есть собственная система разрешений, которая очень хорошо работает во многих ситуациях, и это здорово, если конечные пользователи интенсивно используют интерфейс администратора Django.Это система разрешений на уровне модели, которая может применяться как к отдельным пользователям, так и к группе. Если у вас есть django.contrib.auth
в вашем INSTALLED_APPS
django автоматически создаст , добавит
, изменит,
и удалит типы разрешений
для каждой модели в вашей системе (или любой другой, которую вы добавите позже). Предоставление или отмена этих разрешений для пользователей ограничит действия, которые они могут предпринять при входе в систему с правами администратора. Вместо того, чтобы управлять пользователем за пользователем, вы также можете создать группу, добавить в нее пользователей и управлять разрешениями для всей группы.
Но это не ограничивается админом. Вы можете проверить права пользователей в своих собственных представлениях, используя метод has_perm
, предоставленный в пользовательской модели.
, если user.has_perm ('foo.add_bar'):
return HttpResponse («Вы имеете право добавлять контент!»)
еще:
return HttpResponse ("В разрешении на добавление отказано")
вы также можете проверить права пользователей в своих шаблонах, используя переменную perms
, которая автоматически добавляется в контекст шаблона:
{% if perms.app_label.can_do_something%}
Этот контент будет показан пользователям с разрешением can_do_something.
{% endif%}
Этот контент будет показан всем пользователям.
Вы также можете создать свои собственные разрешения для моделей:
class Content (models.Model):
owner = models.ForeignKey (Пользователь)
content = models.TextField ()
класс Мета:
разрешения = (
('view_content', 'Просмотр содержимого'),
)
Дополнительные сведения о создании новых разрешений, программном управлении разрешениями пользователей и работе с группами см. В официальной документации.
2. Django guardian
Django Guardian - это стороннее приложение, ориентированное на обработку разрешений на уровне объектов. В то время как собственные разрешения Django управляют доступом ко всем объектам в модели, с помощью Guardian мы можем контролировать доступ к конкретному экземпляру модели. Хорошо то, что он имеет интерфейс, аналогичный интерфейсу Django:
>>> from django.contrib.auth.models import User
>>> from contents.model import Content
>>> от опекуна.ярлыки import assign_perm
>>>
>>> writer = User.objects.create (username = 'The Writer')
>>> joe = User.objects.create (username = 'joe')
>>> content = Content.objects.create (
owner = writer, content = 'Это контент!')
>>> joe.has_perm ('view_content', контент)
Ложь
>>> assign_perm ('view_content', Джо, контент)
>>> joe.has_perm ('view_content', контент)
Правда
То же самое можно сделать с группами:
>>> из django.contrib.auth.models import Group
>>> group = Group.objects.create (name = 'reviewers')
>>> assign_perm ('view_content', группа, контент)
>>> joe.groups.add (группа)
>>> joe.has_perm ('view_content', контент)
Правда
Он также имеет несколько очень полезных методов, таких как get_perms
и get_objects_for_user
, декораторы для ваших представлений и тегов шаблонов.
Строительство за пределами
Ежемесячный информационный бюллетень Vinta Software для разработчиков и дизайнеров
Подписаться
3.Разрешения ролей Django
Разрешения ролей Django используют более высокоуровневый подход для управления доступом к представлениям и объектам. Вместо того, чтобы отдельно указывать, какой пользователь имеет доступ к какому объекту, мы определим ролей
с определенным набором разрешений по умолчанию.
из rolepermissions.roles import AbstractUserRole
класс Writer (AbstractUserRole):
available_permissions = {
'create_content': Верно,
view_content: Верно,
}
Рецензент класса (AbstractUserRole):
available_permissions = {
'create_content': ложь,
view_content: Верно,
}
Как только мы дадим пользователю роль, мы сможем проверять его разрешения, а также его роль.
>>> from rolepermissions.verifications import has_permission, has_role
>>> has_permission (Джо, 'view_content')
Ложь
>>> Reviewer.assign_role_to_user (Джо)
>>> has_permission (Джо, 'view_content')
Правда
>>> has_role (Джо, 'рецензент')
Правда
Он также позволяет определять разрешения на уровне объекта с помощью логики программирования:
из rolepermissions.permissions import register_object_checker
@register_object_checker ()
def publish_content (роль, пользователь, объект):
если объектвладелец == пользователь:
вернуть True
вернуть ложь
и проверьте:
>>> from rolepermissions.verifications import has_object_permission
>>> has_object_permission ('publish_content', автор, контент)
Вы также найдете вспомогательные функции, теги шаблонов, декораторы и миксины. Этот проект поддерживается Vinta, так что здесь бесстыдно подключайтесь 🙂
Обновление: Разрешения ролей Django теперь поддерживают назначение нескольких ролей для каждого пользователя.
4. Rules
Rules - очень интересное приложение, которое не использует какую-либо модель базы данных для управления разрешениями на уровне объекта. Все делается с помощью функций проверки, похожих на средства проверки объектов django-role-permissions, но более мощные. Начнем с создания предикатов:
@ rules.predicate
def is_content_writter (пользователь, объект):
вернуть obj.owner == user
@ rules.predicate
def is_admin_user (пользователь, объект):
вернуть user.is_admin
Затем мы связываем наши предикаты с правилом:
правил.add_perm ('содержимое.change_content', is_content_writter)
Мы даже можем использовать операторы для создания сложных правил, которые зависят от нескольких предикатов:
is_admin_writer = is_content_writter & is_admin_user
rules.add_perm ('содержимое.delete_content', is_admin_writer)
и, наконец, мы можем протестировать наши правила с объектами:
>>> joe.has_perm ('contents.delete_content', content)
Ложь
>>> writer.has_perm ('contents.delete_content', контент)
Правда
Rules также предоставляет декораторы и миксины для ваших представлений и тегов шаблонов.Еще одна крутая вещь - это то, что его можно использовать без Django.
Надеюсь, вы быстро ознакомились с некоторыми доступными приложениями разрешений Django и теперь можете выбрать то, которое лучше всего подходит для вашего приложения. Если вы знаете другие интересные приложения с другим подходом, мы будем рады услышать о них в комментариях!
Филипе Шименес
Старший разработчик Fullstack в Vinta Software.
django-rules Python 开发 小巧 但是 强大 的 应用 , 提供 对象 级别 的 权限 管理 , 不需要 使用 数据库 - Python 社区 | CTOLib 码 库
rules
- крошечное, но мощное приложение, предоставляющее Django разрешения на уровне объектов без использования базы данных. По своей сути это общая структура для построения систем на основе правил, аналогичных деревьям решений. Его также можно использовать как отдельную библиотеку в других контекстах и фреймворках.
Возможности
правил
позаботятся о вас. правил
это:
- Документировано , протестировано , надежно и простое в использовании .
- Универсальный . Украшайте вызываемые объекты для построения сложных графов предикатов. Предикаты могут быть вызываемыми любым типом - простые функции, лямбда-выражения, методы, вызываемые объекты классов, частичные функции, декорированные функции, что угодно.
- Хороший гражданин Джанго . Полная интеграция с представлениями Django, шаблонами и администратором для тестирования разрешений на уровне объектов.
- Эффективный и умный . Не нужно возиться с базой данных, чтобы выяснить, действительно ли Джон написал эту книгу.
- Простой . Погрузитесь в код. Вам понадобится 10 минут, чтобы понять, как это работает.
- Мощный . Правила
Содержание
Требования
правил
требует Python 2.6 / 3.3 или новее. При желании его можно интегрировать с Django, и в этом случае требуется Django 1.5 или новее.
Как установить
Использование pip:
Вручную:
$ git clone https://github.com/dfunckt/django-rules.git $ cd django-rules $ python setup.py установить
Выполнить тесты с:
Использование правил
rules
основано на идее, что вы поддерживаете dict-подобный объект, который сопоставляет строковые ключи, используемые в качестве идентификаторов того или иного вида, с вызываемыми объектами, называемыми предикатами .Этот dict-подобный объект на самом деле является экземпляром RuleSet
, а предикаты - экземплярами Predicate
.
Создание предикатов
Давайте на мгновение проигнорируем наборы правил и определим предикат. Самый простой способ - использовать декоратор @predicate
:
>>> @ rules.predicate >>> def is_book_author (пользователь, книга): ... вернуть book.author == пользователь ... >>> is_book_author <Предикат: объект is_book_author в 0x10eeaa490>
Этот предикат вернет Истина
, если автор книги является данным пользователем, Ложь
в противном случае.
Предикаты могут быть созданы из любого вызываемого объекта, который принимает все от нуля до двух позиционных аргументов:
-
fn (объект, цель)
-
fn (obj)
-
fn ()
Это их общая форма. Если смотреть с точки зрения авторизации в Django, эквивалентные подписи:
-
fn (пользователь, объект)
-
fn (пользователь)
-
fn ()
Предикаты могут делать практически все что угодно с заданными аргументами, но всегда должны возвращать Истина
, если условие, которое они проверяют, истинно, Ложь
в противном случае.Правила
поставляется с несколькими предопределенными предикатами, о которых вы можете прочитать позже в Справочнике по API, которые в основном полезны при работе с авторизацией в Django.
Настройка правил
Давайте представим, что мы хотим разрешить авторам редактировать или удалять свои книги, но не книги, написанные другими авторами. Итак, по сути, то, что определяет, может ли автор редактировать или может удалить данную книгу, - это , являются ли они ее автором .
В правилах
такие требования смоделированы как правила . Правило - это отображение уникального идентификатора (например, «можно редактировать») с предикатом. Правила сгруппированы в набор правил . правил
имеет два предопределенных набора правил:
- Набор правил по умолчанию, в котором хранятся общие правила.
- Другой набор правил, хранящих правила, которые служат разрешениями в контексте Django.
Итак, давайте определим нашу первую пару правил, добавив их в общий набор правил.Мы можем использовать предикат is_book_author
, который мы определили ранее:
>>> rules.add_rule ('can_edit_book', is_book_author) >>> rules.add_rule ('can_delete_book', is_book_author)
Предполагая, что у нас есть данные, теперь мы можем протестировать наши правила:
>>> от пользователя django.contrib.auth.models import >>> из books.models import Book >>> guidetodjango = Book.objects.get (isbn = '978-1-4302-1936-1') >>> guidetodjango.автор <Пользователь: adrian> >>> Адриан = User.objects.get (имя пользователя = 'Адриан') >>> rules.test_rule ('can_edit_book', Адриан, Guidetodjango) Правда >>> rules.test_rule ('can_delete_book', Адриан, Guidetodjango) Правда
Красиво ... но не круто.
Комбинирование предикатов
Предикаты сами по себе не так полезны - не более полезны, чем любая другая функция. Однако предикаты можно комбинировать с помощью бинарных операторов для создания более сложных.Предикаты поддерживают следующие операторы:
-
P1 & P2
: возвращает новый предикат, который возвращаетTrue
, если оба предиката возвращаютTrue
, в противном случаеFalse
. Если P1 возвращаетFalse
, P2 не будет оцениваться. -
P1 | P2
: возвращает новый предикат, который возвращаетTrue
, если любой из предикатов возвращаетTrue
, в противном случаеFalse
. Если P1 возвращаетИстинно
, P2 не будет оцениваться.P2 : возвращает новый предикат, который возвращаетTrue
, если один из предикатов возвращаетTrue
, а другой возвращаетFalse
, в противном случаеFalse
. -
~ P
: возвращает новый предикат, который возвращает отрицательный результат исходного предиката.
Предположим, что для разрешения пользователю редактировать данную книгу требовалось, чтобы он был либо автором книги, либо членом группы «редакторы». Разрешение пользователям удалять книгу по-прежнему должно зависеть от того, является ли пользователь автором книги.
С правилами
это легко реализовать. Нам нужно будет определить другой предикат, который вернет True
, если данный пользователь является членом группы «редакторы», False
в противном случае. Пригодится встроенный завод is_group_member
:
>>> is_editor = rules.is_group_member ('редакторы') >>> is_editor <Предикат: is_group_member: объект редакторов в 0x10eee1350>
Мы могли бы объединить его с предикатом is_book_author
, чтобы создать новый, который проверяет любое условие:
>>> is_book_author_or_editor = is_book_author | is_editor >>> is_book_author_or_editor <Предикат: (is_book_author | is_group_member: editors) объект в 0x10eee1390>
Теперь мы можем обновить наше правило can_edit_book
:
>>> правила.add_rule ('can_edit_book', is_book_author_or_editor) Отслеживание (последний вызов последний): ... KeyError: правило с именем can_edit_book уже существует >>> rules.remove_rule ('can_edit_book') >>> rules.add_rule ('can_edit_book', is_book_author_or_editor) >>> rules.test_rule ('can_edit_book', Адриан, Guidetodjango) Правда >>> rules.test_rule ('can_delete_book', Адриан, Guidetodjango) Правда
Посмотрим, что будет с другим пользователем:
>>> martin = Пользователь.objects.get (имя пользователя = 'martin') >>> список (martin.groups.values_list ('name', flat = True)) ['редакторы'] >>> rules.test_rule ('can_edit_book', martin, guidetodjango) Правда >>> rules.test_rule ('can_delete_book', martin, guidetodjango) Ложь
Превосходно.
До сих пор мы использовали только базовую общую структуру для определения и тестирования правил. Этот уровень совершенно не специфичен для Django; его можно использовать в любом контексте. На самом деле нет импорта чего-либо, связанного с Django, во всем приложении (кроме правил .templatetags
модуль). правила
, однако могут быть тесно интегрированы с Django для обеспечения авторизации.
Использование правил с Django
правил
может предоставлять разрешения на уровне объекта в Django. Он поставляется с бэкэндом авторизации и парой тегов шаблонов для использования в ваших шаблонах.
Разрешения
В правилах
разрешения представляют собой особый тип правил. Вы по-прежнему определяете правила, создавая и комбинируя предикаты.Однако эти правила должны быть добавлены к набору правил для конкретных разрешений, который поставляется с правилами
, чтобы они могли быть выбраны серверной частью авторизации правил
.
Создание разрешений
Соглашение об именовании разрешений в Django - app_label.action_object
, и нам нравится его придерживаться. Добавим правила для прав доступа books.change_book
и books.delete_book
:
>>> правила.add_perm ('books.change_book', is_book_author | is_editor) >>> rules.add_perm ('books.delete_book', is_book_author)
Видите разницу в API? add_perm
добавляет к набору правил для конкретных разрешений, тогда как add_rule
добавляет к общему набору правил по умолчанию. Однако важно знать, что эти два набора правил являются отдельными, а это означает, что добавление правила в один не делает его доступным для другого.
Проверка разрешения
Давайте продолжим и проверим, есть ли у adrian
разрешение на изменение guidetodjango
book:
>>> адриан.has_perm ('books.change_book', guidetodjango) Ложь
Когда вы вызываете метод User.has_perm
, Django спрашивает каждый бэкэнд в настройках .AUTHENTICATION_BACKENDS
, имеет ли пользователь данное разрешение для объекта. При запросе прав доступа к объекту бэкэнд аутентификации по умолчанию Django всегда возвращает False
. Правила
поставляется с серверной частью авторизации, которая может предоставлять разрешения на уровне объекта, просматривая набор правил для конкретных разрешений.
Добавим правил бэкэнд авторизации
в настройки:
AUTHENTICATION_BACKENDS = ( 'rules.permissions.ObjectPermissionBackend', 'django.contrib.auth.backends.ModelBackend', )
Теперь повторная проверка дает adrian
необходимые разрешения:
>>> adrian.has_perm ('books.change_book', guidetodjango) Правда >>> adrian.has_perm ('books.delete_book', guidetodjango) Правда >>> martin.has_perm ('books.change_book ', guidetodjango) Правда >>> martin.has_perm ('books.delete_book', guidetodjango) Ложь
Правила и разрешения в представлениях
rules
поставляется с набором декораторов представлений, которые помогут вам обеспечить авторизацию в ваших представлениях.
Использование декоратора представлений на основе функций
Для представлений на основе функций вы можете использовать декоратор permission_required
:
из django.shortcuts import get_object_or_404 из правил.contrib.views import permission_required from posts.models import Post def get_post_by_pk (запрос, post_id): return get_object_or_404 (Сообщение, pk = post_id) @permission_required ('posts.change_post', fn = get_post_by_pk) def post_update (запрос, post_id): # ...
Использование простое, но в приведенном выше примере есть одна вещь, которая выделяется, и это функция get_post_by_pk
. Эта функция, учитывая текущий запрос и все аргументы, переданные в представление, отвечает за выборку и возврат объекта для проверки разрешений - i.е. экземпляр Post
с PK, равным заданному post_id
в примере. Этот конкретный вариант использования довольно распространен, поэтому, чтобы не печатать, правила
поставляются с общей вспомогательной функцией, которую вы можете использовать для декларативного выполнения. Пример ниже эквивалентен приведенному выше:
из rules.contrib.views import permission_required, objectgetter from posts.models import Post @permission_required ('posts.change_post', fn = objectgetter (Post, 'post_id')) def post_update (запрос, post_id): #...
Дополнительные сведения о декораторе и вспомогательной функции см. В модуле rules.contrib.views
.
Использование миксина представлений на основе классов
Django 1.9 представил новый набор миксинов доступа, которые вы можете использовать в представлениях на основе классов для принудительной авторизации. rules
расширяет эту структуру, чтобы предоставить миксин для разрешений на уровне объекта, PermissionRequiredMixin
. Обратите внимание, что правила
без проблем вернутся к импорту собственной копии модуля миксинов доступа Django для версий Django до 1.9.
В следующем примере выполняется автоматическая проверка разрешения для экземпляра, возвращаемого методом представления get_object
:
из django.views.generic.edit импортировать UpdateView из rules.contrib.views import PermissionRequiredMixin from posts.models import Post класс PostUpdate (PermissionRequiredMixin, UpdateView): model = Опубликовать permission_required = 'posts.change_post'
Вы можете настроить объект, переопределив get_object
или get_permission_object
.
Для получения дополнительной информации см. Документацию Django и модуль rules.contrib.views
.
Правила и разрешения в шаблонах
rules
поставляется с двумя тегами шаблонов, которые позволяют вам проверять правила и разрешения в шаблонах.
Добавьте правил
к своим INSTALLED_APPS
:
INSTALLED_APPS = ( # ... 'правила', )
Затем в вашем шаблоне:
{% load rules%} Книги: {% has_perm '.change_book 'автор книги как can_edit_book%} {% if can_edit_book%} ... {% endif%} Пользователь {% test_rule 'has_super_feature' как has_super_feature%} {% if has_super_feature%} ... {% endif%}
Правила и разрешения в Админке
Если вы настроили правил
для использования с разрешениями в Django, вы почти настроены также на использование правил
для авторизации любых действий добавления / изменения / удаления в админке. Администратор запрашивает четыре различных разрешений, в зависимости от действия:
-
.add_ <имя модели> -
<метка_приложения> .change_ <имя модели>
-
<метка_приложения> .delete_ <имя модели>
-
Первые три очевидны. Четвертый - это необходимое разрешение для отображения приложения на «панели управления» администратора. Вот некоторые правила для нашего воображаемого приложения книг
в качестве примера:
>>> rules.add_perm ('книги', rules.всегда позволяют) >>> rules.add_perm ('books.add_book', is_staff) >>> rules.add_perm ('books.change_book', is_staff) >>> rules.add_perm ('books.delete_book', is_staff)
Django Admin не поддерживает объектные разрешения в том смысле, что он никогда не будет запрашивать разрешение на выполнение действия над объектом , только если пользователю разрешено действовать на ( любых ) экземплярах модели.
Если вы хотите сообщить Django, есть ли у пользователя разрешения на определенный объект, вам придется переопределить следующие методы модели ModelAdmin
:
-
has_change_permission (пользователь, obj = None)
-
has_delete_permission (пользователь, obj = None)
Примечание: Также есть has_add_permission (user)
, но здесь это не имеет значения.
rules
поставляется с настраиваемым подклассом ModelAdmin
, rules.contrib.admin.ObjectPermissionsModelAdmin
, который переопределяет эти методы для передачи отредактированного экземпляра модели на серверы авторизации, тем самым разрешая разрешения для каждого объекта в Admin:
# books / admin.py от администратора импорта django.contrib из rules.contrib.admin импортировать ObjectPermissionsModelAdmin из .models import Book класс BookAdmin (ObjectPermissionsModelAdmin): проходить админ.site.register (Книга, BookAdmin)
Теперь это позволяет вам указывать разрешения следующим образом:
>>> rules.add_perm ('книги', rules.always_allow) >>> rules.add_perm ('books.add_book', has_author_profile) >>> rules.add_perm ('books.change_book', is_book_author_or_editor) >>> rules.add_perm ('books.delete_book', is_book_author)
Расширенные функции
Пользовательские наборы правил
Вы можете создать столько наборов правил, сколько вам нужно:
>>> особенности = правила.RuleSet ()
И манипулируйте ими, добавляя, удаляя, запрашивая и проверяя правила:
>>> features.rule_exists ('has_super_feature') Ложь >>> is_special_user = rules.is_group_member ('специальный') >>> features.add_rule ('has_super_feature', is_special_user) >>> 'has_super_feature' в функциях Правда >>> особенности ['has_super_feature'] <Предикат: is_group_member: специальный объект в 0x10eeaa500> >>> features.test_rule ('has_super_feature', Адриан) Правда >>> особенности.remove_rule ('has_super_feature')
Обратите внимание, однако, что пользовательские наборы правил недоступны в шаблонах Django - вам необходимо обеспечить интеграцию самостоятельно.
Контекст вызова
Новый контекст создается в результате вызова Predicate.test ()
и действителен только на время вызова. Контекст - это простой dict
, который вы можете использовать для хранения произвольных данных (например, кэширование вычисленных значений, установка флагов и т. Д.), который может использоваться предикатами позже в цепочке. Внутри функции предиката его можно использовать так:
>>> @predicate ... def mypred (a, b): ... значение = вычислить_дорогое_значение (а) ... mypred.context ['значение'] = значение ... вернуть True
Другие предикаты могут позже использовать сохраненные значения:
>>> @predicate ... def myotherpred (a, b): ... значение = myotherpred.context.get ('значение') ... если значение не равно None: ... вернуть do_something_with_value (значение) ... еще: ... вернуть do_something_without_value ()
Predicate.context
предоставляет единственный атрибут args
, который содержит аргументы, заданные для test ()
в начале вызова.
Переплет "сам"
В теле функции предиката вы можете ссылаться на сам экземпляр предиката по его имени, например. is_book_author
. Передача bind = True
в качестве аргумента ключевого слова декоратору предиката
позволит вам ссылаться на предикат с self
, что более удобно.Связывание и
- это просто синтаксический сахар. Фактически, следующие два эквивалента:
>>> @predicate ... def is_book_author (пользователь, книга): ... если is_book_author.context.args: ... вернуть пользователя == book.author ... вернуть False >>> @predicate (bind = True) ... def is_book_author (я, пользователь, книга): ... если self.context.args: ... вернуть пользователя == book.author ... вернуть False
Пропуск предикатов
Вы можете пропустить оценку, вернув Нет
из вашего предиката:
>>> @predicate (bind = True) ... def is_book_author (я, пользователь, книга): ... если len (self.context.args)> 1: ... вернуть пользователя == book.author ... еще: ... return Нет
Возвращение Нет
означает, что предикат не нужно оценивать, таким образом, результат предиката остается неизменным до этого момента.
Примечание: Это новое в версии 1.1.0. В более старых версиях можно было пропустить предикаты, вызвав метод предиката skip ()
, но это устарело, и поддержка будет полностью удалена в будущей версии.
Лучшие практики
Прежде чем вы сможете проверить правила, эти правила должны быть зарегистрированы в наборе правил, и для этого необходимо импортировать модули, содержащие ваши определения правил.
Для сложных проектов с несколькими предикатами и правилами может оказаться непрактичным определять все ваши предикаты и правила внутри одного модуля. Возможно, лучше всего разделить их между любыми подкомпонентами вашего проекта. В контексте Django эти субкомпоненты могут быть приложениями для вашего проекта.
С другой стороны, поскольку импорт предикатов из любого места для определения правил может привести к циклическому импорту и разбитым сердцам, лучше всего дополнительно разделить предикаты и правила в разных модулях.
При использовании Django 1.7 и новее, правила
можно дополнительно настроить для автоматического обнаружения модулей rules.py
в ваших приложениях и импорта их при запуске. Чтобы правил
сделали это, просто отредактируйте настройку INSTALLED_APPS
:
INSTALLED_APPS = ( # заменить 'rules' на: 'правила.apps.AutodiscoverRulesConfig ', )
Примечание: На Python 2 вы также должны добавить следующее в начало файла rules.py
, иначе вы получите ошибки импорта при попытке импортировать django-rules
:
из __future__ import absolute_import
Ссылка API
Все доступно из корневого модуля rules
.
Правила класса
. Предикат
Вы создаете экземпляров предиката
, передавая вызываемый объект:
>>> def is_book_author (пользователь, книга): ... вернуть book.author == пользователь ... >>> pred = Предикат (is_book_author) >>> пред <Предикат: объект is_book_author в 0x10eeaa490>
При желании вы можете указать другое имя для предиката, который будет использоваться при его проверке:
>>> pred = Predicate (is_book_author, name = 'другое_имя') >>> пред <Предикат: объект another_name в 0x10eeaa490>
Кроме того, вы можете дополнительно указать bind = True
, чтобы иметь доступ к экземпляру предиката с self
:
>>> def is_book_author (я, пользователь, книга): ... если self.context.args: ... вернуть пользователя == book.author ... вернуть False ... >>> pred = Predicate (is_book_author, bind = True) >>> пред <Предикат: объект is_book_author в 0x10eeaa490>
Методы экземпляра
-
test (obj = None, target = None)
- Возвращает результат вызова переданного вызываемого объекта с нулем, одним или двумя позиционными аргументами, в зависимости от того, сколько он принимает.
Правила класса
.RuleSet
RuleSet
расширяет встроенный в Python тип dict. Следовательно, вы можете создавать и использовать набор правил любым способом, которым вы пользуетесь dict.
Методы экземпляра
-
add_rule (имя, предикат)
- Добавляет предикат в набор правил, присваивая его заданному имени правила. Поднимает
KeyError
, если другое правило с таким именем уже существует. -
remove_rule (имя)
- Удалите правило с заданным именем.Поднимает
KeyError
, если правило с таким именем не существует. -
rule_exists (имя)
- Возврат
Истинно
, если существует правило с данным именем,Неверно
иначе. -
test_rule (name, obj = None, target = None)
- Возвращает результат вызова
predicate.test (obj, target)
где ПредикатЛожь
, если правило с данным именем не существует.
Декораторы
-
@predicate
Декоратор, который создает предикат из любого вызываемого объекта:
>>> @predicate ... def is_book_author (пользователь, книга): ... вернуть book.author == пользователь ... >>> is_book_author <Предикат: объект is_book_author в 0x10eeaa490>
Настройка имени предиката:
>>> @predicate (имя = 'другое_имя') ... def is_book_author (пользователь, книга): ... вернуть book.author == пользователь ... >>> is_book_author <Предикат: объект another_name в 0x10eeaa490>
Переплет
сам
:>>> @predicate (bind = True) ... def is_book_author (я, пользователь, книга): ... если 'user_has_special_flag' в self.context: ... вернуть self.context ['user_has_special_flag'] ... вернуть book.author == пользователь
Предопределенные предикаты
-
always_allow ()
,always_true ()
- Всегда возвращается
Истинно
. -
always_deny ()
,always_false ()
- Всегда возвращается
Ложь
. -
is_authenticated (пользователь)
- Возвращает результат вызова
user.is_authenticated ()
. ВозвратЛожь
, если у данного пользователя нетis_authenticated
метод. -
is_superuser (пользователь)
- Возвращает результат вызова
пользователь.Кирилл
. ВозвратЛожь
, если у данного пользователя нетis_superuser
свойство. -
is_staff (пользователь)
- Возвращает результат вызова
user.is_staff
. ВозвратЛожь
, если у данного пользователя нетis_staff
недвижимость. -
is_active (пользователь)
- Возвращает результат вызова
user.is_active
. ВозвратЛожь
, если у данного пользователя нетis_active
свойство. -
is_group_member (* группы)
- Фабрика, которая создает новый предикат, возвращающий
Истинно
, если данный пользователь является членом всех данных групп,Неверно
иначе.
Ярлыки
Управление общим набором правил
-
add_rule (имя, предикат)
- Добавляет правило в общий набор правил. Видеть
RuleSet.add_rule
. -
remove_rule (имя)
- Удалите правило из общего набора правил. Видеть
RuleSet.remove_rule
. -
rule_exists (имя)
- Возвращает, существует ли правило в общем наборе правил. Видеть
RuleSet.rule_exists
. -
test_rule (name, obj = None, target = None)
- Проверяет правило с заданным именем. Видеть
RuleSet.test_rule
.
Управление набором правил разрешений
-
add_perm (имя, предикат)
- Добавляет правило в набор правил разрешений.Видеть
RuleSet.add_rule
. -
remove_perm (имя)
- Удалите правило из набора правил разрешений. Видеть
RuleSet.remove_rule
. -
perm_exists (имя)
- Возвращает, существует ли правило в наборе правил разрешений. Видеть
RuleSet.rule_exists
. -
has_perm (name, user = None, obj = None)
- Проверяет правило с заданным именем.Видеть
RuleSet.test_rule
.
История изменений
-
v1.1.1
- 2015.12.07 - Улучшенная обработка пропущенных предикатов
-
v1.1.0
- 2015/12/05 - Исправлена регрессия, которая не приводила к сокращению логических выражений
- Добавлена поддержка Django 1.9 и Python 3.5
- Добавлена поддержка пропуска предикатов путем простого возврата
Нет
.Предыдущий способ пропуска предикатов путем повышенияSkipPredicate
устарел и не будет поддерживаться в будущих выпусках.
-
v1.0.0
- 06.10.2015 - Первоначальный стабильный общедоступный выпуск
- Прекращена поддержка Python 3.2
- Добавлен набор тестов Django
- Добавлен декоратор представлений на основе функций
- Добавлен миксин представлений на основе классов
-
v0.4
- 16.02.2015 - Добавлена поддержка создания предикатов из частичных функций
- Добавлена поддержка создания предикатов из методов экземпляра
- Добавлен контекст вызова предиката
- Добавлена поддержка автоматической передачи
self
в предикат . - Добавлена поддержка отбрасывания результата предиката
-
v0.3
- 15.10.2014 - Добавлена совместимость с PyPy и PyPy 3
- Добавлены
предикатов always_true ()
иalways_false ()
- Добавлена интеграция с Tox
- Исправления ошибок
-
v0.2
- 06.06.2014 - Добавлена совместимость с Python 3.4
- Улучшенная интеграция администратора
-
v0.1
- 2014/03/07
Лицензия
django-rules
распространяется по лицензии MIT.
Авторские права (c) 2014 Акис Кесоглу
Настоящим предоставляется бесплатное разрешение любому лицу, получающему копию этого программного обеспечения и связанных файлов документации («Программное обеспечение»), на использование Программного обеспечения без ограничений, включая, помимо прочего, права на использование, копирование, изменение, объединять, публиковать, распространять, сублицензировать и / или продавать копии Программного обеспечения и разрешать лицам, которым предоставляется Программное обеспечение, делать это при соблюдении следующих условий:
Приведенное выше уведомление об авторских правах и это уведомление о разрешении должны быть включены во все копии или существенные части Программного обеспечения.
ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ КОММЕРЧЕСКОЙ ЦЕННОСТИ, ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ И НЕЗАЩИТЫ ОТ ПРАВ. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ АВТОРЫ ИЛИ ВЛАДЕЛЬЦЫ АВТОРСКИХ ПРАВ НЕ НЕСЕТ ОТВЕТСТВЕННОСТИ ЗА ЛЮБЫЕ ПРЕТЕНЗИИ, УБЫТКИ ИЛИ ДРУГИЕ ОТВЕТСТВЕННОСТЬ, ВЫЯВЛЯЮЩИЕСЯ В РЕЗУЛЬТАТЕ ДОГОВОРА, ПРАВИЛА ИЛИ ИНЫМ ОБРАЗОМ, ВОЗНИКАЮЩИМ, ВНУТРИ ИЛИ В СВЯЗИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ИЛИ ДРУГИМИ ДЕЛАМИ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ.
Что нужно знать для управления пользователями в Django Admin - Real Python
Управление пользователями в админке Django - непростая задача.Если вы установите слишком много разрешений, вы можете помешать повседневным операциям. Если вы разрешите предоставление разрешений свободно и без присмотра, то вы подвергнете свою систему риску.
Django предоставляет хорошую структуру аутентификации с тесной интеграцией с администратором Django. По умолчанию администратор Django не накладывает особых ограничений на администратора пользователя. Это может привести к опасным сценариям, которые могут поставить под угрозу вашу систему.
Знаете ли вы, что штатные пользователи, которые управляют другими пользователями в админке, могут редактировать свои собственные разрешения? Знаете ли вы, что они также могут стать суперпользователями? В админке Django нет ничего, что могло бы этому помешать, так что решать вам!
Разрешения модели
С разрешениями сложно.Если вы не установите разрешения, ваша система подвергнется риску злоумышленников, утечки данных и человеческих ошибок. Если вы злоупотребляете разрешениями или используете их слишком часто, вы рискуете помешать повседневным операциям.
Django имеет встроенную систему аутентификации. Система аутентификации включает пользователей, группы и разрешения.
При создании модели Django автоматически создает четыре разрешения по умолчанию для следующих действий:
-
добавить
: Пользователи с этим разрешением могут добавить экземпляр модели. -
удалить
: Пользователи с этим разрешением могут удалить экземпляр модели. -
изменить
: Пользователи с этим разрешением могут обновлять экземпляр модели. -
просмотр
: Пользователи с этим разрешением могут просматривать экземпляры этой модели. Это разрешение было долгожданным, и, наконец, оно было добавлено в Django 2.1.
Имена разрешений соответствуют очень конкретному соглашению об именах:
.
Давайте разберемся:
-
User
импортирована из приложенияauth
(django.contrib.auth
). -
<действие>
- одно из действий выше (добавить
,удалить
,изменить
илипросмотреть
). -
<имя модели>
- название модели, написанное строчными буквами.
Знание этого соглашения об именах поможет вам легче управлять разрешениями. Например, имя разрешения на смену пользователя - auth.change_user
.
Как проверить разрешения
Разрешения модели предоставляются пользователям или группам. Чтобы проверить, есть ли у пользователя определенное разрешение, вы можете сделать следующее:
>>> >>> from django.contrib.auth.models import User
>>> u = User.objects.create_user (username = 'haki')
>>> u.has_perm ('auth.change_user')
Ложь
Стоит отметить, что .has_perm ()
всегда будет возвращать Истинный
для активного суперпользователя, даже если разрешение на самом деле не существует:
>>> from django.contrib.auth.models import User
>>> superuser = User.objects.create_superuser (
... username = 'суперхаки',
... email='[email protected] ',
... пароль = 'секрет',
)
>>> superuser.has_perm ('не существует')
Правда
Как видите, когда вы проверяете разрешения для суперпользователя, на самом деле разрешения не проверяются.
Как применить разрешения
МоделиDjango сами по себе не требуют разрешений. Единственное место, где разрешено использовать по умолчанию, - это Django Admin.
Причина, по которой модели не применяют разрешения, заключается в том, что обычно модель не знает о том, что пользователь выполняет действие. В приложениях Django пользователь обычно получается из запроса. Вот почему в большинстве случаев разрешения применяются на уровне представления.
Например, чтобы запретить пользователю без разрешений просмотра на модели Пользователь
получить доступ к представлению, которое показывает информацию о пользователе, выполните следующие действия:
из django.core.exceptions импорт PermissionDenied
def users_list_view (запрос):
если не request.user.has_perm ('auth.view_user'):
поднять PermissionDenied ()
Если пользователь, выполняющий запрос, вошел в систему и прошел аутентификацию, то request.user
будет содержать экземпляр User
. Если пользователь не вошел в систему, то request.user
будет экземпляром AnonymousUser
. Это специальный объект, используемый Django для обозначения неаутентифицированного пользователя.Использование has_perm
на AnonymousUser
всегда будет возвращать False
.
Если пользователь, выполняющий запрос, не имеет разрешения view_user
, вы вызываете исключение PermissionDenied
, и клиенту возвращается ответ со статусом 403
.
Чтобы упростить принудительное применение разрешений в представлениях, Django предоставляет декоратор ярлыков под названием permission_required
, который делает то же самое:
из django.contrib.auth.decorators import permission_required
@permission_required ('auth.view_user')
def users_list_view (запрос):
проходить
Чтобы применить разрешения в шаблонах, вы можете получить доступ к текущим разрешениям пользователя с помощью специальной переменной шаблона, которая называется perms
. Например, если вы хотите показать кнопку удаления только пользователям с разрешением на удаление, выполните следующие действия:
{% if perms.auth.delete_user%}
{% endif%}
Некоторые популярные сторонние приложения, такие как Django rest framework, также обеспечивают полезную интеграцию с разрешениями модели Django.
Разрешения администратора и модели Django
Администратор Django имеет очень тесную интеграцию со встроенной системой аутентификации и, в частности, с разрешениями модели. По умолчанию администратор Django применяет разрешения модели:
- Если у пользователя нет разрешений на модель, он не сможет увидеть ее или получить к ней доступ в админке.
- Если у пользователя есть разрешения на просмотр и изменение модели, он сможет просматривать и обновлять экземпляры, но не сможет добавлять новые экземпляры или удалять существующие.
При наличии соответствующих разрешений администраторы с меньшей вероятностью совершат ошибки, а злоумышленникам будет труднее причинить вред.
Реализация пользовательских бизнес-ролей в Django Admin
Одно из самых уязвимых мест в каждом приложении - это система аутентификации. В приложениях Django это модель User
. Итак, чтобы лучше защитить ваше приложение, вы собираетесь начать с модели User
.
Во-первых, вам нужно взять под контроль страницу администратора модели User
.В Django уже есть очень хорошая админка для управления пользователями. Чтобы воспользоваться преимуществами этой замечательной работы, вы собираетесь расширить встроенную модель администратора User
.
: пользовательский администратор
Чтобы предоставить настраиваемого администратора для модели User
, вам необходимо отменить регистрацию существующего администратора модели, предоставленного Django, и зарегистрировать одного из своих:
от администратора импорта django.contrib
из django.contrib.auth.models импортировать пользователя
из django.contrib.auth.admin импорт UserAdmin
# Отменить регистрацию предоставленного администратора модели
admin.site.unregister (Пользователь)
# Зарегистрируйте собственного администратора модели на основе UserAdmin по умолчанию
@ admin.register (Пользователь)
класс CustomUserAdmin (UserAdmin):
проходить
Ваш CustomUserAdmin
расширяет Django's UserAdmin
. Вы сделали это, чтобы воспользоваться всей работой, уже проделанной разработчиками Django.
На этом этапе, если вы войдете в систему администратора Django по адресу http: // 127.0.0.1: 8000 / admin / auth / user
, вы должны увидеть пользователя admin без изменений:
Расширяя UserAdmin
, вы можете использовать все встроенные функции, предоставляемые администратором Django.
Запретить обновление полей
Автоматические формы администратора - главный кандидат на ужасные ошибки. Штатный пользователь может легко обновить экземпляр модели через администратора так, как приложение не ожидает. В большинстве случаев пользователь даже не замечает, что что-то не так. Такие ошибки обычно очень сложно отследить и исправить.
Чтобы предотвратить такие ошибки, вы можете запретить администраторам изменять определенные поля в модели.
Если вы хотите запретить любому пользователю, включая суперпользователей, обновлять поле, вы можете пометить поле как доступное только для чтения. Например, поле date_joined
устанавливается при регистрации пользователя. Эта информация никогда не должна изменяться ни одним пользователем, поэтому вы помечаете ее как доступную только для чтения:
от администратора импорта django.contrib
из django.contrib.auth.models импортировать пользователя
из джанго.contrib.auth.admin импорт UserAdmin
@ admin.register (Пользователь)
класс CustomUserAdmin (UserAdmin):
readonly_fields = [
'date_joined',
]
Когда поле добавляется в readonly_fields
, его нельзя будет редактировать в форме изменения по умолчанию администратора. Когда поле помечено как только для чтения, Django отобразит элемент ввода как отключенный.
Но что, если вы хотите запретить только некоторым пользователям обновлять поле?
Условно запретить обновление полей
Иногда бывает полезно обновить поля прямо в админке.Но вы не хотите, чтобы это делал какой-либо пользователь: вы хотите, чтобы это могли делать только суперпользователи.
Допустим, вы хотите запретить пользователям, не являющимся суперпользователями, изменять имя пользователя. Для этого вам нужно изменить форму изменения, созданную Django, и отключить поле имени пользователя на основе текущего пользователя:
от администратора импорта django.contrib
из django.contrib.auth.models импортировать пользователя
из django.contrib.auth.admin импортировать UserAdmin
@ admin.register (Пользователь)
класс CustomUserAdmin (UserAdmin):
def get_form (self, request, obj = None, ** kwargs):
форма = супер ().get_form (запрос, объект, ** kwargs)
is_superuser = request.user.is_superuser
если не is_superuser:
form.base_fields ['имя пользователя']. disabled = True
форма возврата
Давайте разберемся:
- Чтобы внести изменения в форму, вы переопределяете
get_form ()
. Эта функция используется Django для создания формы изменения по умолчанию для модели. - Чтобы условно отключить поле, вы сначала получаете форму по умолчанию, сгенерированную Django, а затем, если пользователь не является суперпользователем, отключите поле имени пользователя.
Теперь, когда не суперпользователь пытается редактировать пользователя, поле имени пользователя будет отключено. Любая попытка изменить имя пользователя через Django Admin потерпит неудачу. Когда суперпользователь пытается отредактировать пользователя, поле имени пользователя будет редактируемым и будет вести себя так, как ожидалось.
Запретить пользователям, не являющимся суперпользователями, предоставлять права суперпользователя
Superuser - это очень сильное разрешение, которое нельзя давать легкомысленно. Однако любой пользователь с разрешением на изменение модели Пользователь
может сделать любого пользователя суперпользователем, включая себя.Это противоречит цели системы разрешений, поэтому вы хотите закрыть эту дыру.
На основе предыдущего примера, чтобы запретить пользователям, не являющимся суперпользователями, становиться суперпользователями, вы добавляете следующее ограничение:
из набора импорта Set
от администратора импорта django.contrib
из django.contrib.auth.models импортировать пользователя
из django.contrib.auth.admin импортировать UserAdmin
@ admin.register (Пользователь)
класс CustomUserAdmin (UserAdmin):
def get_form (self, request, obj = None, ** kwargs):
форма = супер ().get_form (запрос, объект, ** kwargs)
is_superuser = request.user.is_superuser
disabled_fields = set () # тип: Set [str]
если не is_superuser:
disabled_fields | = {
'имя пользователя',
'is_superuser',
}
для f в disabled_fields:
если f в form.base_fields:
form.base_fields [f] .disabled = Истина
форма возврата
В дополнение к предыдущему примеру вы внесли следующие дополнения:
Вы инициализировали пустой набор
disabled_fields
, который будет содержать поля для отключения.Набор| =
используется для выполнения обновленияИЛИ
на месте. Дополнительные сведения о наборах см. В разделе «Наборы в Python».Затем, если пользователь является суперпользователем, вы добавляете в набор два поля (
имя пользователя
из предыдущего примера иis_superuser
). Они не позволят пользователям, не являющимся суперпользователями, стать суперпользователями.Наконец, вы перебираете поля в наборе, помечаете их все как отключенные и возвращаете форму.
Двухэтапная форма администратора пользователя Django
Когда вы создаете нового пользователя в админке Django, вы проходите через двухэтапную форму. В первой форме вы вводите имя пользователя и пароль. Во второй форме вы обновляете остальные поля.
Этот двухэтапный процесс уникален для модели User
. Чтобы приспособиться к этому уникальному процессу, вы должны убедиться, что поле существует, прежде чем пытаться отключить его.В противном случае вы можете получить KeyError
. В этом нет необходимости, если вы настраиваете администраторов других моделей. Для получения дополнительной информации о KeyError
ознакомьтесь с исключениями Python KeyError и способами их обработки.
Предоставлять разрешения только с использованием групп
Способ управления разрешениями очень специфичен для каждой команды, продукта и компании. Я обнаружил, что управлять разрешениями в группах проще. В своих проектах я создаю группы поддержки, редакторов контента, аналитиков и так далее.Я обнаружил, что управление разрешениями на уровне пользователя может быть настоящей проблемой. Когда добавляются новые модели или меняются бизнес-требования, обновлять каждого отдельного пользователя утомительно.
Чтобы управлять разрешениями только с помощью групп, необходимо запретить пользователям предоставлять разрешения определенным пользователям. Вместо этого вы хотите разрешить только связывать пользователей с группами. Для этого отключите поле user_permissions
для всех не суперпользователей:
из набора импорта Set
из джанго.contrib import admin
из django.contrib.auth.models импортировать пользователя
из django.contrib.auth.admin импортировать UserAdmin
@ admin.register (Пользователь)
класс CustomUserAdmin (UserAdmin):
def get_form (self, request, obj = None, ** kwargs):
form = super (). get_form (запрос, объект, ** kwargs)
is_superuser = request.user.is_superuser
disabled_fields = set () # тип: Set [str]
если не is_superuser:
disabled_fields | = {
'имя пользователя',
'is_superuser',
'user_permissions',
}
для f в disabled_fields:
если f в форме.base_fields:
form.base_fields [f] .disabled = Истина
форма возврата
Вы использовали ту же технику, что и в предыдущих разделах, для реализации другого бизнес-правила. В следующих разделах вы собираетесь реализовать более сложные бизнес-правила для защиты вашей системы.
Запретить пользователям, не являющимся суперпользователями, изменять свои собственные разрешения
Сильные пользователи часто оказываются слабым местом. Они обладают сильными разрешениями, и потенциальный ущерб, который они могут нанести, значительный.Чтобы предотвратить повышение разрешений в случае вторжения, вы можете запретить пользователям редактировать свои собственные разрешения:
из набора импорта Set
от администратора импорта django.contrib
из django.contrib.auth.models импортировать пользователя
из django.contrib.auth.admin импортировать UserAdmin
@ admin.register (Пользователь)
класс CustomUserAdmin (UserAdmin):
def get_form (self, request, obj = None, ** kwargs):
form = super (). get_form (запрос, объект, ** kwargs)
is_superuser = request.user.is_superuser
disabled_fields = set () # тип: Set [str]
если не is_superuser:
disabled_fields | = {
'имя пользователя',
'is_superuser',
'user_permissions',
}
# Запретить пользователям, не являющимся суперпользователями, редактировать свои собственные разрешения
если (
не is_superuser
и obj не равно None
и obj == request.Пользователь
):
disabled_fields | = {
'is_staff',
'is_superuser',
'группы',
'user_permissions',
}
для f в disabled_fields:
если f в form.base_fields:
form.base_fields [f] .disabled = Истина
форма возврата
Аргумент obj
- это экземпляр объекта, с которым вы сейчас работаете:
- Когда
obj
равно None , форма используется для создания нового пользователя. - Когда
obj
неНет
, форма используется для редактирования существующего пользователя.
Чтобы проверить, работает ли пользователь, выполняющий запрос, над собой, вы сравните request.user
с obj
. Поскольку это администратор пользователя, obj
является либо экземпляром User
, либо None
. Когда пользователь, выполняющий запрос, request.user
, равен obj
, это означает, что пользователь обновляет себя.В этом случае вы отключите все конфиденциальные поля, которые можно использовать для получения разрешений.
Возможность настройки формы на основе объекта очень полезна. Его можно использовать для реализации сложных бизнес-ролей.
Переопределение разрешений
Иногда может быть полезно полностью переопределить разрешения в админке Django. Распространенный сценарий - когда вы используете разрешения в других местах и не хотите, чтобы штатные пользователи вносили изменения в админку.
Django использует хуки для четырех встроенных разрешений.Внутри хуки используют разрешения текущего пользователя для принятия решения. Вы можете переопределить эти перехватчики и предоставить другое решение.
Чтобы запретить штатным пользователям удалять экземпляр модели, независимо от их прав, вы можете сделать следующее:
от администратора импорта django.contrib
из django.contrib.auth.models импортировать пользователя
из django.contrib.auth.admin импортировать UserAdmin
@ admin.register (Пользователь)
класс CustomUserAdmin (UserAdmin):
def has_delete_permission (self, request, obj = None):
вернуть ложь
Как и в случае с get_form ()
, obj
- это экземпляр, на котором вы сейчас работаете:
- Когда
obj
равноНет
, пользователь запросил представление списка. - Когда
obj
неNone
, пользователь запросил изменение ракурса для конкретного экземпляра.
Наличие экземпляра объекта в этой ловушке очень полезно для реализации разрешений на уровне объекта для различных типов действий. Вот другие варианты использования:
- Предотвращение изменений в рабочее время
- Реализация разрешений на уровне объекта
Ограничить доступ к настраиваемым действиям
Специальные действия администратора требуют особого внимания.Django с ними не знаком, поэтому по умолчанию он не может ограничить доступ к ним. Настраиваемое действие будет доступно любому пользователю с правами администратора с любым разрешением на модель.
Для иллюстрации добавьте удобное действие администратора, чтобы отметить нескольких пользователей как активных:
от администратора импорта django.contrib
из django.contrib.auth.models импортировать пользователя
из django.contrib.auth.admin импортировать UserAdmin
@ admin.register (Пользователь)
класс CustomUserAdmin (UserAdmin):
действия = [
'activate_users',
]
def activate_users (self, request, queryset):
cnt = queryset.фильтр (is_active = False) .update (is_active = True)
self.message_user (запрос, 'Активированные {} пользователи.' формат (cnt))
activate_users.short_description = 'Активировать пользователей' # тип: игнорировать
Используя это действие, штатный пользователь может отметить одного или нескольких пользователей и активировать их всех сразу. Это полезно во всех случаях, например, если у вас возникла ошибка в процессе регистрации и вам нужно было активировать пользователей сразу.
Это действие обновляет информацию о пользователе, поэтому вы хотите, чтобы ее могли использовать только пользователи с разрешениями на изменение.
Администратор Django использует внутреннюю функцию для получения действий. Чтобы скрыть activate_users ()
от пользователей без разрешения на изменение, переопределите get_actions ()
:
от администратора импорта django.contrib
из django.contrib.auth.models импортировать пользователя
из django.contrib.auth.admin импортировать UserAdmin
@ admin.register (Пользователь)
класс CustomUserAdmin (UserAdmin):
действия = [
'activate_users',
]
def activate_users (self, request, queryset):
утвердить запрос.user.has_perm ('auth.change_user')
cnt = queryset.filter (is_active = False) .update (is_active = True)
self.message_user (запрос, 'Активированные {} пользователи.' формат (cnt))
activate_users.short_description = 'Активировать пользователей' # тип: игнорировать
def get_actions (self, request):
actions = super (). get_actions (запрос)
если не request.user.has_perm ('auth.change_user'):
дель действия ['activate_users']
вернуть действия
get_actions ()
возвращает OrderedDict
.Ключ - это имя действия, а значение - функция действия. Чтобы настроить возвращаемое значение, вы переопределяете функцию, получаете исходное значение и, в зависимости от разрешений пользователя, удаляете настраиваемое действие activate_users
из dict
. На всякий случай вы также подтверждаете права пользователя в действии.
Для штатных пользователей без разрешений change_user ()
действие activate_users
не будет отображаться в раскрывающемся списке действий.
Заключение
Администратор Django - отличный инструмент для управления проектом Django. Многие команды полагаются на него, чтобы оставаться продуктивным при управлении повседневными операциями. Если вы используете администратор Django для выполнения операций с моделями, важно знать разрешения. Приемы, описанные в этой статье, полезны для любого администратора модели, а не только для модели User
.
В этом руководстве вы защитили свою систему, внося следующие изменения в Django Admin:
- Вы, , защитили от повышения разрешений , запретив пользователям редактировать свои собственные разрешения.
- Вы, , поддерживали аккуратность и удобство обслуживания разрешений, заставляя пользователей управлять разрешениями только с помощью групп.
- Вы, , предотвратили утечку разрешений с помощью настраиваемых действий , явно установив необходимые разрешения.
Ваш администратор модели User
теперь намного безопаснее, чем когда вы начинали!
Awesome Django авторизация, без базы данных
rules
- крошечное, но мощное приложение, предоставляющее Django разрешения на уровне объектов без использования базы данных.По своей сути это общая структура для построения систем на основе правил, аналогичных деревьям решений. Его также можно использовать как отдельную библиотеку в других контекстах и фреймворках.
Возможности
правил
позаботятся о вас. правил
это:
- Документировано , протестировано , надежно и простое в использовании .
- Универсальный . Украшайте вызываемые объекты для построения сложных графов предикатов.Предикаты могут быть вызываемыми любым типом - простые функции, лямбда-выражения, методы, вызываемые объекты классов, частичные функции, декорированные функции, что угодно.
- Хороший гражданин Джанго . Полная интеграция с представлениями Django, шаблонами и администратором для тестирования разрешений на уровне объектов.
- Эффективный и умный . Не нужно возиться с базой данных, чтобы выяснить, действительно ли Джон написал эту книгу.
- Простой .Погрузитесь в код. Вам понадобится 10 минут, чтобы понять, как это работает.
- Мощный . Правила
Содержание
Требования
rules
требует Python 2.7 / 3.4 или новее. При желании он может интегрироваться с Django, и в этом случае требуется Django 1.11 или новее.
Примечание : В любой момент времени правила
будут поддерживать все поддерживаемые в настоящее время версии Django, при этом прекращая поддержку тех версий, срок жизни которых подошел к концу в второстепенных выпусках. Текущее состояние и временную шкалу см. В разделе «Поддерживаемые версии» на веб-сайте Django Project.
Обновление 1.x
- Прекращена поддержка Python 2.6 и 3.3, а также версий Django до 1.11.
- Исключение
SkipPredicate
и методskip ()
изPredicate
, которые использовались для обозначения того, что предикат должен быть пропущен, были удалены.Для этого вы можете вернутьNone
из вашего предиката. - API-интерфейсы для замены предиката правила были переименованы, и их поведение изменилось.
replace_rule
иreplace_perm Функции
иreplace_rule
методRuleSet
были переименованы вset_rule
,set_perm
иRuleSet.set_perm
соответственно. Старое поведение заключалось в выдачеKeyError
, если правило с заданным именем не существовало.Начиная с версии 2.0 это изменилось, и вы можете безопасно использоватьset_ *
для установки предиката правила без необходимости сначала проверять, существует ли правило.
Как установить
Использование pip:
Вручную:
$ git clone https://github.com/dfunckt/django-rules.git $ cd django-rules $ python setup.py установить
Выполнить тесты с:
Вы также можете прочитать Лучшие практики для получения общих советов о том, как использовать правила
.
Настройка Django
Добавить правил
в INSTALLED_APPS
:
INSTALLED_APPS = ( #... 'правила', )
Добавьте серверную часть аутентификации:
AUTHENTICATION_BACKENDS = ( 'rules.permissions.ObjectPermissionBackend', 'django.contrib.auth.backends.ModelBackend', )
Использование правил
rules
основано на идее, что вы поддерживаете dict-подобный объект, который сопоставляет строковые ключи, используемые в качестве идентификаторов того или иного вида, с вызываемыми объектами, называемыми предикатами . Этот dict-подобный объект на самом деле является экземпляром RuleSet
, а предикаты - экземплярами Predicate
.
Создание предикатов
Давайте на мгновение проигнорируем наборы правил и определим предикат. Самый простой способ - использовать декоратор @predicate
:
>>> @ rules.predicate >>> def is_book_author (пользователь, книга): ... вернуть book.author == пользователь ... >>> is_book_author <Предикат: объект is_book_author в 0x10eeaa490>
Этот предикат вернет Истина
, если автор книги является данным пользователем, Ложь
в противном случае.
Предикаты могут быть созданы из любого вызываемого объекта, который принимает все от нуля до двух позиционных аргументов:
-
fn (объект, цель)
-
fn (obj)
-
fn ()
Это их общая форма. Если смотреть с точки зрения авторизации в Django, эквивалентные подписи:
-
fn (пользователь, объект)
-
fn (пользователь)
-
fn ()
Предикаты могут делать практически все что угодно с заданными аргументами, но всегда должны возвращать Истина
, если условие, которое они проверяют, истинно, Ложь
в противном случае.Правила
поставляется с несколькими предопределенными предикатами, о которых вы можете прочитать позже в Справочнике по API, которые в основном полезны при работе с авторизацией в Django.
Настройка правил
Давайте представим, что мы хотим разрешить авторам редактировать или удалять свои книги, но не книги, написанные другими авторами. Итак, по сути, то, что определяет, может ли автор редактировать или может удалить данную книгу, - это , являются ли они ее автором .
В правилах
такие требования смоделированы как правила .Правило - это отображение уникального идентификатора (например, «можно редактировать») с предикатом. Правила сгруппированы в набор правил . правил
имеет два предопределенных набора правил:
- Набор правил по умолчанию, в котором хранятся общие правила.
- Другой набор правил, хранящих правила, которые служат разрешениями в контексте Django.
Итак, давайте определим нашу первую пару правил, добавив их в общий набор правил. Мы можем использовать предикат is_book_author
, который мы определили ранее:
>>> правила.add_rule ('can_edit_book', is_book_author) >>> rules.add_rule ('can_delete_book', is_book_author)
Предполагая, что у нас есть данные, теперь мы можем протестировать наши правила:
>>> от пользователя django.contrib.auth.models import >>> из books.models import Book >>> guidetodjango = Book.objects.get (isbn = '978-1-4302-1936-1') >>> guidetodjango.author <Пользователь: adrian> >>> Адриан = User.objects.get (имя пользователя = 'Адриан') >>> rules.test_rule ('can_edit_book', Адриан, Guidetodjango) Правда >>> правила.test_rule ('can_delete_book', Адриан, Guidetodjango) Правда
Красиво ... но не круто.
Комбинирование предикатов
Предикаты сами по себе не так полезны - не более полезны, чем любая другая функция. Однако предикаты можно комбинировать с помощью бинарных операторов для создания более сложных. Предикаты поддерживают следующие операторы:
-
P1 & P2
: возвращает новый предикат, который возвращаетTrue
, если оба предиката возвращаютTrue
, в противном случаеFalse
.P2 : возвращает новый предикат, который возвращаетTrue
, если один из предикатов возвращаетTrue
, а другой возвращаетFalse
, в противном случаеFalse
. -
~ P
: возвращает новый предикат, который возвращает отрицательный результат исходного предиката.
Предположим, что для разрешения пользователю редактировать данную книгу требовалось, чтобы он был либо автором книги, либо членом группы «редакторы». Разрешение пользователям удалять книгу по-прежнему должно зависеть от того, является ли пользователь автором книги.
С правилами
это легко реализовать. Нам нужно будет определить другой предикат, который вернет True
, если данный пользователь является членом группы «редакторы», False
в противном случае. Пригодится встроенный завод is_group_member
:
>>> is_editor = rules.is_group_member ('редакторы') >>> is_editor <Предикат: is_group_member: объект редакторов в 0x10eee1350>
Мы могли бы объединить его с предикатом is_book_author
, чтобы создать новый, который проверяет любое условие:
>>> is_book_author_or_editor = is_book_author | is_editor >>> is_book_author_or_editor <Предикат: (is_book_author | is_group_member: editors) объект в 0x10eee1390>
Теперь мы можем обновить наше правило can_edit_book
:
>>> правила.set_rule ('can_edit_book', is_book_author_or_editor) >>> rules.test_rule ('can_edit_book', Адриан, Guidetodjango) Правда >>> rules.test_rule ('can_delete_book', Адриан, Guidetodjango) Правда
Посмотрим, что будет с другим пользователем:
>>> martin = User.objects.get (имя пользователя = 'martin') >>> список (martin.groups.values_list ('name', flat = True)) ['редакторы'] >>> rules.test_rule ('can_edit_book', martin, guidetodjango) Правда >>> правила.test_rule ('can_delete_book', martin, guidetodjango) Ложь
Превосходно.
До сих пор мы использовали только базовую общую структуру для определения и тестирования правил. Этот уровень совершенно не специфичен для Django; его можно использовать в любом контексте. Фактически нет импорта чего-либо, связанного с Django, во всем приложении (кроме модуля rules.templatetags
). правила
, однако могут быть тесно интегрированы с Django для обеспечения авторизации.
Использование правил с Django
правил
может предоставлять разрешения на уровне объекта в Django.Он поставляется с бэкэндом авторизации и парой тегов шаблонов для использования в ваших шаблонах.
Разрешения
В правилах
разрешения представляют собой особый тип правил. Вы по-прежнему определяете правила, создавая и комбинируя предикаты. Однако эти правила должны быть добавлены к набору правил для конкретных разрешений, который поставляется с правилами
, чтобы они могли быть выбраны серверной частью авторизации правил
.
Создание разрешений
Соглашение об именах разрешений в Django - app_label.action_object
, и мы хотим этого придерживаться. Добавим правила для прав доступа books.change_book
и books.delete_book
:
>>> rules.add_perm ('books.change_book', is_book_author | is_editor) >>> rules.add_perm ('books.delete_book', is_book_author)
Видите разницу в API? add_perm
добавляет к набору правил для конкретных разрешений, тогда как add_rule
добавляет к общему набору правил по умолчанию. Однако важно знать, что эти два набора правил являются отдельными, а это означает, что добавление правила в один не делает его доступным для другого.
Проверка разрешения
Давайте продолжим и проверим, есть ли у adrian
разрешение на изменение guidetodjango
book:
>>> adrian.has_perm ('books.change_book', guidetodjango) Ложь
Когда вы вызываете метод User.has_perm
, Django спрашивает каждый бэкэнд в настройках .AUTHENTICATION_BACKENDS
, имеет ли пользователь данное разрешение для объекта. При запросе прав доступа к объекту бэкэнд аутентификации по умолчанию Django всегда возвращает False
.Правила
поставляется с серверной частью авторизации, которая может предоставлять разрешения на уровне объекта, просматривая набор правил для конкретных разрешений.
Добавим правил бэкэнд авторизации
в настройки:
AUTHENTICATION_BACKENDS = ( 'rules.permissions.ObjectPermissionBackend', 'django.contrib.auth.backends.ModelBackend', )
Теперь повторная проверка дает adrian
необходимые разрешения:
>>> адриан.has_perm ('books.change_book', guidetodjango) Правда >>> adrian.has_perm ('books.delete_book', guidetodjango) Правда >>> martin.has_perm ('books.change_book', guidetodjango) Правда >>> martin.has_perm ('books.delete_book', guidetodjango) Ложь
Разрешения в моделях
ПРИМЕЧАНИЕ: Функции, описанные в этом разделе, работают только на Python 3+.
Обычно есть набор разрешений для модели, как то, что предлагает Django с разрешениями модели по умолчанию (например, добавить , изменить и т. Д.). При использовании правил
в качестве серверной части проверки разрешений вы можете объявить разрешения на уровне объекта для любой модели аналогичным образом, используя новую опцию Meta
.
Во-первых, вам нужно переключить базу и метакласс вашей модели на слегка расширенные версии, представленные в файле rules.contrib.models
. Есть несколько классов и миксинов, которые вы можете использовать, в зависимости от того, используете ли вы уже настраиваемую базу и / или метакласс для своих моделей или нет. Расширения очень тонкие и никоим образом не влияют на поведение модели, кроме как заставляют ее регистрировать разрешения.
Если вы используете стандартную модель
django.db.models.Model
в качестве основы для своих моделей, просто переключитесь наRulesModel
, и все готово.Если у вас уже есть настраиваемый базовый класс, добавляющий общие функции к вашим моделям, добавьте
RulesModelMixin
к классам, от которых он наследуется, и установитеRulesModelBase
в качестве его метакласса, например:из django.db.models import Model из rules.contrib.models импортировать RulesModelBase, RulesModelMixin класс MyModel (RulesModelMixin, Модель, метакласс = RulesModelBase): ...
Если вы используете собственный метакласс для своих моделей, вы уже знаете, как заставить его наследовать от
RulesModelBaseMixin
самостоятельно.
Затем создайте свои модели таким образом, предполагая, что вы используете RulesModel
как базу напрямую:
правила импорта из rules.contrib.models импортировать RulesModel Книга классов (RulesModel): класс Мета: rules_permissions = { "добавить": rules.is_staff, «читать»: правила.is_authenticated, }
Это будет эквивалентно следующим звонкам:
rules.add_perm ("app_label.add_book", rules.is_staff) rules.add_perm ("app_label.read_book", rules.is_authenticated)
В RulesModelMixin
есть методы, которые можно перезаписать, чтобы настроить регистрацию разрешений модели. Если вам это нужно, см. Задокументированный исходный код.
Особый интерес представляет метод класса get_perm
из RulesModelMixin
, который можно использовать для преобразования типа разрешения в соответствующее полное имя разрешения.Если вам нужно программно запросить какой-либо тип разрешений для данной модели, это удобно:
, если user.has_perm (Book.get_perm ("читать")): ...
Разрешения в представлениях
rules
поставляется с набором декораторов представлений, которые помогут вам обеспечить авторизацию в ваших представлениях.
Использование декоратора представлений на основе функций
Для представлений на основе функций вы можете использовать декоратор permission_required
:
из django.ярлыки import get_object_or_404 из rules.contrib.views import permission_required from posts.models import Post def get_post_by_pk (запрос, post_id): return get_object_or_404 (Сообщение, pk = post_id) @permission_required ('posts.change_post', fn = get_post_by_pk) def post_update (запрос, post_id): # ...
Использование простое, но в приведенном выше примере есть одна вещь, которая выделяется, и это функция get_post_by_pk
. Эта функция, учитывая текущий запрос и все аргументы, переданные в представление, отвечает за выборку и возврат объекта для проверки разрешений - i.е. экземпляр Post
с PK, равным заданному post_id
в примере. Этот конкретный вариант использования довольно распространен, поэтому, чтобы не печатать, правила
поставляются с общей вспомогательной функцией, которую вы можете использовать для декларативного выполнения. Пример ниже эквивалентен приведенному выше:
из rules.contrib.views import permission_required, objectgetter from posts.models import Post @permission_required ('posts.change_post', fn = objectgetter (Post, 'post_id')) def post_update (запрос, post_id): #...
Дополнительные сведения о декораторе и вспомогательной функции см. В модуле rules.contrib.views
.
Использование миксина представлений на основе классов
Django включает набор миксинов доступа, которые вы можете использовать в представлениях на основе классов для принудительной авторизации. Правила .
расширяет эту структуру для предоставления разрешений на уровне объектов с помощью миксина PermissionRequiredMixin
.
В следующем примере выполняется автоматическая проверка разрешения для экземпляра, возвращаемого методом представления get_object
:
из django.views.generic.edit импорт UpdateView из rules.contrib.views import PermissionRequiredMixin from posts.models import Post класс PostUpdate (PermissionRequiredMixin, UpdateView): model = Опубликовать permission_required = 'posts.change_post'
Вы можете настроить объект, переопределив get_object
или get_permission_object
.
Для получения дополнительной информации см. Документацию Django и модуль rules.contrib.views
.
Автоматическая проверка разрешений в зависимости от типа представления
Если вы используете механизмы, предусмотренные правилами .contrib.models
для регистрации разрешений для ваших моделей, как описано в разделе «Разрешения в моделях». Для вас доступен еще один удобный миксин для представлений на основе классов.
rules.contrib.views.AutoPermissionRequiredMixin
может распознавать тип представления, с которым он используется, и автоматически проверять наличие соответствующего разрешения.
В этом примере представления без какой-либо дополнительной настройки будет автоматически проверяться разрешение «posts.change_post»
, учитывая, что метка приложения - «сообщений»
:
из django.views.generic импорт UpdateView из rules.contrib.views импортировать AutoPermissionRequiredMixin from posts.models import Post класс UpdatePostView (AutoPermissionRequiredMixin, UpdateView): model = Опубликовать
По умолчанию общие представления CRUD из django.views.generic
сопоставляются с собственными типами разрешений Django ( добавить , изменить , удалить и вид ). Однако предопределенные сопоставления могут быть расширены, изменены или полностью заменены при создании подкласса AutoPermissionRequiredMixin
.См. Полностью документированный исходный код, чтобы узнать, как это сделать правильно.
Разрешения и правила в шаблонах
rules
поставляется с двумя тегами шаблонов, которые позволяют вам проверять правила и разрешения в шаблонах.
Добавьте правил
к своим INSTALLED_APPS
:
INSTALLED_APPS = ( # ... 'правила', )
Затем в вашем шаблоне:
{% load rules%} {% has_perm 'books.change_book' авторская книга как can_edit_book%} {% if can_edit_book%} ... {% endif%} Пользователь {% test_rule 'has_super_feature' как has_super_feature%} {% if has_super_feature%} ... {% endif%}
Разрешения в админке
Если вы настроили правил
для использования с разрешениями в Django, вы почти настроены также на использование правил
для авторизации любых действий добавления / изменения / удаления в админке. Администратор запрашивает четыре различных разрешений, в зависимости от действия:
-
<метка_приложения> .add_ <имя модели>
-
.view_ <имя модели> -
<метка_приложения> .change_ <имя модели>
-
<метка_приложения> .delete_ <имя модели>
-
Примечание. Разрешение на просмотр является новым в Django v2.1 и не должно добавляться в более ранних версиях.
Первые четыре очевидны. Пятое - это необходимое разрешение для отображения приложения на «панели управления» администратора. Его переопределение не ограничивает доступ к добавлению, изменению или удалению представлений.Вот некоторые правила для нашего воображаемого приложения книг
в качестве примера:
>>> rules.add_perm ('книги', rules.always_allow) >>> rules.add_perm ('books.add_book', is_staff) >>> rules.add_perm ('books.view_book', is_staff | has_secret_access_code) >>> rules.add_perm ('books.change_book', is_staff) >>> rules.add_perm ('books.delete_book', is_staff)
Django Admin не поддерживает объектные разрешения в том смысле, что он никогда не будет запрашивать разрешение на выполнение действия над объектом , только если пользователю разрешено действовать на ( любых ) экземплярах модели.
Если вы хотите сообщить Django, есть ли у пользователя разрешения на определенный объект, вам придется переопределить следующие методы модели ModelAdmin
:
-
has_view_permission (пользователь, obj = None)
-
has_change_permission (пользователь, obj = None)
-
has_delete_permission (пользователь, obj = None)
rules
поставляется с пользовательским подклассом ModelAdmin
, rules.contrib.admin.ObjectPermissionsModelAdmin
, который переопределяет эти методы для передачи отредактированного экземпляра модели бэкэндам авторизации, тем самым разрешая разрешения для каждого объекта в Admin:
# books / admin.py от администратора импорта django.contrib из rules.contrib.admin импортировать ObjectPermissionsModelAdmin из .models import Book класс BookAdmin (ObjectPermissionsModelAdmin): проходить admin.site.register (Книга, BookAdmin)
Теперь это позволяет вам указывать разрешения следующим образом:
>>> правила.add_perm ('книги', rules.always_allow) >>> rules.add_perm ('books.add_book', has_author_profile) >>> rules.add_perm ('books.change_book', is_book_author_or_editor) >>> rules.add_perm ('books.delete_book', is_book_author)
Чтобы сохранить обратную совместимость, Django запросит разрешение view или change . Для максимальной гибкости, правила
ведут себя несколько иначе: правила
будут запрашивать разрешение на изменение тогда и только тогда, когда для разрешения просмотра не существует правила.
Разрешения в Django Rest Framework
Подобно rules.contrib.views.AutoPermissionRequiredMixin
, существует rules.contrib.rest_framework.AutoPermissionViewSetMixin
для наборов представлений в Django Rest Framework. Разница в том, что он получает разрешение не от типа представления, а от действия API ( создать , получить и т. Д.), Которое пытались выполнить. Конечно, это также требует, чтобы вы объявили свои модели, как описано в разделе Разрешения в моделях.
Вот возможный ModelViewSet
для модели Post
с полностью автоматизированной проверкой разрешений CRUD:
из rest_framework.serializers import ModelSerializer из rest_framework.viewsets импортировать ModelViewSet из rules.contrib.rest_framework импорт AutoPermissionViewSetMixin from posts.models import Post класс PostSerializer (ModelSerializer): класс Мета: model = Опубликовать fields = "__all__" класс PostViewSet (AutoPermissionViewSetMixin, ModelViewSet): queryset = Сообщение.objects.all () serializer_class = PostSerializer
По умолчанию действия CRUD ModelViewSet
сопоставляются с собственными типами разрешений Django ( добавить , изменить , удалить и просмотреть ). Для действия список
не включена проверка разрешений. Однако предопределенные сопоставления могут быть расширены, изменены или полностью заменены при использовании (или создании подклассов) AutoPermissionViewSetMixin
. Пользовательские действия API, определенные с помощью декоратора @action
, также могут быть сопоставлены.См. Полностью документированный исходный код для получения подробной информации о том, как правильно настроить поведение по умолчанию.
Расширенные функции
Пользовательские наборы правил
Вы можете создать столько наборов правил, сколько вам нужно:
>>> features = rules.RuleSet ()
И манипулируйте ими, добавляя, удаляя, запрашивая и проверяя правила:
>>> features.rule_exists ('has_super_feature') Ложь >>> is_special_user = rules.is_group_member ('специальный') >>> особенности.add_rule ('has_super_feature', is_special_user) >>> 'has_super_feature' в функциях Правда >>> особенности ['has_super_feature'] <Предикат: is_group_member: специальный объект в 0x10eeaa500> >>> features.test_rule ('has_super_feature', Адриан) Правда >>> features.remove_rule ('has_super_feature')
Обратите внимание, однако, что пользовательские наборы правил недоступны в шаблонах Django - вам необходимо обеспечить интеграцию самостоятельно.
Контекст вызова
Новый контекст создается в результате вызова предиката .test ()
и действует только на время вызова. Контекст - это простой dict
, который вы можете использовать для хранения произвольных данных (например, кэширование вычисленных значений, установки флагов и т. Д.), Которые могут использоваться предикатами позже в цепочке. Внутри функции предиката его можно использовать так:
>>> @predicate ... def mypred (a, b): ... значение = вычислить_дорогое_значение (а) ... mypred.context ['значение'] = значение ... вернуть True
Другие предикаты могут позже использовать сохраненные значения:
>>> @predicate ... def myotherpred (a, b): ... значение = myotherpred.context.get ('значение') ... если значение не равно None: ... вернуть do_something_with_value (значение) ... еще: ... вернуть do_something_without_value ()
Predicate.context
предоставляет единственный атрибут args
, который содержит аргументы, заданные для test ()
в начале вызова.
Переплет "сам"
В теле функции предиката вы можете ссылаться на сам экземпляр предиката по его имени, например. is_book_author
. Передача bind = True
в качестве аргумента ключевого слова декоратору предиката
позволит вам ссылаться на предикат с self
, что более удобно. Связывание и
- это просто синтаксический сахар. Фактически, следующие два эквивалента:
>>> @predicate ... def is_book_author (пользователь, книга): ... если is_book_author.context.args: ... вернуть пользователя == book.author ... вернуть False >>> @predicate (bind = True) ... def is_book_author (я, пользователь, книга): ... если self.context.args: ... вернуть пользователя == book.author ... вернуть False
Пропуск предикатов
Вы можете пропустить оценку, вернув Нет
из вашего предиката:
>>> @predicate (bind = True) ... def is_book_author (я, пользователь, книга): ... если len (self.context.args)> 1: ... вернуть пользователя == book.author ... еще: ... return Нет
Возвращение Нет
означает, что предикат не нужно оценивать, таким образом, результат предиката остается неизменным до этого момента.
Ведение журнала оценки предиката
правила
можно дополнительно настроить для регистрации отладочной информации по мере оценки правил, чтобы помочь с отладкой ваших предикатов. Сообщения отправляются на уровне DEBUG в регистратор 'rules'
. Следующий файл dictConfig настраивает регистратор консоли (поместите его в файл settings.py вашего проекта, если вы используете правила с Django):
LOGGING = { 'версия': 1, disable_existing_loggers: Ложь, 'handlers': { 'приставка': { 'level': 'DEBUG', 'класс': 'ведение журнала.StreamHandler ', }, }, 'loggers': { 'правила': { 'обработчики': ['консоль'], 'level': 'DEBUG', 'распространять': Верно, }, }, }
Когда этот регистратор активен, для каждого отдельного предиката будет напечатано сообщение журнала при его оценке.
Лучшие практики
Прежде чем вы сможете проверить правила, эти правила должны быть зарегистрированы в наборе правил, и для этого необходимо импортировать модули, содержащие ваши определения правил.
Для сложных проектов с несколькими предикатами и правилами может оказаться непрактичным определять все ваши предикаты и правила внутри одного модуля. Возможно, лучше всего разделить их между любыми подкомпонентами вашего проекта. В контексте Django эти субкомпоненты могут быть приложениями для вашего проекта.
С другой стороны, поскольку импорт предикатов из любого места для определения правил может привести к циклическому импорту и разбитым сердцам, лучше всего дополнительно разделить предикаты и правила в разных модулях.
rules
можно дополнительно настроить для автоматического обнаружения модулей rules.py
в ваших приложениях и импорта их при запуске. Чтобы правил
сделали это, просто отредактируйте настройку INSTALLED_APPS
:
INSTALLED_APPS = ( # заменить 'rules' на: 'rules.apps.AutodiscoverRulesConfig', )
Примечание: На Python 2 вы также должны добавить следующее в верхнюю часть файла rules.py
, иначе вы получите ошибки импорта при попытке импортировать правила сам
:
из __future__ import absolute_import
Ссылка API
Основные API-интерфейсы доступны из корневого модуля rules
.Специфичные для Django функции для администратора и представлений доступны по адресу rules.contrib
.
Правила класса
. Предикат
Вы создаете экземпляров предиката
, передавая вызываемый объект:
>>> def is_book_author (пользователь, книга): ... вернуть book.author == пользователь ... >>> pred = Предикат (is_book_author) >>> пред <Предикат: объект is_book_author в 0x10eeaa490>
При желании вы можете указать другое имя для предиката, который будет использоваться при его проверке:
>>> pred = Predicate (is_book_author, name = 'другое_имя') >>> пред <Предикат: объект another_name в 0x10eeaa490>
Кроме того, вы можете дополнительно указать bind = True
, чтобы иметь доступ к экземпляру предиката с self
:
>>> def is_book_author (я, пользователь, книга): ... если self.context.args: ... вернуть пользователя == book.author ... вернуть False ... >>> pred = Predicate (is_book_author, bind = True) >>> пред <Предикат: объект is_book_author в 0x10eeaa490>
Методы экземпляра
-
test (obj = None, target = None)
- Возвращает результат вызова переданного вызываемого объекта с нулем, одним или двумя позиционными аргументами, в зависимости от того, сколько он принимает.
Правила класса
.RuleSet
RuleSet
расширяет встроенный в Python тип dict. Следовательно, вы можете создавать и использовать набор правил любым способом, которым вы пользуетесь dict.
Методы экземпляра
-
add_rule (имя, предикат)
- Добавляет предикат в набор правил, присваивая его заданному имени правила. Вызывает ошибку
KeyError
, если другое правило с таким именем уже существует. -
set_rule (имя, предикат)
- Установите правило с заданным именем, независимо от того, существует ли оно уже.
-
remove_rule (имя)
- Удалите правило с заданным именем. Вызывает
KeyError
, если правило с таким именем не существует. -
rule_exists (имя)
- Возвращает
Истина,
, если правило с данным именем существует,Ложь,
в противном случае. -
test_rule (name, obj = None, target = None)
- Возвращает результат вызова
predicate.test (obj, target)
, гдеpredicate
- это предикат для правила с заданным именем.ВозвращаетЛожь
, если правило с данным именем не существует.
Декораторы
-
@predicate
Декоратор, который создает предикат из любого вызываемого объекта:
>>> @predicate ... def is_book_author (пользователь, книга): ... вернуть book.author == пользователь ... >>> is_book_author <Предикат: объект is_book_author в 0x10eeaa490>
Настройка имени предиката:
>>> @predicate (имя = 'другое_имя') ... def is_book_author (пользователь, книга): ... вернуть book.author == пользователь ... >>> is_book_author <Предикат: объект another_name в 0x10eeaa490>
Переплет
сам
:>>> @predicate (bind = True) ... def is_book_author (я, пользователь, книга): ... если 'user_has_special_flag' в self.context: ... вернуть self.context ['user_has_special_flag'] ... вернуть book.author == пользователь
Предопределенные предикаты
-
always_allow ()
,always_true ()
- Всегда возвращает
Истинно
. -
always_deny ()
,always_false ()
- Всегда возвращает
Ложь
. -
is_authenticated (пользователь)
- Возвращает результат вызова
user.is_authenticated ()
. ВозвращаетFalse
, если у данного пользователя нет методаis_authenticated
. -
is_superuser (пользователь)
- Возвращает результат вызова
user.is_superuser
. ВозвращаетFalse
, если у данного пользователя нет свойстваis_superuser
. -
is_staff (пользователь)
- Возвращает результат вызова
user.is_staff
. ВозвращаетFalse
, если у данного пользователя нет свойстваis_staff
. -
is_active (пользователь)
- Возвращает результат вызова
user.is_active
. ВозвращаетFalse
, если у данного пользователя нет свойстваis_active
. -
is_group_member (* группы)
- Фабрика, которая создает новый предикат, который возвращает
Истина
, если данный пользователь является членом всех данных групп,Ложь
в противном случае.
Ярлыки
Управление общим набором правил
-
add_rule (имя, предикат)
- Добавляет правило в общий набор правил. См.
RuleSet.add_rule
. -
set_rule (имя, предикат)
- Установите правило с заданным именем из общего набора правил. См.
RuleSet.set_rule
. -
remove_rule (имя)
- Удалите правило из общего набора правил. См.
RuleSet.remove_rule
. -
rule_exists (имя)
- Возвращает, существует ли правило в общем наборе правил. См.
RuleSet.rule_exists
. -
test_rule (name, obj = None, target = None)
- Проверяет правило с заданным именем. См.
RuleSet.test_rule
.
Управление набором правил разрешений
-
add_perm (имя, предикат)
- Добавляет правило в набор правил разрешений.См.
RuleSet.add_rule
. -
set_perm (имя, предикат)
- Заменить правило из набора правил разрешений. См.
RuleSet.set_rule
. -
remove_perm (имя)
- Удалите правило из набора правил разрешений. См.
RuleSet.remove_rule
. -
perm_exists (имя)
- Возвращает, существует ли правило в наборе правил разрешений. См.
RuleSet.rule_exists
. -
has_perm (name, user = None, obj = None)
- Проверяет правило с заданным именем.См.
RuleSet.test_rule
.
Лицензия
django-rules
распространяется по лицензии MIT.
Авторские права (c) 2014 Акис Кесоглу
Настоящим предоставляется бесплатное разрешение любому лицу, получающему копию этого программного обеспечения и связанных файлов документации («Программное обеспечение»), на использование Программного обеспечения без ограничений, включая, помимо прочего, права на использование, копирование, изменение, объединять, публиковать, распространять, сублицензировать и / или продавать копии Программного обеспечения и разрешать лицам, которым предоставляется Программное обеспечение, делать это при соблюдении следующих условий:
Приведенное выше уведомление об авторских правах и это уведомление о разрешении должны быть включены во все копии или существенные части Программного обеспечения.
ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ, ЯВНЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ГАРАНТИЯМИ КОММЕРЧЕСКОЙ ЦЕННОСТИ, ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ И НЕЗАЩИТЫ ОТ ПРАВ. НИ ПРИ КАКИХ ОБСТОЯТЕЛЬСТВАХ АВТОРЫ ИЛИ ВЛАДЕЛЬЦЫ АВТОРСКИХ ПРАВ НЕ НЕСЕТ ОТВЕТСТВЕННОСТИ ЗА ЛЮБЫЕ ПРЕТЕНЗИИ, УБЫТКИ ИЛИ ДРУГИЕ ОТВЕТСТВЕННОСТЬ, ВЫЯВЛЯЮЩИЕСЯ В РЕЗУЛЬТАТЕ ДОГОВОРА, ПРАВИЛА ИЛИ ИНЫМ ОБРАЗОМ, ВОЗНИКАЮЩИМ, ВНУТРИ ИЛИ В СВЯЗИ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ ИЛИ ИСПОЛЬЗОВАНИЕМ ИЛИ ДРУГИМИ ДЕЛАМИ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ.
.