我有一些表单字段,我想根据是否满足某个条件来包含/排除。我知道如何包含和排除表单元素,但是当我希望它根据函数的结果显示元素时,我很难做到。
这是我的表格:
class ProfileForm(ModelForm):
# this_team = get Team instance from team.id passed in
# how?
def draft_unlocked(self):
teams = Team.objects.order_by('total_points')
count = 0
for team in teams:
if team.pk == this_team.pk:
break
count += 1
now = datetime.datetime.now().weekday()
if now >= count:
# show driver_one, driver_two, driver_three
else:
# do not show driver_one, driver_two, driver_three
class Meta:
model = Team
我想要完成的是,根据总积分的排名,团队不应该在指定的日期之前改变他们的驾驶员。在比赛中,排名最后一支球队可以在周一添加/减少一名车手,倒数第二支球队可以在周二加/减,依此类推...
所以第一个问题 - 如何从传入的id中获取表单内部的Team实例。而且,如何根据draft_unlocked()的结果包含/排除。
或许有更好的方法可以做到这一切?
非常感谢大家。
答案 0 :(得分:6)
这实际上非常简单(条件字段设置) - 这是一个简单的例子:
from django.forms import Modelform
from django.forms.widgets import HiddenInput
class SomeForm(ModelForm):
def __init__(self, *args, **kwargs):
# call constructor to set up the fields. If you don't do this
# first you can't modify fields.
super(SomeForm, self).__init__(*args, **kwargs)
try:
# make somefunc return something True
# if you can change the driver.
# might make sense in a model?
canchangedriver = self.instance.somefunc()
except AttributeError:
# unbound form, what do you want to do here?
canchangedriver = True # for example?
# if the driver can't be changed, use a input=hidden
# input field.
if not canchangedriver:
self.fields["Drivers"].widget = HiddenInput()
class Meta:
model = SomeModel
所以,关键点是:
self.instance
表示绑定对象。我相信它是作为命名参数传递的,因此在kwargs
中,父构造函数用来创建self.instance
。<input type="hidden" .../>
。有一个限制;如果修改提交的POST / GET数据,我可以篡改输入以更改值。如果您不希望发生这种情况,需要考虑的事项是覆盖表单的验证(clean())方法。请记住,Django中的所有内容都只是对象,这意味着您可以实际修改类对象并随机添加数据(虽然它不会被保留)。所以在__init__
你可以:
self.instance.olddrivers = instance.drivers.all()
然后用你所说的形式的干净方法:
def clean(self):
# validate parent. Do this first because this method
# will transform field values into model field values.
# i.e. instance will reflect the form changes.
super(SomeForm, self).clean()
# can we modify drivers?
canchangedriver = self.instance.somefunc()
# either we can change the driver, or if not, we require
# that the two lists are, when sorted, equal (to allow for
# potential non equal ordering of identical elements).
# Wrapped code here for niceness
if (canchangedriver or
(sorted(self.instance.drivers.all()) ==
sorted(self.instance.olddrivers))):
return True
else:
raise ValidationError() # customise this to your liking.
答案 1 :(得分:2)
您可以通过添加自己的init来执行所需的操作,在实例化表单类时可以传入id:
class ProfileForm(ModelForm):
def __init__(self, team_id, *args, **kwargs):
super(ProfileForm, self).__init__(*args, **kwargs)
this_team = Team.objects.get(pk=team_id)
teams = Team.objects.order_by('total_points')
count = 0
for team in teams:
if team.pk == this_team.pk:
break
count += 1
now = datetime.datetime.now().weekday()
if now >= count:
# show driver_one, driver_two, driver_three
else:
# do not show driver_one, driver_two, driver_three
class Meta:
model = Team
#views.py
def my_view(request, team_id):
profile_form = ProfileForm(team_id, request.POST or None)
#more code here
希望能帮到你。