Django中一对一数据库关系的正确模型字段

时间:2014-10-22 17:19:20

标签: django database orm foreign-key-relationship

我的问题是我的应用不允许我更新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))

1 个答案:

答案 0 :(得分:0)

在POST上实例化表单时,您没有传递实例。

if request.method == 'POST':
    form = InstrumentForm(request.POST, instance=instrument)