为何带auto_now_add的DateTimeField无法显示在表单?更新时如何显示?
嘿,我来帮你搞定这个问题!你遇到的created_at字段不显示在表单里的原因很明确——Django的默认行为在起作用:
你的created_at字段设置了auto_now_add=True,Django会自动把这个字段的editable属性默认设为False。而当你用表单关联模型时(哦对了,你的表单继承的是forms.Form,其实应该用forms.ModelForm才能让Meta里的模型配置生效),哪怕设置了fields='__all__',Django也会自动排除所有editable=False的字段,所以它不会出现在渲染的表单里。
下面给你几个实用的解决方案,你可以根据自己的需求选择:
方案1:直接修改模型字段(适合全局需要编辑的场景)
如果你希望这个字段在所有关联的表单里都能编辑,只需要在模型字段里显式加上editable=True:
class MyModel(models.Model): code = models.CharField(_('Code'), max_length=56, null=False, blank=False, db_column='code') name = models.CharField(_('Name'), max_length=128, null=False, db_index=True, db_column='name', blank=False) created_at = models.DateTimeField( _('Created At'), null=False, db_column='created_at', blank=False, auto_now_add=True, editable=True # 加上这一行,强制让字段可编辑 )
放心,auto_now_add=True只会在对象第一次创建时自动填充值,后续更新不会自动覆盖,你可以手动修改它。
方案2:在表单里显式定义字段(推荐,不改动模型)
如果不想修改模型的默认行为,只在这个特定表单里显示created_at,可以在MyForm里显式声明这个字段,同时注意表单要继承ModelForm:
class MyForm(forms.ModelForm): # 这里改成ModelForm,不然Meta里的配置无效 # 显式定义created_at字段,覆盖默认的editable=False created_at = forms.DateTimeField( label=_('Created At'), required=True, # 根据你的需求设置是否必填 widget=forms.DateTimeInput(attrs={'type': 'datetime-local'}) # 可选,用更友好的时间控件 ) class Meta: model = MyModel fields = ['code', 'name', 'created_at'] # 显式列出所有需要的字段,包含created_at
这样即使模型里的editable是False,表单里的这个字段依然会显示并允许编辑。
方案3:仅在更新时显示字段(精准控制场景)
如果只有在更新对象时才需要显示created_at,新建时隐藏,那可以在视图里判断场景,动态处理:
class MyView(View): def get(self, request, pk=None): # 更新时传入对象的pk参数 if pk: # 更新场景:获取对象实例,使用包含created_at的表单 instance = MyModel.objects.get(pk=pk) form = MyForm(instance=instance) else: # 新建场景:动态移除created_at字段 form = MyForm() del form.fields['created_at'] return render(request, 'test_manager/testrule_form.html', {'form': form})
配合方案2的表单定义,就能实现新建不显示、更新显示的效果。
最后提个关键细节:你原来的表单继承的是forms.Form,这会导致Meta里的model和fields配置完全不生效,一定要改成forms.ModelForm才能让表单和模型关联起来哦!
内容的提问来源于stack exchange,提问作者Diksha

