2017-10-15 2 views
0

Je voudrais de l'aide ou des conseils sur la façon de tester les erreurs dans l'un de mes formulaires Django. Il est responsable de s'assurer que l'utilisateur entre un ID de session valide qui est utilisé comme un jeton d'authentification pour une API tierce. Les ID valides ont 32 caractères et sont alphanumériques.Pourquoi Django AssertFormError lance-t-il un TypeError: l'argument de type 'property' n'est pas itérable?

J'ai choisi une approche qui valide le champ, plutôt que le modèle.

Lorsque je le teste manuellement à l'aide du serveur de développement, cela fonctionne comme prévu. C'EST À DIRE. Si l'utilisateur colle une chaîne de la mauvaise longueur ou avec les caractères spéciaux, la méthode de validation du champ crée des erreurs qui sont ensuite affichées via une boucle for autour des erreurs de formulaire dans le modèle html.

Je ne comprends pas l'erreur suivante. J'ai temporairement modifié testcases.py pour prouver que les erreurs lui ont été transmises - alors pourquoi context [form] .errors est-il une 'propriété' et comment est-il arrivé?

J'utilise Django 1.10 et Python 3.5.1

====================================================================== 
ERROR: test_index_sessid_short_strings (poe.tests.TestBannerButtons) 
---------------------------------------------------------------------- 
Traceback (most recent call last): 
    File "/Users/adam.green/Documents/workspace/poe-client/poetools_project/poe/tests.py", line 105, in test_index_sessid_short_strings 
    self.assertFormError(response, 'form', "new_sessid" , 'The Session ID needs to be exactly 32 characters long') 
    File "/Users/adam.green/.virtualenvs/poe-tools/lib/python3.5/site-packages/django/test/testcases.py", line 421, in assertFormError 
    if field in context[form].errors: 
TypeError: argument of type 'property' is not iterable 

---------------------------------------------------------------------- 
Ran 1 test in 0.805s 

Test

def test_index_sessid_short_strings(self): 
    url = reverse('index') 
    response = self.client.post(url, {'new_sessid': "f14"}) 
    self.assertFormError(response, 'form', "new_sessid" , 'The Session ID needs to be exactly 32 characters long') 

form.py

class SessID(forms.Field): 

    def validate(self, session_id): 
     """Check if value consists only of valid emails.""" 
     # Use the parent's handling of required fields, etc. 
     super().validate(session_id) 
     if len(session_id) <32> len(session_id): 
      raise ValidationError(
            _('The Session ID needs to be exactly 32 characters long'), 
            code = 'sessid wrong length' 
           ) 
     if not re.match("^[A-Za-z0-9]*$", session_id): 
      raise ValidationError(
            _('The Session ID should only have letters and numbers, no special characters'), 
            code = 'sessid not alphanumeric' 
           )   


class ResetSessID(forms.ModelForm): 
    new_sessid = SessID() 
    #forms.CharField(widget=forms.TextInput(attrs={'class':'special', 'size': '32'})      ) 

    def __init__(self, *args, **kwargs): 
     super(ResetSessID, self).__init__(*args, **kwargs) 
     stdlogger.info("init of ResetSessID") 
     #print("dir")#, self.fields.items['new_sessid']) 
     if kwargs.get('instance'): 
      new_sessid = kwargs['instance'].new_essid 
      stdlogger.info("inner kwargs loop") 
     return super(ResetSessID, self).__init__(*args, **kwargs) 

    class Meta: 
     model = PoeAccount 
     exclude = ("acc_name", "sessid") 

    def clean(self): 
     if 'reg_button' in self.data: 
      print("amazing") 

views.py

def index(request): 
    request.session.set_test_cookie() 
    item_category_list = ItemCategory.objects.all() 
    modifications_list = FixCategory.objects.all() 
    context_dict = {} 
    if request.user.is_authenticated: 
     if request.method == 'POST': 
      form = ResetSessID(request.POST)  
      if form.is_valid(): 
       # get the right account 
       me = poe.models.PoeAccount.objects.get(
         acc_name = request.user.poeuser.poe_account_name 
         ) 
       # commit new sessid passed to here 
       # me.full_clean() 
       me.sessid = form['new_sessid'].value() 
       me.save(update_fields=['sessid']) 
       context_dict["old_sessid"] = me.sessid 
       context_dict['form'] = ResetSessID 
       response = render(request,'poe/index.html', context_dict) 
       #return response 
      else: 
       context_dict['errors'] = form.errors 
       print("form has errors", form.errors) 
       me = poe.models.PoeAccount.objects.get(
         acc_name = request.user.poeuser.poe_account_name 
         ) 
       context_dict['errors'] = form.errors 
       context_dict["old_sessid"] = me.sessid 
       context_dict['form'] = ResetSessID 
       for x, y in form.errors.items(): 
        print("errors", x, y) 
       response = render(request,'poe/index.html', context_dict) 
       #return response 

     else: 
      context_dict = {'form': ResetSessID} 
      me = poe.models.PoeAccount.objects.get(acc_name = request.user.poeuser.poe_account_name) 
      context_dict["old_sessid"] = me.sessid 

    context_dict.update({'item_categories': item_category_list, 'mods': modifications_list}) 
    # make sure the session keeps track of the number of visits 
    visits = request.session.get('visits') 
    if not visits: 
     visits = 1 
    reset_last_visit_time = False 
    last_visit = request.session.get('last_visit') 
    if last_visit: 
     last_visit_time = datetime.datetime.strptime(last_visit[:-7], "%Y-%m-%d %H:%M:%S") 
     if (datetime.datetime.now() - last_visit_time).seconds > 0: 
      # ...reassign the value of the cookie to +1 of what it was before... 
      visits = visits + 1 
      # ...and update the last visit cookie, too. 
      reset_last_visit_time = True 
    else: 
     # Cookie last_visit doesn't exist, so create it to the current date/time. 
     reset_last_visit_time = True 
    # make sure the session keeps track of time last visited 
    if reset_last_visit_time: 
     request.session['last_visit'] = str(datetime.datetime.now()) 
     request.session['visits'] = visits 
    context_dict['visits'] = visits 

    #print("context_dict", context_dict) 
    response = render(request,'poe/index.html', context_dict) 

    return response 

Répondre

1

Cela se produit parce que vous définissez la variable de contexte form dans votre vue à votre formulaire classe elle-même, plutôt que d'un exemple de cette classe.

Remplacer:

context_dict['form'] = ResetSessID

avec:

context_dict['form'] = form

form est la variable que vous définissez juste au-dessus de votre chèque form.is_valid(). Faites-le dans les deux branches si votre bloc form.is_valid().

Même chose pour l'extérieur si le bloc ainsi:

# Not a post request 
context_dict = {'form': ResetSessID()} # Note brackets 

La vue que vous avez actuellement ne fonctionnerait pas du tout pour autant que je peux voir - il peut être utile de faire fonctionner avant d'écrire des tests pour il.

+0

génial, merci beaucoup - qui l'a réparé immédiatement. – Flicky