如何检查Django表单是否正确绑定?

时间:2013-07-10 13:25:17

标签: django django-models django-forms

情况


使用Django 1.5,我使用forms.ModelForm来让用户编辑数据库内容。但是,我无法在form.save()上获取更新数据库的表单。

我的每个模型都对应一个设置表单(应用程序是桌面软件的直接移植,用户可以在其中存储多个设置)。我需要实现重置为默认功能,所以我想到了一个默认对象(用Django灯具导入),我只会用它来重置第二个。用户只能与第二个模型进行交互。

  • pk=1指基础对象
  • pk=2指的是自定义对象

我在同一页面上有几个表单(这里只有foobar),所以基本上我打算这样做:

  • 没有POST数据
    1. 根据pk=1pk=2建立表单,具体取决于pk=2
    2. 将表单呈现给模板
  • AJAX请求,带有POST数据
    1. 获取表单内容
    2. 检查用户是否有权编辑模型(校验和)
    3. 更新模型表格POST数据
    4. 返回AJAX响应

代码


我已经放了两个调试print来说明我面临的问题。我获取的表单似乎与我的模型无关。

# Response codes to use in the template
RESPONSES = {
    200: {'code':'0xB16B00B5', 'message':'Success'},
    400: {'code':'0x8BADF00D', 'message':'Form is not valid'},
    403: {'code':'0xBAADF00D', 'message':'No permission to edit the database'},
    501: {'code':'0xDEADC0DE', 'message':'POST datas not found'},
    }

# Those are the setting labels
TYPES = {
    'foobar': {'model':FooBar, 'form':FooBarForm },
    }
def index(request):
    # Handling form datas
    if request.method == 'POST':
        response = HttpResponse(simplejson.dumps({'code':RESPONSES[501]['code']}), 'application/json')
        for label in TYPES:

            # Filtering the right form to handle
            if label in request.POST:
                model = _fetch_setting(label, mode='model')
                form = _fetch_setting(label, mode='form', post=request.POST)
                checksum = model.checksum  # Somehow, 'form.is_valid()' is altering 'model', need to backup the checksum
                if form.is_valid():

                    # The user has permission to edit the model
                    if form.cleaned_data['checksum'] == checksum:
                        if form.has_changed():
                            print form.cleaned_data['foo']  # Outputs the form data, as expected
                            form.save()
                            print model.foo  # Outputs the old data
                            model.checksum = str(uuid4()).replace('-', '')
                            model.save()
                        response = HttpResponse(simplejson.dumps({'code':RESPONSES[200]['code']}), 'application/json')

                    # This one does not
                    else:
                        response = HttpResponse(simplejson.dumps({'code':RESPONSES[403]['code']}), 'application/json')

                    break  # We are still inside the label loop

                # The form is not valid
                else:
                    response = HttpResponse(simplejson.dumps({'code':RESPONSES[400]['code']}), 'application/json')

    # Form not submitted yet, building the HTML forms
    else:
        forms = {}
        label = 'foobar'
        for label in TYPES:
            forms[label] = _fetch_setting(label, mode='form')
        context = {'errors':RESPONSES, 'forms':forms}
        response = render(request, 'home/index.html', context)

    return response
# Return a setting object (model or form) corresponding to the given label
def _fetch_setting(label, mode='model', post=None):
    try:
        result = None
        default = TYPES[label]['model'].objects.get(pk=1)
        try:
            model = TYPES[label]['model'].objects.get(pk=2)
        except TYPES[label]['model'].DoesNotExist:
            model = TYPES[label]['model'].objects.create(
                checksum = default.checksum,
                foo      = default.foo,
                bar      = default.bar,
                )
        if mode == 'model':
            result = model
        if mode == 'form':
            print model
            result = TYPES[label]['form'](data=post, instance=model)  # The 'instance' attribute doesn't seem to be applied
    except KeyError:
        result = None
    finally:
        return result

更新


07.10

当我将实例传递给与_fetch_setting绑定时,它确实有效。所以我想这个问题来自表单验证。

def _fetch_setting(label, mode='model', post=None, instance=None):
    # ...
        if mode == 'form':
            if instance:
                model = instance
            result = TYPES[label]['form'](data=post, instance=model)
    # ...

正如我在代码中评论的那样,form.is_valid()似乎改变了对象。

如果没有人提供干净的解决方案,那么会标记为已回答。

2 个答案:

答案 0 :(得分:1)

问题是,您正在使用每个form.save()

创建一个新的模型对象

您需要使用commit=False

更新相同的模型对象
if form.cleaned_data['checksum'] == checksum:
    if form.has_changed():
        print form.cleaned_data['foo']  # Outputs the form data, as expected
        model = form.save(commit=False)
        model.checksum = str(uuid4()).replace('-', '')
        model.save()

答案 1 :(得分:0)

来自精彩的手册:

  

第一次调用is_valid()或访问ModelForm触发器的错误属性时,表单验证以及模型验证。这具有清除传递给ModelForm构造函数的模型的副作用。例如,在表单上调用is_valid()会将模型上的任何日期字段转换为实际日期对象。如果表单验证失败,则只能应用某些更新。因此,您可能希望避免重用传递给表单的模型实例,尤其是在验证失败的情况下。