Sei sulla pagina 1di 13

Criando sistema com Multithreaded em Python

2011-04-01 by avelino Multithreaded quando temos mais de um programa executando ao mesmo tempo, totalmente diferente de executar duas ve o mesmo programa, com !threads! o sistema vai ser executado apenas uma ve e via thread vai processar mais de uma fun"#o ao mesmo tempo, isso necessario para concorr$ncia em sistema% &lgumas vantagens de trabalha com threads' M(ltiplos processo ao mesmo tempo e pode, portanto, compartilhar informa")es e comunicar uns com os outros mais facilmente do que se fossem processos separados* Menos consumo de mem+ria, pois o mesmo vai consumir mais ,-.% .ma thread tem um come"o, meio e fim, assim podemos colocar um ponteiro de instru"#o para acompanhar onde esta sendo processado cada thread dentro de seu contexto% /la pode ser antecipada 0interrompido1* -ode ser temporariamente suspensos 0tambm conhecido como sleep1, enquanto outros segmentos est#o em execu"#o - isso chamado de rendimento% 2niciando uma nova 3hread'
#!/usr/bin/python # -*- coding: UTF-8 -*import thread import time # Defini o da fun o de thread def print!time" name# de$ay%: count & ' (hi$e count ) *: time+s$eep"de$ay% count ,& print ./s: /s. / " name# time+ctime"time+time"%% % # 0riar dois t1picos try: thread+start!ne(!thread" print!time# ".Thread--.# 2# % % thread+start!ne(!thread" print!time# ".Thread-2.# 3# % % e4cept: print .5rro: n o conseguiu iniciar a thread. (hi$e -: pass

/xecutando'
a6e$ino:mu$tithreading/ 7--:'-:'-8 9 python e4amp$e+py Thread--: Thu :ar ;- --:';:2' 2'-Thread-2: Thu :ar ;- --:';:22 2'-Thread--: Thu :ar ;- --:';:22 2'-Thread--: Thu :ar ;- --:';:23 2'-Thread-2: Thu :ar ;- --:';:2< 2'-Thread--: Thu :ar ;- --:';:2< 2'-Thread--: Thu :ar ;- --:';:28 2'--

Thread-2: Thu :ar ;- --:';:;' 2'-Thread-2: Thu :ar ;- --:';:;3 2'-Thread-2: Thu :ar ;- --:';:;8 2'--

4e repararmos temos alguns processo concorrendo ao mesmo tempos, dessa forma 56 estamos trabalhando com 3hread%

Modulos da biblioteca thread


