• django formset bug?


    碰到了一个郁闷的问题,修改inlineformset时,全部删掉子表,再新增一行时,报错.

    背景: 用django配合jq做动态表格,实现用js动态添加/删除行,并通过inlineformset更新到数据库.示例代码在这里:https://github.com/TommyU/dynamic_form/

    重现步骤:

    1. 新增一个待办事宜,并设置清单,如下:

    2. submit

    3. 回头修改(通过列表的update按钮进入),把以上数据全部清空(圈起来的),只留下最后一行空白行,提交.

    然后报错了,如下

    Environment:
    
    
    Request Method: POST
    Request URL: http://127.0.0.1:8000/todolist/update/14/
    
    Django Version: 1.6.5
    Python Version: 2.7.5
    Installed Applications:
    ('django.contrib.admin',
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
     'django.contrib.messages',
     'django.contrib.staticfiles',
     'south',
     'eForm',
     'formset_test')
    Installed Middleware:
    ('django.contrib.sessions.middleware.SessionMiddleware',
     'django.middleware.common.CommonMiddleware',
     'django.middleware.csrf.CsrfViewMiddleware',
     'django.contrib.auth.middleware.AuthenticationMiddleware',
     'django.contrib.messages.middleware.MessageMiddleware',
     'django.middleware.clickjacking.XFrameOptionsMiddleware',
     'django.middleware.locale.LocaleMiddleware')
    
    
    Traceback:
    File "C:Python27libsite-packagesdjangocorehandlersase.py" in get_response
      112.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
    File "C:Python27libsite-packagesdjangoviewsgenericase.py" in view
      69.             return self.dispatch(request, *args, **kwargs)
    File "C:Python27libsite-packagesdjangoviewsgenericase.py" in dispatch
      87.         return handler(request, *args, **kwargs)
    File "C:Python27libsite-packagesdjangoviewsgenericedit.py" in post
      228.         return super(BaseUpdateView, self).post(request, *args, **kwargs)
    File "C:Python27libsite-packagesdjangoviewsgenericedit.py" in post
      171.             return self.form_valid(form)
    File "E:/workspace/django_test/mysite/mysiteformset_testviews.py" in form_valid
      31.         if iter_form.is_valid():
    File "C:Python27libsite-packagesdjangoformsformsets.py" in is_valid
      292.         err = self.errors
    File "C:Python27libsite-packagesdjangoformsformsets.py" in errors
      267.             self.full_clean()
    File "C:Python27libsite-packagesdjangoformsformsets.py" in full_clean
      314.             form = self.forms[i]
    File "C:Python27libsite-packagesdjangoutilsfunctional.py" in __get__
      49.         res = instance.__dict__[self.func.__name__] = self.func(instance)
    File "C:Python27libsite-packagesdjangoformsformsets.py" in forms
      133.         forms = [self._construct_form(i) for i in xrange(self.total_form_count())]
    File "C:Python27libsite-packagesdjangoformsmodels.py" in _construct_form
      848.         form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs)
    File "C:Python27libsite-packagesdjangoformsmodels.py" in _construct_form
      567.                 connection=connections[self.get_queryset().db])
    File "C:Python27libsite-packagesdjangodbmodelsfields\__init__.py" in get_db_prep_lookup
      387.             value = self.get_prep_lookup(lookup_type, value)
    File "C:Python27libsite-packagesdjangodbmodelsfields\__init__.py" in get_prep_lookup
      369.             return self.get_prep_value(value)
    File "C:Python27libsite-packagesdjangodbmodelsfields\__init__.py" in get_prep_value
      613.         return int(value)
    
    Exception Type: ValueError at /todolist/update/14/
    Exception Value: invalid literal for int() with base 10: ''
    

      

     post数据:

    似乎一定要求子表必需有一行数据是原表的?

    update对应的python代码如下:

    class todo_listUpdateView(UpdateView):
        model = todo_list
        template_name = 'todo_list_create.html'
        success_url = '/todolist/'
        form_class = todo_listForm
    
        def get_context_data(self, **kwargs):
            context = super(todo_listUpdateView, self).get_context_data(**kwargs)
            if self.request.POST:
                context.update(item_form = todo_itemSet(self.request.POST))
            else:
                context.update(item_form = todo_itemSet(instance =todo_list.objects.get(pk = self.kwargs.get('pk',False))))
            return  context
    
        def form_valid(self, form):
            iter_form = todo_itemSet(self.request.POST,instance=self.object)
            if iter_form.is_valid():
                self.object = form.save()
                iter_form.instance = self.object
                iter_form.save()
                return HttpResponseRedirect(self.get_success_url())
            else:
                return self.render_to_response(self.get_context_data())
    

      

     ============================经过调试,分析,看文档===================

    发现如果用js直接把数据行给remove掉,如果全部move了,会报错.(原因有待分析).

    其实,对于inlineformset的更新操作,django有做一个很不错的设计,直接给标志位打标记即可,什么都不用处理.核心修改如下:

    1. 从create模板中分离出update模板(因为js处理不同)

    2. 将update模板的deleteForm函数修改为:

        function deleteForm(btn, prefix) {
            $(".delete_mark",$(btn).parent().parent()).children().attr("checked","checked")
            $(btn).parents('.item').hide();
            return false;
        }
    

     同时update模板添加标志位:

    <p class="delete_mark">{{form.DELETE}}</p>
    

     py代码不用修改,就这么简单!(其实django都处理好了,有时间要分析下)

    ===============备注===================

    重现以上bug的方法是将todo_listUpdateView的template_name修改为"todo_list_create.html",如下图所示:

  • 相关阅读:
    Android Loader异步装载
    Android 清除本地缓存
    Android 小知识
    Android 百度地图用法
    ANDROID笔记:四大组件之广播
    Android扩展:一个自动findViewById的小工具
    ANDROID笔记:基于handle的异步请求网络数据的一种方法
    ANDROID笔记:多线程断点下载
    ANDROID笔记:AIDL介绍
    ANDROID笔记:activity通过ContentProvider传值(仿调用系统图片浏览器过程)
  • 原文地址:https://www.cnblogs.com/Tommy-Yu/p/3939749.html
Copyright © 2020-2023  润新知