Django 在 UpdateView 中设置 ModelForm ModelChoiceField 初始值 class
Django set ModelForm ModelChoiceField initial value in UpdateView class
在发布自己的问题之前,我检查了很多相关问题,但我仍然无法弄清楚。使用 Django 2.2.x.
我希望 html 表单的 owner
字段最初只显示 1 个用户名,并且此用户名必须是当前 event
实例所有者。
作为 ModelChoiceField
,html 表单上的字段呈现为下拉列表。此下拉列表暂时包含所有应用程序用户,因为 ModelChoiceField
有 queryset=User.objects.all()
我试图覆盖 UpdateView
的 get_initial()
方法,但是,这对 ModelChoiceField
没有影响。不过,我可以设置所有 forms.CharField() 初始值。
我也尝试重写 class EventForm(forms.ModelForm)
的 __init__
方法,但运气不佳。
forms.py
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ["customer", "owner", ...]
# the helper block comes from crispy_forms extension.
# It rules the form layout, allowing to specify css classes, fields order
# and even adding custom buttons
helper = FormHelper()
helper.layout = Layout(
Field('customer'),
Field('owner'),
...
Submit('submit', 'Update')
)
customer = forms.CharField(disabled=True)
owner = forms.ModelChoiceField(queryset=User.objects.all())
...
views.py
class EventUpdateView(LoginRequiredMixin, UpdateView):
""" this view renders the update form that allows service desk operators to update event status,
ownership and event notes
"""
model = Event
form_class = EventForm
template_name = "metamonitor/event_update_form.html"
def get_initial(self):
""" returns the initial data to populate form field on this view.
We override this method to customize the `owner` initial value to the
default event owner.
"""
initial = super().get_initial()
# the event instance being updated
event = self.get_object()
# this expression returns a queryset containing only 1 item,
# like <QuerySet [<User: operator2>]>
initial['owner'] = User.objects.filter(pk=event.owner.pk)
return initial
# without this, after a successfull event update we would get an error
# because django needs a valid url to redirect to.
def get_success_url(self):
# app_name:url_name, as defined in the corresponding path() `name` argument in urls.py
return reverse("metamonitor:event_update", kwargs={"pk": self.object.pk})
如何正确设置初始值?
这是解决您问题的方法。它需要两个步骤:
覆盖视图的 get_form_kwargs 方法,因此它检索 'owner' 对象并将其发送到表单,存储在 kwargs 参数中
覆盖表单的init,然后将所有者对象(取自kwargs)分配给您要更改的字段的.queryset :
在您的视图中覆盖 get_form_kwargs:
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
event = self.object # no need to call get_object() as you did in your post
owner = User.objects.filter(pk=event.owner.pk)
kwargs.update({'owner': owner})
return kwargs
重写 forms.py 中表单 class 的 init:
def __init__(self, *args, **kwargs):
owner = kwargs.pop('owner') # get the owner object from kwargs
super().__init__(*args, **kwargs)
# assign owner to the field; note the use of .queryset on the field
self.fields['owner'].queryset = owner
另一种与上面不同的方法是简单地修改视图的get_form方法:
def get_form(self, form_class=None):
form = super().get_form(form_class)
event = self.object
owner = User.objects.filter(pk=event.owner.pk)
form.fields['owner'].queryset = owner
return form
这个解决方案比第一个解决方案实施起来要快得多,这是真的;我只在最后提到它,因为根据我的经验,当期望的目标是更改表单的显示方式时,人们似乎更喜欢修改表单 class 本身。使用最适合您需要的那个。
在发布自己的问题之前,我检查了很多相关问题,但我仍然无法弄清楚。使用 Django 2.2.x.
我希望 html 表单的 owner
字段最初只显示 1 个用户名,并且此用户名必须是当前 event
实例所有者。
作为 ModelChoiceField
,html 表单上的字段呈现为下拉列表。此下拉列表暂时包含所有应用程序用户,因为 ModelChoiceField
有 queryset=User.objects.all()
我试图覆盖 UpdateView
的 get_initial()
方法,但是,这对 ModelChoiceField
没有影响。不过,我可以设置所有 forms.CharField() 初始值。
我也尝试重写 class EventForm(forms.ModelForm)
的 __init__
方法,但运气不佳。
forms.py
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ["customer", "owner", ...]
# the helper block comes from crispy_forms extension.
# It rules the form layout, allowing to specify css classes, fields order
# and even adding custom buttons
helper = FormHelper()
helper.layout = Layout(
Field('customer'),
Field('owner'),
...
Submit('submit', 'Update')
)
customer = forms.CharField(disabled=True)
owner = forms.ModelChoiceField(queryset=User.objects.all())
...
views.py
class EventUpdateView(LoginRequiredMixin, UpdateView):
""" this view renders the update form that allows service desk operators to update event status,
ownership and event notes
"""
model = Event
form_class = EventForm
template_name = "metamonitor/event_update_form.html"
def get_initial(self):
""" returns the initial data to populate form field on this view.
We override this method to customize the `owner` initial value to the
default event owner.
"""
initial = super().get_initial()
# the event instance being updated
event = self.get_object()
# this expression returns a queryset containing only 1 item,
# like <QuerySet [<User: operator2>]>
initial['owner'] = User.objects.filter(pk=event.owner.pk)
return initial
# without this, after a successfull event update we would get an error
# because django needs a valid url to redirect to.
def get_success_url(self):
# app_name:url_name, as defined in the corresponding path() `name` argument in urls.py
return reverse("metamonitor:event_update", kwargs={"pk": self.object.pk})
如何正确设置初始值?
这是解决您问题的方法。它需要两个步骤:
覆盖视图的 get_form_kwargs 方法,因此它检索 'owner' 对象并将其发送到表单,存储在 kwargs 参数中
覆盖表单的init,然后将所有者对象(取自kwargs)分配给您要更改的字段的.queryset :
在您的视图中覆盖 get_form_kwargs:
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
event = self.object # no need to call get_object() as you did in your post
owner = User.objects.filter(pk=event.owner.pk)
kwargs.update({'owner': owner})
return kwargs
重写 forms.py 中表单 class 的 init:
def __init__(self, *args, **kwargs):
owner = kwargs.pop('owner') # get the owner object from kwargs
super().__init__(*args, **kwargs)
# assign owner to the field; note the use of .queryset on the field
self.fields['owner'].queryset = owner
另一种与上面不同的方法是简单地修改视图的get_form方法:
def get_form(self, form_class=None):
form = super().get_form(form_class)
event = self.object
owner = User.objects.filter(pk=event.owner.pk)
form.fields['owner'].queryset = owner
return form
这个解决方案比第一个解决方案实施起来要快得多,这是真的;我只在最后提到它,因为根据我的经验,当期望的目标是更改表单的显示方式时,人们似乎更喜欢修改表单 class 本身。使用最适合您需要的那个。