threading.activeCount()' 7etorna o n(mero de ob5etos de thread que est#o ativos% threading.currentThread()' 7etorna o n(mero de ob5etos de thread no controle do chamador de thread% threading.enumerate()' 7etorna uma lista de todos os ob5etos de thread que est#o atualmente activas% run()' Mtodo o ponto de partida para uma thread% start()' Mtodo inicia uma thread, chamando o mtodo de execu"#o% join([time])' /spera para terminar% isAlive()' Mtodo verifica se uma thread ainda est6 em execu"#o% getName()' Mtodo retorno o nome de uma thread% setName()' Mtodo declaro o nome de um thread%

Cron dentro do Django com Celery


2010-10-18 by avelino 9ntem na parte da noite conversando com um conhecido ele falou que 4ystem Message' :&7;2;<=2 0)string=, line 81 >ine bloc? ends @ithout a blan? line% estava usando em um pro5eto o ,elery, como ainda n#o conhecia vamos estudar este pro5eto% <ostei da forma que ele trabalha e como ele integra com o A5ango% B 3enho em um pro5eto uma fila de processamento s+ que foi desenvolvido por mim e n#o tem todos os recursos que o ,elery tem% Cou explicar como usar o ,elery com o A5ango em um exemplo simples, e como sempre basta usar a criatividade para desenvolver a sua necessidade% -rimeiramente temos que instalar dois pacotes -ython para que possamos trabalhar com o ,elery no A5ango, o d5ango-celery e ghettoq% ,aso tenhamos o easyDinstall instalado basta instalar os pacotes da seguinte forma'
9 easy!insta$$ d>ango-ce$ery 9 easy!insta$$ ghetto?

,aso n#o tenha vamos instalar'


9 9 9 9 9 9 9 9 9 9 cd /usr/src/ git c$one http://github+com/as@/d>ango-ce$ery+git cd d>ango-ce$ery python setup+py bui$d python setup+py insta$$ cd ++ git c$one http://github+com/as@/ghetto? cd ghetto? python setup+py bui$d python setup+py insta$$

&p+s instalar vamos criar um pro5eto para que possamos trabalhar com o ,elery nele%
9 d>ango-admin+py startpro>ect ce$erytest 9 cd ce$erytest

Camos editar o settings%py'


DATABAC5C & D Edefau$tE: D E5FGHF5E: Ed>ango+db+bac@ends+s?$ite;E# EFA:5E: EtestE# I I +++ 0AJJKT!BA0L5FD & .ghetto?+taproot+Database. HFCTAMM5D!ANNC & " +++ Ed>ce$eryE# Eghetto?E# %

&p+s declarar qual biblioteca o pro5eto em A5ango vai carregar podemos sincroni ar o nosso database'
9 python manage+py syncdb

3emos que criar um arquivo chamado tas?s%py, esse arquivo trabalha como o models de uma aplica"#o'
from ce$ery+tas@+schedu$es import crontab from ce$ery+decorators import periodic!tas@ # this (i$$ run e6ery minute# see http://ce$erypro>ect+org/docs/reference/ce$ery+tas@+schedu$es+htm$#ce$ery+tas@+s chedu$es+crontab Operiodic!tas@"run!e6ery&crontab"hour&.*.# minute&.*.# day!of!(ee@&.*.%% def test"%: print .Tarefa de teste+++.

&gora temos que dar start em nosso daemon ,elery'


9 python manage+py ce$eryd -6 2 -B -s ce$ery -5 -$ HFFK 2'-'--'--P '*:;3:33#2-*: QAJFHFG/:ainNrocess8 ce$eryOprogram-8 62+-+- is starting+ 72'-'--'--P '*:;3:33#2-<: QAJFHFG/:ainNrocess8 /usr/$oca$/$ib/python2+</dist-pac@ages/ce$ery-2+-+--py2+<+egg/ce$ery/apps/ (or@er+py:-'*: UserQarning: Junning ce$eryd (ith superuser pri6i$eges is not encouraged! .Junning ce$eryd (ith superuser pri6i$eges is not encouraged!.% 72'-'--'--P '*:;3:33#2-<: QAJFHFG/:ainNrocess8 /usr/$oca$/$ib/python2+</dist-pac@ages/ce$ery-2+-+--py2+<+egg/ce$ery/apps/ (or@er+py:-'8: UserQarning: Using settings+D5BUG $eads to a memory $ea@# ne6er use this setting in a production en6ironment! (arnings+(arn".Using settings+D5BUG $eads to a memory $ea@# . 72'-'--'--P '*:;3:33#222: QAJFHFG/:ainNrocess8 0onfiguration -RgtS + bro@er -RgtS ghetto?+taproot+Database://guestO$oca$host/ + ?ueues -RgtS + ce$ery -RgtS e4change:ce$ery "direct% binding:ce$ery + concurrency -RgtS 2 + $oader -RgtS d>ce$ery+$oaders+D>angoMoader + $ogfi$e -RgtS 7stderr8OHFFK

+ e6ents -RgtS KF + beat -RgtS KF + tas@s -RgtS + ce$erytest+$o$+tas@s+test 72'-'--'--P '*:;3:33#2;8: HFFK/Noo$Qor@er-28 chi$d process ca$$ing se$f+run"% 72'-'--'--P '*:;3:33#2;P: HFFK/Noo$Qor@er-;8 chi$d process ca$$ing se$f+run"% 72'-'--'--P '*:;3:33#23-: QAJFHFG/:ainNrocess8 ce$eryOprogram-8 has started+ 72'-'--'--P '*:;3:33#23-: HFFK/Beat8 chi$d process ca$$ing se$f+run"% 72'-'--'--P '*:;3:33#23-: HFFK/Beat8 0e$erybeat: Ctarting+++ 72'-'--'--P '*:;*:''#*;T: HFFK/:ainNrocess8 Got tas@ from bro@er: ce$erytest+$o$+tas@s+test722d-*afT-8feP-3acd-bdde-'<2<*''3eb*'8 72'-'--'--P '*:;*:''#T<': QAJFHFG/Noo$Qor@er-;8 firing test tas@ 72'-'--'--P '*:;*:'-#'88: HFFK/:ainNrocess8 Tas@ ce$erytest+$o$+tas@s+test722d-*afT-8feP-3acd-bdde-'<2<*''3eb*'8 processed: Fone

-ronto ele esta rodando% 9 ,elery um pro5eto muito bom s+ que ainda estamos enfrentando alguns bugs com processos pesado o pior que ele para de processar e n#o esta dando nem um retorno, por isso antes colocar em produ"#o teste sua aplica"#o onde o ,elery vai rodar%

Hmp$ementando form de fi$tro numa MistUie( "Jesposta para um t1pico na D>ango Brasi$%

forms.py -ython
# https://groups+goog$e+com/forum/Vfromgroups#!topic/d>ango-brasi$/d<gU-UP?rgU from d>ango+forms import :ode$Form from minha!app+mode$s import :eu:ode$ c$ass :euForm":ode$Form%: c$ass :eta: mode$ & :eu:ode$

views.py -ython
# https://groups+goog$e+com/forum/Vfromgroups#!topic/d>ango-brasi$/d<gU-UP?rgU from d>ango+6ie(s+generic import MistUie( from d>ango+db+mode$s import W from minha!app+forms import :euForm from minha!app+mode$s import :eu:ode$ c$ass :inhaMistUie("MistUie(%: mode$ & :eu:ode$ temp$ate!name & Emeu!temp$ate+htm$E conte4t!ob>ect!name & Eresu$tadosE def get!?ueryset"se$f# **@(args%: fi$tro- & se$f+re?uest+G5T+get"Eparametro-E# EE% fi$tro2 & se$f+re?uest+G5T+get"Eparametro2E# EE% return :eu:ode$+ob>ects+fi$ter"W"0A:NK-!!icontains&fi$tro-% X W"0A:NK2!!icontains&fi$tro2%% def get!conte4t!data"se$f# **@(args%: conte4t & super":inhaMistUie(# se$f%+get!conte4t!data"**@(args% conte4t7EmeuformE8 & :euForm return conte4t se$ect name&Emyse$ectE on0hange&.this+form+submit"%S.=

& quic? solution to integrate this into your form @ould involve adding a attribute to your @idget%
(idgetdays & forms+:ode$0hoiceFie$d"?ueryset&Day+ob>ects+a$$"%+order!by"Ea$iasE%# (idget&forms+Ce$ect"attrs&D.on0hange.:Erefresh"%EI%% &forms+JadioCe$ect"attrs&DEonchangeE: Ethis+form+submit"%SEI%

Filtered Menus in Django


-osted on by 4am <% ,lar?e Eor a recent pro5ect 2 needed to ma?e some classic filtered menus% 3his is the typical cascading choice type @here a selection in one field of a form filters the available options in a subsequent field% 2 cam across several methods to get this done in A5ango, most notably the Aa5ax pro5ect% Fo@ever, 2 @as expecting that this @ould be a one-off a5ax call and 2 had recently done me some a5ax learning so 2 figured 2 @ould 5ust @rite it myself% Eirst off 2 need to define my model% models.py' 1 c$ass 0ountry"mode$s+:ode$%: name & mode$s+0harFie$d"uni?ue&True# ma4!$ength&2**#% 2 G capita$ & mode$s+0harFie$d"uni?ue&True# ma4!$ength&2**% ;o@ 2 need a form% forms.py' 1 from d>ango import forms 2 G c$ass CearchForm"forms+Form%: country & forms+:ode$0hoiceFie$d" 4 ?ueryset&0ountry+ob>ects+6a$ues!$ist"EnameE%# H empty!$abe$&EFot CpecifiedE# I (idget&forms+Ce$ect"attrs&D J K .on0hange.:Eget0ity"%EI% 8 % 10 11 city & forms+:ode$0hoiceFie$d" 12 ?ueryset&0ountry+ob>ects+6a$ues!$ist"EcityE%# 1G empty!$abe$&EFot CpecifiedE 14 % ;ot much of a form but sufficient for demonstration purposes% & couple of things to note here' 1% 2 set up the querysets as 6a$ue!$ists for each field% 3his means that our default is to display a full list of both country name and city in our unmodified select boxes% 2n case the 5avascript brea?s or is disabled, 2 @ill still be able to ma?e our selection% Lust not so elegantly% 2% 2 use the Qidget+attrs argument to t@ea? the html output of the capital select field% 4pecifying additional attributes in the form is a very po@erful method for adding specific mar?up to the form fields% 2n this case 2 add an onchange event handler% 3hen of course the template @hich holds the html output of the form% index.html'

1 )di6 id&.se$ect!form.= )form action&.D/ ur$ search /I. method&.post.=D/ csrf!to@en /I 2 D/ for fie$d in form /I G )di6 c$ass&.fie$d!(rapper.= 4 DD fie$d+errors II H DD fie$d+$abe$!tag II DD fie$d II I J )/di6= K D/ endfor /I 8 )input type&.submit. name&.submit. 6a$ue&.Cearch. /= 10 )/form= 11 )/di6= ;o@, in my urls%py 2 need to specify t@o url patterns% 9ne for the template and one for the a5ax call% urls.py: 1 ur$"rEY9E# 6ie(s+form# name&EformE%# 2 ur$"rEYfind!cities/9E# 6ie(s+find!cities# name&Efind!citiesE%# &nd in the vie@s 2 ma?e t@o vie@s @hich handle the template and the a5ax call respectively% views.py: 1 2 G 4 H I J K find!cities "a>a4 processor% 8 # 10 def find!cities"re?uest# ?s&Fone%: if ?s is Fone: 11 ?s & 0ountry+ob>ects+6a$ues!$ist"EcityE# f$at&True%+a$$"% 12 if re?uest+G5T+get"Ecountry!nameE%: 1G country!name&re?uest+G5T+get"Ecountry!nameE% 14 1H # create an empty $ist to ho$d the resu$ts 1I resu$ts & 78 1J ?s & 0ountry+ob>ects+6a$ues!$ist"EcityE# 1K f$at&True%+fi$ter"name&country!name%+order!by"EcityE% 18 # iterate o6er each city and append to resu$ts $ist 20 for city in ?s: 21 resu$ts+append"city% 22 # if no resu$ts found then append a re$e6ant message to 2G resu$ts $ist 24 if not resu$ts: 2H # if no resu$ts then dispay empty message 2I resu$ts+append"!".Fo cities found.%% 2J # return ZCKF ob>ect return [ttpJesponse"simp$e>son+dumps"resu$ts%% 3he last piece of the pu le is the a5ax call itself% ;ote that this particular method relies on j uery being installed= lin?ed to% find!cities.js' # inde4 def inde4"re?uest%: # create conte4t dictionary conte4t & DI # 6ariab$es+++ conte4t7EformE8 & CearchForm"% return render"re?uest# Einde4+htm$E# conte4t%

