【问题标题】:Why does Django AssertFormError throw a TypeError: argument of type 'property' is not iterable?为什么 Django AssertFormError 会抛出 TypeError:'property' 类型的参数不可迭代?
【发布时间】:2023-04-02 10:41:01
【问题描述】:

我想要一些关于如何测试我的一个 Django 表单中的错误的帮助或建议。它负责确保用户输入有效的会话 ID,该 ID 用作 3rd 方 API 的身份验证令牌。有效 ID 长度为 32 个字符,由字母数字组成。

我选择了一种验证字段的方法,而不是模型。

当我使用开发服务器手动测试它时,它按预期工作。 IE。如果用户粘贴长度错误的字符串或带有特殊字符的字符串,则该字段的 validate 方法会创建错误,然后通过 for 循环在 html 模板中的表单错误周围显示。

我不明白以下错误。我临时修改了 testcases.py 以证明错误正在传递给它 - 那么为什么 context[form].errors 是一个“属性”以及它是如何到达那里的?

我正在使用 Django 1.10 和 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

测试

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

【问题讨论】:

    标签: django python-3.x unit-testing


    【解决方案1】:

    发生这种情况是因为您将视图中的form 上下文变量设置为表单 本身,而不是该类的实例

    替换:

    context_dict['form'] = ResetSessID

    与:

    context_dict['form'] = form

    其中form 是您在form.is_valid() 检查上方定义的变量。如果您的 form.is_valid() 块,请在两个分支中执行此操作。

    外部 if 块也是如此:

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

    据我所知,您当前拥有的视图根本不起作用 - 在为它编写测试之前让它起作用可能是值得的。

    【讨论】:

      猜你喜欢
      • 2021-02-14
      • 2017-05-03
      • 2021-10-28
      • 2020-03-14
      • 1970-01-01
      • 2021-01-15
      • 2011-10-04
      • 2019-08-24
      相关资源
      最近更新 更多