我的问题是我的应用不允许我更新OneToOneField
字段。这是我对我要做的事情的解释。
我正在构建一个库存应用程序,用于跟踪已借给学生的工具。学生和乐器之间始终存在一对一的数据库关系。因此,一个学生不能拥有多个乐器,反之亦然。
因此我创建了一个如下所示的Intrument模型:
class Instrument(models.Model):
instrument_type = models.CharField(max_length=100)
needs_repairs = models.BooleanField()
inventory_id = models.CharField(max_length=100)
student = models.OneToOneField(Student, null=True, blank=True, default = None)
我创建了一个允许我更新现有学生的表单,并且我尝试使用尽可能多的内置内容,这样我就不需要重新编写验证代码或HTML。所以我使用ModelForm
对象并使用is_valid()
方法验证我的输入。
以下是更新工具的POST请求示例:
csrfmiddlewaretoken=xyUBhVuQZus6XmeV2DhCmpJHwIXVmdHm&instrument_type=Viola&inventory_id=abcde&student=3
请注意,唯一具有唯一性约束的字段是student
。
所以最后,问题出在这里:当我调用is_valid()
方法时,它总是失败并显示错误,表示学生已被分配到乐器。
我的第一个想法是使用框架添加一些预验证代码,如果学生pkey没有改变则没有错误。这当然看起来很容易,但对我来说似乎有些笨拙。我假设一对一的关系会像所有其他模型字段一样“正常工作”,并且不需要特殊的验证。
但后来我读了OneToOneField
类的API文档,它似乎没有解决一对一的数据库关系 - 它似乎解决了 one-一对一的OO关系。所以我可能会一起使用错误的模型字段类型。由于这是一个如此简单的应用程序,我没有进行大量的OO建模 - 我只是担心正确的数据建模:-)
我使用错误的字段,还是以“正确”的方式解决这个问题,以便为我的学生模型添加预验证代码?
来自评论的更新
这是我对堆栈跟踪最接近的事情:
>>> data = {'instrument_type': 'Viola', 'inventory_id': 'abcde', 'student': 3, 'repairer': 1}
>>> form = InstrumentForm(data)
>>> form.is_bound
True
>>> form.is_valid()
False
>>> form.errors
{'student': [u'Instrument with this Student already exists.']}
我使用单一视图方法显示仪器详细信息并更新单个仪器。就是这样:
def instrument_detail(request, instrument_id):
try:
instrument = Instrument.objects.get(pk=instrument_id)
except Instrument.DoesNotExist:
raise Http404
# Default if not a POST
form = InstrumentForm(instance=instrument)
if request.method == 'POST':
form = InstrumentForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('instruments.views.instruments_index'))
# otherwise...
t = loader.get_template('instruments/details.html')
c = RequestContext(request, {
'instrument': instrument,
'form': form,
})
return HttpResponse(t.render(c))
答案 0 :(得分:0)
在POST上实例化表单时,您没有传递实例。
if request.method == 'POST':
form = InstrumentForm(request.POST, instance=instrument)