1 // set up a ne( \:M[ttpJe?uest 6ariab$e 2 6ar re?uest & fa$seS G try D 4 re?uest & ne( \:M[ttpJe?uest"%S H I catch "trymicrosoft% D I try D J re?uest & ne( Acti6e\Kb>ect".:s4m$2+\:M[TTN.%S K I catch "othermicrosoft% D 8 try D 10 re?uest & ne( Acti6e\Kb>ect".:icrosoft+\:M[TTN.%S 11 I catch "fai$ed% D 12 re?uest & fa$seS 1G I 14 I 1H I 1I 1J if "!re?uest% 1K a$ert".5rror initia$i]ing \:M[ttpJe?uest!.%S 18 20 function get0ity"% D 21 6ar countryFame & document+get5$ementByHd".country.%+6a$ueS 22 6ar ur$ & .http://$oca$host:8'''/co$$ections/find!citiesV 2G country!name&. , escape"countryFame%S 24 re?uest+open".G5T.# ur$# true%S 2H re?uest+onreadystatechange & updateNageS 2I re?uest+send"nu$$%S 2J I 2K 28 // (hat to do (hen http ready state changes G0 function updateNage"% D G1 if "re?uest+readyCtate && 3% D G2 if "re?uest+status && 2''% D GG G4 // get response array GH 6ar data & ZCKF+parse"re?uest+responseTe4t%S GI update!se$ect"9"Ese$ect7name&city8E%# data%S GJ I GK // some error chec@ing G8 e$se if "re?uest+status && 3'3% D 40 a$ert".Je?uest ur$ does not e4ist.%S 41 I 42 e$se D 4G a$ert".5rror: status code is . , re?uest+status%S 44 I 4H I 4I I 4J 4K 48 function update!se$ect"se$ect# data% D se$ect+find"EoptionE%+remo6e"%S H0 for "6ar @ in data% D H1 se$ect+append"9"E)option 6a$ue&.E,data7@8,E.=E,data7@8 H2 ,E)/option=E%%S

