Decorators mit django

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
d3f3nd3r
User
Beiträge: 40
Registriert: Montag 19. November 2007, 20:17

Dienstag 15. April 2008, 12:57

heo

ich würde gerne meine eigenen decorators wie @login_required basteln nur leider bin ich aus der python dokumentation für decorators nicht wirklich schlau geweorden

Code: Alles auswählen

from django.http import HttpResponseRedirect

def login_test():
		
	try:
		if request.session["current_user"].is_active() :
			return HttpResponseRedirect("/thlab_web/required_Login/FUNTZT/")
		else :
			return HttpResponseRedirect("/thlab_web/accounts/login/")

	except KeyError:
		return HttpResponseRedirect("/thlab_web/accounts/login/")

login_required = login_test()
so hätt ich mir das gedacht, aber ich bekommen folgende Fehlermeldung :

Code: Alles auswählen

Exception Type:  	NameError
Exception Value: 	global name 'request' is not defined
Exception Location: 	/home/d3f3nd3r/d3f3nd3rs-code/thlab_web/../thlab_web/core/decorators.py in ?, line 14
kann mir da jemand helfen
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 15. April 2008, 13:13

Du weißt aber, das es den schon gibt: http://www.djangoproject.com/documentat ... -decorator

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Dienstag 15. April 2008, 13:42

Dein Beispiel dürfte so nicht klappen.

(unparametrisierte) Dekoratoren sind Funktionen, die als Argument eine andere funktion entgegennehmen, und eine funktion zurückgeben.

beispiel

Code: Alles auswählen

def add_one(func):
   def neue_funktion(*args):
       return func(*args) + 1
   return neue_funktion

@add_one
def test(a,b):
   return a + b
durch den dekorator "add_one" wird test durch eine neue funktion ersetzt, nämlich die "neue_funktion"
d3f3nd3r
User
Beiträge: 40
Registriert: Montag 19. November 2007, 20:17

Mittwoch 16. April 2008, 19:47

gut so halbwegs hab ich das verstanden.....

und ja ich weiß, dass dieser decorator in django.contrib.auth.decorators vorhanden ist, nur ich benutzte nicht das standard django user model....

Und ich bin gerade dabei, die wichtigsten funktionen bereitzustellen und das mit dem decorator ist sehr praktisch.

aber noch eine frage zu meiner (durch viel vodooo magie funktionierenden) Variante (angepasste django funktion) :

Code: Alles auswählen

def user_passes_test(test_func):

	def _dec(view_func):
		def _checklogin(request, *args, **kwargs):
			
			try :
				if test_func(request.session["current_user"]):
					return view_func(request, *args, **kwargs)				
				return HttpResponseRedirect('/thlab_web/accounts/login')

			except KeyError:
				return HttpResponseRedirect('/thlab_web/accounts/login')
		
		return _checklogin
	return _dec

login_required = user_passes_test(lambda u: u.is_active())
welchen inhalt haben *args, **kwargs und was ist view_func (ich werde auf die richtige seite weitergeleitet, aber ich hab nirgendsd view_func als redirect definiert....??)

wäre auch für dokumentationslinks dankbar... (bin leider noch kein richtiger python profi (kenne nur die basics..... und auch keine django guru....)
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Mittwoch 16. April 2008, 20:54

aber noch eine frage zu meiner (durch viel vodooo magie funktionierenden) Variante (angepasste django funktion) :
((code gesnipped))
welchen inhalt haben *args, **kwargs und was ist view_func (ich werde auf die richtige seite weitergeleitet, aber ich hab nirgendsd view_func als redirect definiert....??)
ei, das beispiel, was du da hast, ist ziemlich magisch ;). Da soll der Graham nochmal von Lisps überragender Metaprogrammierung labern...

Erst noch kurz, zum einfacheren Beschreiben:

Code: Alles auswählen

@decorator
def x():
  pass
ist nur eine andere Art, dies hier zu schreiben:

Code: Alles auswählen

def x():
  pass
x = decorator(x)
Ok, zum eigentlichen Problem, fangen wir mal hinten an.
"login_required" soll ein Dekorator sein, den wir im stil

Code: Alles auswählen

@login_required
def meine_geheime_seite(request, a, b):
  #...
nutzen wollen.
Also muss user_passes_test(..) einen Dekorator zurückliefern. "user_passes_test" ist also quasi ein dekorator-generator.

Gucken wir uns also user_passes_test an: user_passes_test definiert eine Funktion _dec (den Dekorator), der zurückgegeben wird.

Der Dekorator _dec tauscht die eigentliche view_func (also in meinem beispiel z.B. "meine_geheime_seite") gegen eine eigene Funktion aus, nämlich die Funktion _checklogin.

Diese Funktion, die nun anstelle der eigentlichen view_func steht, überprüft anhand der test_func, on sie den user umeilten soll (HttpResponseRedirect), oder doch die eigentliche view aufrufen möchte.

somit heist die zeile:

Code: Alles auswählen

login_required = user_passes_test(lambda u: u.is_active())
in umgangssprache: "erstelle einen Dekorator, der anhand der Funktion 'lambda u: u.is_active()' entscheidet, ob er die eigentliche View zeigen soll oder umleiten, und nenne diesen Dekorator user_passes_test
wäre auch für dokumentationslinks dankbar... (bin leider noch kein richtiger python profi (kenne nur die basics..... und auch keine django guru....)
Wenn du dekoratoren halbwegs verstanden hast, hasst du schon einen recht beachtlichen Weg geschafft.[/code]
d3f3nd3r
User
Beiträge: 40
Registriert: Montag 19. November 2007, 20:17

Sonntag 20. April 2008, 17:11

danke für deine ausführliche erklärung
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 21. April 2008, 09:48

Was ich in dem zusammenhang doof finde: Django bietet mit @login_required quasi eine black list. Ich hätte gern aber sowas wie @login_not_required um ehr eine white liste aufzubauen...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 21. April 2008, 12:55

Dann lass doch den Dekorator weg :)
My god, it's full of CARs! | Leonidasvoice vs Modvoice
lunar

Montag 21. April 2008, 13:09

Leonidas hat geschrieben:Dann lass doch den Dekorator weg :)
Das ist wohl nicht das, was er will, denn es löst nicht das grundlegende Problem, den Login für alle Seiten außer für ein paar bestimmte erforderlich zu machen.
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Montag 21. April 2008, 14:37

lunar hat geschrieben:
Leonidas hat geschrieben:Dann lass doch den Dekorator weg :)
Das ist wohl nicht das, was er will, denn es löst nicht das grundlegende Problem, den Login für alle Seiten außer für ein paar bestimmte erforderlich zu machen.
Ich kenne Django nicht so gut, aber ich glaube, dass das nicht so einfach möglich ist, da es bedeuten würde, dass djangos dispatcher sich ums login kümmert, und nicht, wie jetzt, die view selber.
Mit etwas offenem, z.B. werkzeug ist sowas recht einfach zu machen, da man den Dispatcher selber baut.

P.S: ich glaube aber, das ist überschätzt. Ich habe (in PHP, möge es in der Hölle schmoren, wenn es endlich mal wirklich stirbt) einige selbstgebastelte Frameworks genutz, die auch "open by default" waren, und die Befürchtung, dass ich es an sicherheitskritischen Stellen vergesse, hat sich als ähnlich falsch herausgestelllt, wie die Befürchtung, dass man in python dauernd Fehler macht, weil man die Variablen nicht deklarieren muss.
Antworten