使用Django 1.5,我使用forms.ModelForm
来让用户编辑数据库内容。但是,我无法在form.save()
上获取更新数据库的表单。
我的每个模型都对应一个设置表单(应用程序是桌面软件的直接移植,用户可以在其中存储多个设置)。我需要实现重置为默认功能,所以我想到了一个默认对象(用Django灯具导入),我只会用它来重置第二个。用户只能与第二个模型进行交互。
pk=1
指基础对象pk=2
指的是自定义对象我在同一页面上有几个表单(这里只有foobar
),所以基本上我打算这样做:
pk=1
或pk=2
建立表单,具体取决于pk=2
我已经放了两个调试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
当我将实例传递给与_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()
似乎改变了对象。
如果没有人提供干净的解决方案,那么会标记为已回答。
答案 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()
会将模型上的任何日期字段转换为实际日期对象。如果表单验证失败,则只能应用某些更新。因此,您可能希望避免重用传递给表单的模型实例,尤其是在验证失败的情况下。