I I 3his is pretty straightfor@ard &L&M% 1% &n \:M[ttpJe?uest"% is instantiated, @ith a special method of instantiating for 2/ 0oh the 5oyN1% 2% 3hen the get0ity"% function gets the value selected in the Country field @hich it then passes along @ith the url for our a5ax vie@ to re?uest+open"%% 3he final parameter, @hen set to true, requests an asynchronous connection 0thus ma?ing this &5ax1% :hen the readystate changes the updateNage function is called 0note the lac? of parenthesis @hen calling the function% G% 3he updateNage"% function chec?s that the readystate has changed to 4 @hich means the response from the server is complete% 2t then chec?s that the re?uest+status is 200 0as opposed to 404 or H001% 2f all is good then @e can grab the L49; data from the re?uest+responseTe4t and pass it to the updateCe$ect function along @ith the name of the select target 0in this case city1% 4% Einally @e reach our updateCe$ect"% function @hich first removes any existing options form the city select field% &s a default this holds only the string "ot #pecified @hich 2 defined in the forms%py as empty!$abe$&EFot CpecifiedE% 3he function then iterates through the L49; data array and populates the select function appropriately% 9f course if no results @ere found then there @ill be only one element in the dump, namely the $"o cities found% fallbac? string% &nd thatOs it% 3his clearly lays out the moving parts associated @ith this common tas?% 9f course this code could be @ritten more concisely% Eor example @e could use only one vie@ P url @hich handles both the template and the a5ax call, @here @e 5ust pass an argument to the vie@ @hich ma?es it execute the a5ax call in an if loop, or return the template as a default%

#etup Memcached for Django in a Development &nvironment


-osted on 4o 2 5ust started adding a caching layer for a large A5ango pro5ect and found that the initial setup @as much less painful than 2 expected% Fere are the steps so far' 1% install memcached system-@ide%
sudo apt-get install memcached

2% install python bindings


pip install python-memcached

G% &dd cache settings to settings%py 0or local settings for specific configuration1% 4et the location to local ip address%
CACHES = { 'default': { 'BACKEN ':'d!ango"co#e"cache"$ac%ends"memcached"&emcachedCache'' '()CA*+)N':',-."/"/",:,,-,,'' 0 0

4% 3est that everything @or?s%


f#om d!ango"co#e"cache impo#t cache cache"get1'foo'2 cache"set1'foo'' '$a#'2 cache"get1'foo'2 '$a#'

Erom here the A5ango cache settings can be used to cache the @hole site, per-vie@ or template framgents' https'==docs%d5angopro5ect%com=en=dev=topics=cache= -osted in A5ango = >eave a comment

Django extensions
-osted on 2 5ust started using d5ango-extensions and it is a really simple @ay to add some really useful features to d5ango% 2nstallation is really straightfor@ard' 9 pip insta$$ d>ango-e4tensions or 9 easy!insta$$ d>ango-e4tensions 2 did also needed to install pygraphvi ' 9 apt-get insta$$ python-pygraph6i] 3hen add d5ango-extensions to the '"#()**&D )PP#'

1 HFCTAMM5D!ANNC & " +++ 2 Ed>ango!e4tensionsE# G 4 +++ H% 3he first command 2 @anted to use @as the graph!models command @hich basically creates a graphical relational diagram of the applications in the pro5ect% 3o visuali e the @hole pro5ect @ith grouping by application' 9 +/manage+py graph!mode$s -a -g -o my!pro>ect+png and for specific apps' 9 +/manage+py graph!mode$s my!app X dot -Tpng -o my!app+png 3his is a really nice @ay to let yourself and others visuali e the db schema at a glance% &nother insanely useful feature is django shell!plus% &mong other things this feature autoloads you models into the shell' 9 +/manage+py she$$!p$us Qou should see all the models loaded before the prompt% 4o no more === from myapp+mode$s import * 3here are plenty of other features described in the documentation, but even in the short time 2 have played @ith this pac?age 2 can tell it @ill be an indispensable tool in my d5ango toolbox%

Multiple database implementation in Django


-osted on ;e@ @ith A5ango 1%2 came multiple database support% 2t 5ust so happened that 2 am putting together such a pro5ect and had need of this feature% 2t @as one of those tas?s @hich seemed dauntingly complicated at first, though @hen 2 got it @or?ing, seemed surprisingly easy% Fo@ever, the documentation, of @hich the official docs are the best offering, left me scratching my head for some time% 4o in this post 2 aim to lay things out a little more clearly for someone @ho is attempting this for the first time, and of course as a reference for myself% My use case may or may not be typical but 2 @ould bet it is not rare% 2 had t@o independent A5ango pro5ects @hich had an app each% 3he time came @hen these needed to be t@o apps in a larger pro5ect, but they still required discrete databases% 4o 2 rolled one into the other and dealt @ith my need for multi-db support by using the manual method% 3his definitely @or?ed but @as more of a stop-gap until 2 @or?ed up courage to tac?le the automatic routing method% My primary motivation @as that 2 needed to have access to both apps in the admin, @hich required the automatic method% &side from that, the frequency of the using method such as' item & Htem+ob>ects+using"Emy!db!2E%+a$$"% @as getting ugly and daunting to ?eep trac? of% 4o @hen it came to it, implementing automatic routing came do@n to three main steps' 1% Aefine database connections in myproject+settings.py'

1 DATABAC5C & D Edefau$tE: D 2 EFA:5E: Edb-E# G E5FGHF5E: Ed>ango+db+bac@ends+mys?$E# 4 EUC5JE: Emyuser-E# H ENACCQKJDE: Emypass-E# I I# J K Emy!db!2E: D 8 EFA:5E: Edb2E# 10 E5FGHF5E: Ed>ango+db+bac@ends+mys?$E# 11 EUC5JE: Emyuser2E# 12 ENACCQKJDE: Emypass2E 1G I 14 I 2% Aefine router in myproject+myapp,+router.py' c$ass :yApp2Jouter"ob>ect%: ... 1 A router to contro$ a$$ database operations on mode$s 2 in G the myapp2 app$ication 4 ... H I def db!for!read"se$f# mode$# **hints%: J ... K Noint a$$ operations on myapp2 mode$s to Emy!db!2E 8 ... 10 if mode$+!meta+app!$abe$ && Emyapp2E: 11 return Emy!db!2E 12 return Fone 1G 14 def db!for!(rite"se$f# mode$# **hints%: 1H ... 1I Noint a$$ operations on myapp mode$s to EotherE 1J 1K ... 18 if mode$+!meta+app!$abe$ && Emyapp2E: 20 return Emy!db!2E 21 return Fone 22 2G def a$$o(!syncdb"se$f# db# mode$%: 24 ... 2H :a@e sure the Emyapp2E app on$y appears on the 2I EotherE db 2J ... 2K if db && Emy!db!2E: 28 return mode$+!meta+app!$abe$ && Emyapp2E G0 e$if mode$+!meta+app!$abe$ && Emyapp2E: G1 return Fa$se return Fone 3his is pretty much a copy and paste 5ob from the official example% 3he one ?ey point left out @as @here to define this% 2t turns out that myapp,+models.py is not the right place and something li?e myapp,+router.py isN

G% ;o@ all that remains is to tell our pro5ect about the router% 2n myproject+settings.py add' DATABAC5!JKUT5JC & 7Emyapp+routers+:yApp2JouterE#8 Qou can see that throughout 2 am only concerned @ith my second app 0myapp21% 3his is because, for the time being myapp1 @ould use the default database router @hich comes out of the box @ith A5ango% 9f course at some point 2 may @ell need another router for that app or an additional one, @hich is @hen 2 could define 2 ne@ router, hoo? it up to said app and add the router path to the settings% 2 am sure that there are a number of unexplored nuances to @or?ing @ith multiple databases in A5ango, and 2 admit 2 have not delved into the underlying code of this functionality, but for the time being everything seems to @or?s as required% 3he really impressive part @as seeing both apps in the admin @ithout errors% 3han?s A5ango%
from d>ango+contrib+auth+decorators import $ogin!re?uired from d>ango+uti$s+decorators import method!decorator c$ass MoginJe?uired:i4in"ob>ect%: Omethod!decorator"$ogin!re?uired% def dispatch"se$f# re?uest# *args# **@(args%: return super"MoginJe?uired:i4in# se$f%+dispatch"re?uest# *args# **@(args%

:henever you @ant a vie@ to be protected you 5ust add the appropriate mixin'
c$ass ComeNrotectedUie(Uie("MoginJe?uired:i4in# Temp$ateUie(%: temp$ate!name & Einde4+htm$E

Potrebbero piacerti anche