django:根据条件排除某些表单元素
我有一些表单字段,想根据某个条件来决定是否显示这些字段。我知道怎么添加和删除表单元素,但当我想根据一个函数的结果来显示这些元素时,就遇到困难了。
这是我的表单:
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()的结果来决定是否显示这些字段。
或者,也许还有更好的方法来实现这一切?
非常感谢大家。
2 个回答
2
你可以通过添加自己的初始化方法来实现你需要的功能,这样在创建表单类的时候就可以传入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
希望这对你有帮助。
8
其实这很简单(条件字段设置)——这里有个快速的例子:
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?
can_change_driver = self.instance.somefunc()
except AttributeError:
# unbound form, what do you want to do here?
can_change_driver = True # for example?
# if the driver can't be changed, use a input=hidden
# input field.
if not can_change_driver:
self.fields["Drivers"].widget = HiddenInput()
class Meta:
model = SomeModel
所以,以下是一些关键点:
self.instance
代表了绑定的对象,如果表单是绑定的。我认为它是作为一个命名参数传入的,因此在kwargs
中,父类构造函数用它来创建self.instance
。- 在调用父类构造函数之后,你可以修改字段的属性。
- widgets 是表单的显示方式。HiddenInput 基本上意味着
<input type="hidden" .../>
。
有一个限制;如果我修改提交的 POST/GET 数据,我可以篡改输入来改变值。如果你不想让这种情况发生,可以考虑重写表单的验证(clean())方法。记住,在 Django 中,一切都是对象,这意味着你实际上可以随机修改类对象并向它们添加数据(不过这些数据不会被保存)。所以在你的 __init__
方法中,你可以:
self.instance.olddrivers = instance.drivers.all()
然后在你所说的表单的 clean 方法中:
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?
can_change_driver = 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 (can_change_driver or
(sorted(self.instance.drivers.all()) ==
sorted(self.instance.olddrivers))):
return True
else:
raise ValidationError() # customise this to your liking.