为什么我的Django模板没有渲染ModelForm的id或pk字段?

5
在Django 1.10中,我正在使用数据库中的记录来预填充模板中的ModelForm,以便在表单中编辑该记录。但是,当我要呈现表单的HTML时,它不显示id(或pk)字段。我想把id放在一个隐藏的<input>标签中,这样当表单提交到后端时,后端就知道要编辑哪条记录。我的Web应用程序在URL中没有id。
以下是我的models.py:
from django.db import models

class MyModel(models.Model):
    name = models.CharField(max_length=50)
    phone = models.CharField(max_length=50)

在数据库中,我添加了一个名为'Alice'和电话号码为'212-555-5555'的MyModel记录。它的id/主键是1
这是我的forms.py文件:
from django import forms
from . import models

class TestForm(forms.ModelForm):
    class Meta:
        model = models.MyModel
        fields = ['id', 'name', 'phone']

这是我的views.py文件:

from django.shortcuts import render
from . import forms, models

def test_page(request):
    m = models.MyModel.objects.get(name='Alice')
    prepopulatedForm = forms.TestForm(instance=m)
    return render(request, 'testproject/test_template.html', {'form': prepopulatedForm})

这是我的test_template.html文件:

<h1>Test Page</h1>
{{ form }}

这将在页面上呈现表单,预填有'Alice''212-555-5555'

<h1>Test Page</h1>
<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" maxlength="50" name="name" type="text" value="Alice" required /></td></tr>
<tr><th><label for="id_phone">Phone:</label></th><td><input id="id_phone" maxlength="50" name="phone" type="text" value="212-555-5555" required /></td></tr>

我的问题是,为什么这个表格中没有显示id/主键列?我无法在模板中使用以下代码进行渲染:
```html ```
<h1>Test Page</h1>
{{ form.id }}
{{ form.name }}
{{ form.phone }}

这会在id为的位置呈现一个空白:
<h1>Test Page</h1>

<input id="id_name" maxlength="50" name="name" type="text" value="Alice" required />
<input id="id_phone" maxlength="50" name="phone" type="text" value="212-555-5555" required />

我可以从运行python manage.py shell命令中看到记录实际上已经存在:
>>> from testproject import models
>>> m = models.MyModel.objects.get(name='Alice')
>>> m.id
1

在 forms.py 中,将 fields 设置为 ['id', 'name', 'phone']['pk', 'name', 'phone'] 不会引起任何错误。但是,如果我故意添加一个不存在的字段名,例如 ['NOT_REAL_FIELD', 'name', 'phone'],那么运行 python manage.py runserver 将会产生一个错误:
  File "C:\Users\Al\venvs\tas_env\lib\site-packages\django\forms\models.py", line 257, in __new__
    raise FieldError(message)
django.core.exceptions.FieldError: Unknown field(s) (NOT_REAL_FIELD) specified for MyModel

我知道在ModelForm中必须使用合法的'id'/'pk'字段。

为什么我的Django模板不能渲染ModelForm的id或pk字段?

最终,我想在表单中包含主键作为隐藏输入,以便可以编辑数据库中的记录。请注意,我不关心ModelAdmin,因为我试图在用户可查看的模板中显示它,而不是在管理面板中。PK是只读的也不影响,只需要在模板中呈现即可。


你为什么想让id字段可编辑?在Django中,通常的方法是将id包含在url中,例如/mymodel/<pk>/,然后在视图中获取要编辑的对象,例如MyModel.objects.get(pk=pk) - Alasdair
我想把主键放在一个隐藏的<input>标签中,这样当表单提交时,后端就知道在提交表单时要编辑哪个记录。我的URL没有<用户物品>的主键,而是"/<用户>/<用户物品>"。我需要使用这两个信息来检索记录吗? - Al Sweigart
3个回答

8

使用{{ form.initial.id }}访问id如何?

从我查看ModelForm元类的结果来看,form.initial的填充方式与创建表单属性(例如form.nameform.phone)略有不同。因此基本上它涉及Django元类magic的细节...

更具体地说,创建表单时似乎调用了model_to_dict来从传递的模型实例中获取数据。但是直到调用fields_for_model表单实例才可以将模型字段作为类属性访问。 我猜id可能被从fields_for_model中考虑的字段中排除了。这里也引发了您提到的不可编辑字段异常。


这个确实有效!奇怪的是,{{ form.initial.pk }} 是空的。虽然这并没有回答我的原始问题,但它比我当前的解决方法稍微好一点。我该搜索什么来了解 .initial 是什么?它是否与“动态初始值”相关或是另一个概念?我想找出在模板中呈现 PK 的最佳实践是什么。 - Al Sweigart
刚刚添加了一些更多的信息。我通过查看ModelForm源代码,特别是元类部分,能够大致了解情况。 - scuerda

4
晚回答,但可以帮助其他人:
{{ form.instance.id }}

这对我有效


3

id字段自动设置为editable=False,这意味着默认情况下它不会出现在任何模型表单中。

但是没有必要将id放入隐藏字段中。如果您转到URL以编辑对象,并且该URL显示一个表单,则应将其提交回相同的URL - 在这种情况下,您仍然可以在URL中找到id。


1
我认为这不是解决方案。当我在“name”或“phone”字段上设置editable=False时,只要我运行python manage.py runserver就会收到错误消息:django.core.exceptions.FieldError: 'phone' cannot be specified for MyModel model form as it is a non-editable field但是,在“id”或“pk”字段上我不会收到此错误。 - Al Sweigart
在我的 Web 应用程序中,我没有在 URL 中使用主键。URL 是 /<user>/<thing>,而不是使用用户的 thing 的 ID,因此无法从 URL 中获取它。 - Al Sweigart

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接