2

情况


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

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

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

我在同一页面上有几个表格(仅foobar在这里),所以基本上这是我计划做的:

  • 无更新数据
    1. 是否已找到来自pk=1orpk=2的建筑形式pk=2
    2. 将表单呈现到模板
  • AJAX 请求,带有 POST 数据
    1. 获取表单内容
    2. 检查用户是否有权编辑模型(校验和)
    3. 更新模型表单 POST 数据
    4. 返回 AJAX 响应

代码


我放了两个 debugprint来说明我面临的问题。我获取的表格似乎没有绑定到我的模型。

# 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

当我将实例传递给与 to 绑定时,它确实有效_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()似乎改变了对象。

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

4

2 回答 2

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()
于 2013-07-10T15:17:24.683 回答
0

来自神话般的手册:

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

于 2013-07-10T15:30:28.517 回答