【问题标题】:Why doesn't my Django template render a ModelForm's id or pk field?为什么我的 Django 模板不呈现 ModelForm 的 id 或 pk 字段?
【发布时间】:2017-08-21 10:01:54
【问题描述】:

在 Django 1.10 中,我使用数据库中的记录在模板中预填充 ModelForm,以便在表单中编辑该记录。但是,当我想为表单呈现 HTML 时,它不会显示 id(或 pk)字段。我想将 id 放在隐藏的 标记中,以便在提交表单时,后端知道在提交表单时要编辑哪个记录。我的网络应用在 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 / 主键列没有出现在这种形式中?当我将它用于模板时,我也无法渲染它:

<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

所以我知道'id'/'pk' 必须是一个合法的字段才能放入 ModelForm。

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

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

【问题讨论】:

  • 为什么要让 id 字段可编辑?在 Django 中,通常的方法是在 url 中包含 id,例如/mymodel/&lt;pk&gt;/,然后在视图中获取要编辑的对象,例如MyModel.objects.get(pk=pk).
  • 我想把pk放在一个隐藏的<input>标记,因此当表单提交时,后端知道在提交表单时要编辑哪个记录。我的 URL 没有 的 pk,而是“//”。我是否必须使用这两个信息来检索记录?

标签: django forms django-templates


【解决方案1】:

使用{{ 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 的最佳做法是什么。
  • 刚刚添加了更多信息。通过查看 ModelForm 源代码,特别是元类部分,我能够大致了解。
【解决方案2】:

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

不过,没有必要将 id 放在隐藏字段中。如果您转到一个 URL 来编辑一个对象,并且该 URL 显示一个表单,它应该提交回相同的 URL - 在这种情况下,您仍然在 URL 中拥有 id。

【讨论】:

  • 我不认为是这样。当我在namephone 字段上设置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 我没有在idpk 上收到此错误字段。
  • 在我的网络应用程序中,我没有在 URL 中使用主键。 url 是 //,而不是使用用户的东西的 id,所以从 URL 中获取它是不可能的。
【解决方案3】:

迟到的答案,但可能对其他人有所帮助:

{{ form.instance.id }}

这对我有用

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-01
    • 1970-01-01
    • 2019-11-22
    • 2018-05-31
    • 1970-01-01
    • 2015-07-30
    • 2017-08-04
    • 1970-01-01
    相关资源
    最近更新 更多