2009-12-02 4 views
0

Ce problème est en partie dû à mon manque de compréhension complète de la portée en python, donc je vais devoir revoir cela. De toute façon, voici un morceau de code sérieusement trivial qui continue de se briser sur mon application de test Django.Problème avec la portée de la variable en Python

Voici un extrait:

@login_required 
def someview(request): 
try: 
    usergroup = request.user.groups.all()[0].name 
except: 
    HttpResponseRedirect('/accounts/login') 

if 'client' in usergroup: 
    stafflist = ProxyUserModel.objects.filter(groups__name='staff') 

Pas de chirurgie du cerveau ici, le problème est que je reçois une erreur telle que:

File "/usr/local/django/myapp/views.py", line 18, in someview 
    if 'client' in usergroup: 

UnboundLocalError: local variable 'usergroup' referenced before assignment 

Ma question est ici, pourquoi est-usergroup non liée? Si elle n'est pas liée, cela signifie que l'instruction try a généré une exception et qu'un HttpResponseRedirect devrait arriver, mais cela ne se produit jamais. Au lieu de cela, je reçois une erreur HTTP 500, ce qui est légèrement déroutant.

Oui Je peux écrire du code plus intelligent et m'assurer que l'utilisateur qui se connecte a définitivement un groupe qui lui est associé. Mais ce n'est pas une application de production, j'essaie juste de comprendre/apprendre Python/Django. Pourquoi exactement ce qui précède se produit lorsqu'un utilisateur qui n'est pas associé à un groupe se connecte au lieu d'une redirection vers une page de connexion?

Dans ce cas, je me connecte intentionnellement en tant qu'utilisateur ne faisant pas partie d'un groupe. Cela signifie que le code ci-dessus devrait jeter une exception IndexError comme ce qui suit:

>>> somelist = [] 
>>> print somelist[0] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
IndexError: list index out of range 

Répondre

10
HttpResponseRedirect('/accounts/login') 

Vous créez mais pas le retourner. Flow continue à la ligne suivante, qui fait référence à usergroup, même s'il n'a jamais été affecté en raison de l'exception. Le except est également gênant. En général, vous ne devriez jamais attraper 'tout' (except: ou except Exception:) car il y a beaucoup de conditions étranges là-dedans que vous pourriez jeter, ce qui rend le débogage très difficile. Vous pouvez soit attraper la sous-classe d'exception spécifique qui, selon vous, se produira lorsque l'utilisateur n'est pas connecté, ou, mieux, utiliser un test if pour voir si elle est connectée. (Ce n'est pas vraiment une condition exceptionnelle.)

par ex. dans Django normalement:

if not request.user.is_authenticated(): 
    return HttpResponseRedirect('/accounts/login') 

ou si votre préoccupation est que l'utilisateur est pas dans un groupe (rendant le [0] FAIL):

groups= request.user.groups.all() 
if len(groups)==0: 
    return HttpResponseRedirect('/accounts/login') 
usergroup= groups[0].name 
+1

+1; mais notez que la dernière condition est déjà faite dans le décorateur '@login_required' – Javier

+0

J'ai fait la même erreur plus d'une fois. Pour une raison quelconque, il se sent juste comme si vous n'aviez pas besoin d'un retour, mais bien sûr vous le faites. –

+0

N'a pu être plus d'accord Peter. Je n'oublie pas que c'est une classe et non une invocation de méthode. Merci pour le crochet tout. – randombits

0

Essayez vous déplacer si une partie « client » à l'intérieur que vous essayez bloc . Soit cela ou définir usergroup = None juste au-dessus de l'essai.

0

Dans les cas où vous avez une suite try…except et que vous voulez code à exécuter ssi pas exceptions ont eu lieu, il est une bonne habitude d'écrire le code comme suit:

try: 
    # code that could fail 
except Exception1: 
    # handle exception1 
except Exception2: 
    # handle exception2 
else: # the code-that-could-fail didn't 
    # here runs the code that depends 
    # on the success of the try clause